diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..dca857a3de --- /dev/null +++ b/.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/.github/workflows/autoroll.yml b/.github/workflows/autoroll.yml index 6a7a814df2..8e8c3a4203 100644 --- a/.github/workflows/autoroll.yml +++ b/.github/workflows/autoroll.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 # Checkout the depot tools they are needed by roll_deps.sh - name: Checkout depot tools @@ -47,6 +47,10 @@ jobs: if: steps.update_dependencies.outputs.changed == 'true' run: | git push --force --set-upstream origin roll_deps - gh pr create --label 'kokoro:run' --base main -f -r s-perron + # 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/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 5c353718e7..347f884ff5 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -18,13 +18,13 @@ jobs: runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: '0' - name: Download dependencies run: python3 utils/git-sync-deps - name: Mount Bazel cache - uses: actions/cache@v3 + uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 with: path: ~/.bazel/cache key: bazel-cache-${{ runner.os }} diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml new file mode 100644 index 0000000000..68bf59b6ef --- /dev/null +++ b/.github/workflows/ios.yml @@ -0,0 +1,30 @@ +name: iOS +permissions: + contents: read + +on: [push, pull_request, workflow_dispatch] + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ macos-12, macos-13 ] + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: lukka/get-cmake@4865386b66955d11be0abf8c112d0230023e742a # v3.27.9 + - 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/.github/workflows/release.yml b/.github/workflows/release.yml index ada943169e..50e32a9047 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ jobs: prepare-release-job: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Prepare CHANGELOG for version run: | python utils/generate_changelog.py CHANGES "${{ github.ref_name }}" VERSION_CHANGELOG diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 0000000000..455e6f14c8 --- /dev/null +++ b/.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@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 + 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@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + 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@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8 + with: + sarif_file: results.sarif diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 62c9af3842..552e56a9db 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: '0' - name: Build web diff --git a/Android.mk b/Android.mk index dcb8d63191..afa0403933 100644 --- a/Android.mk +++ b/Android.mk @@ -136,6 +136,7 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/instrument_pass.cpp \ source/opt/interface_var_sroa.cpp \ source/opt/interp_fixup_pass.cpp \ + source/opt/invocation_interlock_placement_pass.cpp \ source/opt/ir_context.cpp \ source/opt/ir_loader.cpp \ source/opt/licm_pass.cpp \ @@ -182,6 +183,7 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/strip_debug_info_pass.cpp \ source/opt/strip_nonsemantic_info_pass.cpp \ source/opt/struct_cfg_analysis.cpp \ + source/opt/switch_descriptorset_pass.cpp \ source/opt/trim_capabilities_pass.cpp \ source/opt/type_manager.cpp \ source/opt/types.cpp \ diff --git a/BUILD.bazel b/BUILD.bazel index a2342770e7..b83fd5aead 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -456,7 +456,6 @@ cc_library( ], exclude = [ "test/cpp_interface_test.cpp", - "test/log_test.cpp", "test/pch_test.cpp", ], )] @@ -487,19 +486,6 @@ cc_test( ], ) -cc_test( - name = "base_log_test", - size = "small", - srcs = ["test/log_test.cpp"], - copts = TEST_COPTS, - linkstatic = 1, - deps = [ - ":spirv_tools_opt_internal", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", - ], -) - cc_library( name = "link_test_lib", testonly = 1, diff --git a/BUILD.gn b/BUILD.gn index bc48e43b2a..9ff36d83db 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -693,6 +693,8 @@ static_library("spvtools_opt") { "source/opt/interface_var_sroa.h", "source/opt/interp_fixup_pass.cpp", "source/opt/interp_fixup_pass.h", + "source/opt/invocation_interlock_placement_pass.cpp", + "source/opt/invocation_interlock_placement_pass.h", "source/opt/ir_builder.h", "source/opt/ir_context.cpp", "source/opt/ir_context.h", @@ -789,6 +791,8 @@ static_library("spvtools_opt") { "source/opt/strip_nonsemantic_info_pass.h", "source/opt/struct_cfg_analysis.cpp", "source/opt/struct_cfg_analysis.h", + "source/opt/switch_descriptorset_pass.cpp", + "source/opt/switch_descriptorset_pass.h", "source/opt/tree_iterator.h", "source/opt/trim_capabilities_pass.cpp", "source/opt/trim_capabilities_pass.h", diff --git a/CHANGES b/CHANGES index 97caaee192..48aa87664a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,49 @@ Revision history for SPIRV-Tools +v2023.6 2023-12-18 + - General + - update_build_version.py produce deterministic header. (#5426) + - Support missing git in update_build_version.py (#5473) + - Optimizer + - Add ComputeDerivativeGroup*NV capabilities to trim capabilities pass. (#5430) + - Do not crash when tryingto fold unsupported spec constant (#5496) + - instrument: Fix handling of gl_InvocationID (#5493) + - Fix nullptr argument in MarkInsertChain (#5465) + - opt: support 64-bit OpAccessChain index in FixStorageClass (#5446) + - opt: add StorageImageReadWithoutFormat to cap trim (#5475) + - opt: add PhysicalStorageBufferAddresses to trim (#5476) + - Fix array size calculation (#5463 + - Validator + - spirv-val: Loosen restriction on base type of DebugTypePointer and DebugTypeQualifier (#5479) + - spirv-val: Add WorkgroupMemoryExplicitLayoutKHR check for Block (#5461) + +v2023.5 2023-10-15 + - General + - Support 2 Intel extensions (#5357) + - SPV_QCOM_image_processing support (#5223) + - Optimizer + - opt: fix StorageInputOutput16 trimming. (#5359) + - opt: add StoragePushConstant16 to trim pass (#5366) + - opt: enable StorageUniform16 (#5371) + - opt: add bitmask support for capability trimming (#5372) + - opt: Add SwitchDescriptorSetPass (#5375) + - opt: add FragmentShader*InterlockEXT to capability trim pass (#5390) + - opt: add Int64 capability to trim pass (#5398) + - opt: add Float64 capability to trim pass (#5428) + - opt: add raytracing/rayquery to trim pass (#5397) + - opt: add ImageMSArray capability to trim pass. (#5395) + - Add SPV_KHR_physical_storage_buffer to allowlists (#5402) + - Add SPV_EXT_fragment_shader_interlock to allow lists (#5393) + - Make sure that fragment shader interlock instructions are not removed by DCE (#5400) + - instrument: Use Import linkage for instrumentation functions (#5355) + - Add a new legalization pass to dedupe invocation interlock instructions (#5409) + - instrument: Ensure linking works even of nothing is changed (#5419) + - Validator + - Move token version/cap/ext checks from parsing to validation (#5370) + - val: re-add ImageMSArray validation (#5394) + - Linker + - linker: Add --use-highest-version option + v2023.4 2023-07-17 - General - Set cmake_policy CMP0128 (#5341) diff --git a/CMakeLists.txt b/CMakeLists.txt index 375229ba2a..07be2dfc91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -304,15 +304,23 @@ if(ENABLE_SPIRV_TOOLS_INSTALL) endmacro() endif() -# Defaults to OFF if the user didn't set it. -option(SPIRV_SKIP_EXECUTABLES - "Skip building the executable and tests along with the library" - ${SPIRV_SKIP_EXECUTABLES}) -option(SPIRV_SKIP_TESTS - "Skip building tests along with the library" ${SPIRV_SKIP_TESTS}) -if ("${SPIRV_SKIP_EXECUTABLES}") +# Currently iOS and Android are very similar. +# They both have their own packaging (APP/APK). +# Which makes regular executables/testing problematic. +# +# Currently the only deliverables for these platforms are +# libraries (either STATIC or SHARED). +# +# Furthermore testing is equally problematic. +if (IOS OR ANDROID) + set(SPIRV_SKIP_EXECUTABLES ON) +endif() + +option(SPIRV_SKIP_EXECUTABLES "Skip building the executable and tests along with the library") +if (SPIRV_SKIP_EXECUTABLES) set(SPIRV_SKIP_TESTS ON) endif() +option(SPIRV_SKIP_TESTS "Skip building tests along with the library") # Defaults to ON. The checks can be time consuming. # Turn off if they take too long. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 893998e1b5..11fb4e2c7e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,7 @@ ## For users: Reporting bugs and requesting features We organize known future work in GitHub projects. See -[Tracking SPIRV-Tools work with GitHub projects](https://github.com/KhronosGroup/SPIRV-Tools/blob/master/docs/projects.md) +[Tracking SPIRV-Tools work with GitHub projects](https://github.com/KhronosGroup/SPIRV-Tools/blob/main/docs/projects.md) for more. To report a new bug or request a new feature, please file a GitHub issue. Please @@ -46,7 +46,7 @@ sign the CLA until after you've submitted your code for review and a member has approved it, but you must do it before we can put your code into our codebase. See -[README.md](https://github.com/KhronosGroup/SPIRV-Tools/blob/master/README.md) +[README.md](https://github.com/KhronosGroup/SPIRV-Tools/blob/main/README.md) for instruction on how to get, build, and test the source. Once you have made your changes: @@ -59,7 +59,7 @@ your changes: * If your patch completely fixes bug 1234, the commit message should say `Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/1234` When you do this, the issue will be closed automatically when the commit goes into - master. Also, this helps us update the [CHANGES](CHANGES) file. + main. Also, this helps us update the [CHANGES](CHANGES) file. * Watch the continuous builds to make sure they pass. * Request a code review. @@ -107,7 +107,7 @@ should pay particular attention to: ## For maintainers: Merging a PR -We intend to maintain a linear history on the GitHub master branch, and the +We intend to maintain a linear history on the GitHub main branch, and the build and its tests should pass at each commit in that history. A linear always-working history is easier to understand and to bisect in case we want to find which commit introduced a bug. The diff --git a/DEPS b/DEPS index 1d9f0ba1bd..a27f4fca18 100644 --- a/DEPS +++ b/DEPS @@ -7,13 +7,13 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '6f6ab4212aa02cfe02e480711246da4fc17b0761', + 'googletest_revision': 'b10fad38c4026a29ea6561ab15fc4818170d1c10', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '960c861764ff54c9a12ff683ba55ccaad1a8f73b', - 'spirv_headers_revision': '124a9665e464ef98b8b718d572d5f329311061eb', + 're2_revision': '7e0c1a9e2417e70e5f0efc323267ac71d1fa0685', + 'spirv_headers_revision': '1c6bb2743599e6eb6f37b2969acc0aef812e32e3', } deps = { diff --git a/README.md b/README.md index 8c76895785..042b83da13 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # SPIR-V Tools +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/KhronosGroup/SPIRV-Tools/badge)](https://securityscorecards.dev/viewer/?uri=github.com/KhronosGroup/SPIRV-Tools) NEWS 2023-01-11: Development occurs on the `main` branch. diff --git a/docs/downloads.md b/docs/downloads.md index 168937a705..f56b6fe992 100644 --- a/docs/downloads.md +++ b/docs/downloads.md @@ -2,7 +2,7 @@ ## Latest builds -Download the latest builds of the [master](https://github.com/KhronosGroup/SPIRV-Tools/tree/master) branch. +Download the latest builds of the [main](https://github.com/KhronosGroup/SPIRV-Tools/tree/main) branch. ### Release build | Windows | Linux | MacOS | diff --git a/docs/projects.md b/docs/projects.md index 8f7f0bcd94..cc88cb3ff3 100644 --- a/docs/projects.md +++ b/docs/projects.md @@ -34,7 +34,7 @@ through the project workflow: ones. * They determine if the work for a card has been completed. * Normally they are the person (or persons) who can approve and merge a pull - request into the `master` branch. + request into the `main` branch. Our projects organize cards into the following columns: * `Ideas`: Work which could be done, captured either as Cards or Notes. @@ -51,7 +51,7 @@ Our projects organize cards into the following columns: claimed by someone. * `Done`: Issues which have been resolved, by completing their work. * The changes have been applied to the repository, typically by being pushed - into the `master` branch. + into the `main` branch. * Other kinds of work could update repository settings, for example. * `Rejected ideas`: Work which has been considered, but which we don't want implemented. diff --git a/include/spirv-tools/instrument.hpp b/include/spirv-tools/instrument.hpp index 34e169a9ef..0a6e6306ec 100644 --- a/include/spirv-tools/instrument.hpp +++ b/include/spirv-tools/instrument.hpp @@ -73,206 +73,14 @@ static const int kInstCommonOutShaderId = 1; // which generated the validation error. static const int kInstCommonOutInstructionIdx = 2; -// This is the stage which generated the validation error. This word is used -// to determine the contents of the next two words in the record. -// 0:Vert, 1:TessCtrl, 2:TessEval, 3:Geom, 4:Frag, 5:Compute -static const int kInstCommonOutStageIdx = 3; -static const int kInstCommonOutCnt = 4; - -// Stage-specific Stream Record Offsets -// -// Each stage will contain different values in the next set of words of the -// record used to identify which instantiation of the shader generated the -// validation error. -// -// Vertex Shader Output Record Offsets -static const int kInstVertOutVertexIndex = kInstCommonOutCnt; -static const int kInstVertOutInstanceIndex = kInstCommonOutCnt + 1; -static const int kInstVertOutUnused = kInstCommonOutCnt + 2; - -// Frag Shader Output Record Offsets -static const int kInstFragOutFragCoordX = kInstCommonOutCnt; -static const int kInstFragOutFragCoordY = kInstCommonOutCnt + 1; -static const int kInstFragOutUnused = kInstCommonOutCnt + 2; - -// Compute Shader Output Record Offsets -static const int kInstCompOutGlobalInvocationIdX = kInstCommonOutCnt; -static const int kInstCompOutGlobalInvocationIdY = kInstCommonOutCnt + 1; -static const int kInstCompOutGlobalInvocationIdZ = kInstCommonOutCnt + 2; - -// Tessellation Control Shader Output Record Offsets -static const int kInstTessCtlOutInvocationId = kInstCommonOutCnt; -static const int kInstTessCtlOutPrimitiveId = kInstCommonOutCnt + 1; -static const int kInstTessCtlOutUnused = kInstCommonOutCnt + 2; - -// Tessellation Eval Shader Output Record Offsets -static const int kInstTessEvalOutPrimitiveId = kInstCommonOutCnt; -static const int kInstTessEvalOutTessCoordU = kInstCommonOutCnt + 1; -static const int kInstTessEvalOutTessCoordV = kInstCommonOutCnt + 2; - -// Geometry Shader Output Record Offsets -static const int kInstGeomOutPrimitiveId = kInstCommonOutCnt; -static const int kInstGeomOutInvocationId = kInstCommonOutCnt + 1; -static const int kInstGeomOutUnused = kInstCommonOutCnt + 2; - -// Ray Tracing Shader Output Record Offsets -static const int kInstRayTracingOutLaunchIdX = kInstCommonOutCnt; -static const int kInstRayTracingOutLaunchIdY = kInstCommonOutCnt + 1; -static const int kInstRayTracingOutLaunchIdZ = kInstCommonOutCnt + 2; - -// Mesh Shader Output Record Offsets -static const int kInstMeshOutGlobalInvocationIdX = kInstCommonOutCnt; -static const int kInstMeshOutGlobalInvocationIdY = kInstCommonOutCnt + 1; -static const int kInstMeshOutGlobalInvocationIdZ = kInstCommonOutCnt + 2; - -// Task Shader Output Record Offsets -static const int kInstTaskOutGlobalInvocationIdX = kInstCommonOutCnt; -static const int kInstTaskOutGlobalInvocationIdY = kInstCommonOutCnt + 1; -static const int kInstTaskOutGlobalInvocationIdZ = kInstCommonOutCnt + 2; - -// Size of Common and Stage-specific Members -static const int kInstStageOutCnt = kInstCommonOutCnt + 3; - -// Validation Error Code Offset -// -// This identifies the validation error. It also helps to identify -// how many words follow in the record and their meaning. -static const int kInstValidationOutError = kInstStageOutCnt; - -// Validation-specific Output Record Offsets -// -// Each different validation will generate a potentially different -// number of words at the end of the record giving more specifics -// about the validation error. -// -// A bindless bounds error will output the index and the bound. -static const int kInstBindlessBoundsOutDescSet = kInstStageOutCnt + 1; -static const int kInstBindlessBoundsOutDescBinding = kInstStageOutCnt + 2; -static const int kInstBindlessBoundsOutDescIndex = kInstStageOutCnt + 3; -static const int kInstBindlessBoundsOutDescBound = kInstStageOutCnt + 4; -static const int kInstBindlessBoundsOutUnused = kInstStageOutCnt + 5; -static const int kInstBindlessBoundsOutCnt = kInstStageOutCnt + 6; - -// A descriptor uninitialized error will output the index. -static const int kInstBindlessUninitOutDescSet = kInstStageOutCnt + 1; -static const int kInstBindlessUninitOutBinding = kInstStageOutCnt + 2; -static const int kInstBindlessUninitOutDescIndex = kInstStageOutCnt + 3; -static const int kInstBindlessUninitOutUnused = kInstStageOutCnt + 4; -static const int kInstBindlessUninitOutUnused2 = kInstStageOutCnt + 5; -static const int kInstBindlessUninitOutCnt = kInstStageOutCnt + 6; - -// A buffer out-of-bounds error will output the descriptor -// index, the buffer offset and the buffer size -static const int kInstBindlessBuffOOBOutDescSet = kInstStageOutCnt + 1; -static const int kInstBindlessBuffOOBOutDescBinding = kInstStageOutCnt + 2; -static const int kInstBindlessBuffOOBOutDescIndex = kInstStageOutCnt + 3; -static const int kInstBindlessBuffOOBOutBuffOff = kInstStageOutCnt + 4; -static const int kInstBindlessBuffOOBOutBuffSize = kInstStageOutCnt + 5; -static const int kInstBindlessBuffOOBOutCnt = kInstStageOutCnt + 6; - -// A buffer address unalloc error will output the 64-bit pointer in -// two 32-bit pieces, lower bits first. -static const int kInstBuffAddrUnallocOutDescPtrLo = kInstStageOutCnt + 1; -static const int kInstBuffAddrUnallocOutDescPtrHi = kInstStageOutCnt + 2; -static const int kInstBuffAddrUnallocOutCnt = kInstStageOutCnt + 3; - -// Maximum Output Record Member Count -static const int kInstMaxOutCnt = kInstStageOutCnt + 6; - -// Validation Error Codes -// -// These are the possible validation error codes. -static const int kInstErrorBindlessBounds = 1; -static const int kInstErrorBindlessUninit = 2; -static const int kInstErrorBuffAddrUnallocRef = 3; -static const int kInstErrorOOB = 4; -static const int kInstErrorMax = kInstErrorOOB; - -// Direct Input Buffer Offsets -// -// The following values provide member offsets into the input buffers -// consumed by InstrumentPass::GenDebugDirectRead(). This method is utilized -// by InstBindlessCheckPass. -// -// The only object in an input buffer is a runtime array of unsigned -// integers. Each validation will have its own formatting of this array. -static const int kDebugInputDataOffset = 0; - // Debug Buffer Bindings // // These are the bindings for the different buffers which are // read or written by the instrumentation passes. // -// This is the output buffer written by InstBindlessCheckPass, -// InstBuffAddrCheckPass, and possibly other future validations. -static const int kDebugOutputBindingStream = 0; - -// The binding for the input buffer read by InstBindlessCheckPass. -static const int kDebugInputBindingBindless = 1; - -// The binding for the input buffer read by InstBuffAddrCheckPass. -static const int kDebugInputBindingBuffAddr = 2; - // This is the output buffer written by InstDebugPrintfPass. static const int kDebugOutputPrintfStream = 3; -// clang-format off -// Bindless Validation Input Buffer Format -// -// An input buffer for bindless validation has this structure: -// GLSL: -// layout(buffer_reference, std430, buffer_reference_align = 8) buffer DescriptorSetData { -// uint num_bindings; -// uint data[]; -// }; -// -// layout(set = 7, binding = 1, std430) buffer inst_bindless_InputBuffer -// { -// DescriptorSetData desc_sets[32]; -// } inst_bindless_input_buffer; -// -// -// To look up the length of a binding: -// uint length = inst_bindless_input_buffer[set].data[binding]; -// Scalar bindings have a length of 1. -// -// To look up the initialization state of a descriptor in a binding: -// uint num_bindings = inst_bindless_input_buffer[set].num_bindings; -// uint binding_state_start = inst_bindless_input_buffer[set].data[num_bindings + binding]; -// uint init_state = inst_bindless_input_buffer[set].data[binding_state_start + index]; -// -// For scalar bindings, use 0 for the index. -// clang-format on -// -// The size of the inst_bindless_input_buffer array, regardless of how many -// descriptor sets the device supports. -static const int kDebugInputBindlessMaxDescSets = 32; - -// Buffer Device Address Input Buffer Format -// -// An input buffer for buffer device address validation consists of a single -// array of unsigned 64-bit integers we will call Data[]. This array is -// formatted as follows: -// -// At offset kDebugInputBuffAddrPtrOffset is a list of sorted valid buffer -// addresses. The list is terminated with the address 0xffffffffffffffff. -// If 0x0 is not a valid buffer address, this address is inserted at the -// start of the list. -// -static const int kDebugInputBuffAddrPtrOffset = 1; -// -// At offset kDebugInputBuffAddrLengthOffset in Data[] is a single uint64 which -// gives an offset to the start of the buffer length data. More -// specifically, for a buffer whose pointer is located at input buffer offset -// i, the length is located at: -// -// Data[ i - kDebugInputBuffAddrPtrOffset -// + Data[ kDebugInputBuffAddrLengthOffset ] ] -// -// The length associated with the 0xffffffffffffffff address is zero. If -// not a valid buffer, the length associated with the 0x0 address is zero. -static const int kDebugInputBuffAddrLengthOffset = 0; - } // namespace spvtools #endif // INCLUDE_SPIRV_TOOLS_INSTRUMENT_HPP_ diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index 0208097a80..b70f084a8e 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -293,6 +293,15 @@ typedef enum spv_operand_type_t { SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_LAYOUT, SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_USE, + // Enum type from SPV_INTEL_global_variable_fpga_decorations + SPV_OPERAND_TYPE_INITIALIZATION_MODE_QUALIFIER, + // Enum type from SPV_INTEL_global_variable_host_access + SPV_OPERAND_TYPE_HOST_ACCESS_QUALIFIER, + // Enum type from SPV_INTEL_cache_controls + SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL, + // Enum type from SPV_INTEL_cache_controls + SPV_OPERAND_TYPE_STORE_CACHE_CONTROL, + // 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/include/spirv-tools/linker.hpp b/include/spirv-tools/linker.hpp index d2f3e72ca2..5b60cb9f95 100644 --- a/include/spirv-tools/linker.hpp +++ b/include/spirv-tools/linker.hpp @@ -26,11 +26,6 @@ namespace spvtools { class LinkerOptions { public: - LinkerOptions() - : create_library_(false), - verify_ids_(false), - allow_partial_linkage_(false) {} - // Returns whether a library or an executable should be produced by the // linking phase. // @@ -63,10 +58,16 @@ class LinkerOptions { allow_partial_linkage_ = allow_partial_linkage; } + bool GetUseHighestVersion() const { return use_highest_version_; } + void SetUseHighestVersion(bool use_highest_vers) { + use_highest_version_ = use_highest_vers; + } + private: - bool create_library_; - bool verify_ids_; - bool allow_partial_linkage_; + bool create_library_{false}; + bool verify_ids_{false}; + bool allow_partial_linkage_{false}; + bool use_highest_version_{false}; }; // Links one or more SPIR-V modules into a new SPIR-V module. That is, combine diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp index 8579c8c4df..53ebc59f00 100644 --- a/include/spirv-tools/optimizer.hpp +++ b/include/spirv-tools/optimizer.hpp @@ -766,11 +766,9 @@ Optimizer::PassToken CreateCombineAccessChainsPass(); // potentially de-optimizing the instrument code, for example, inlining // the debug record output function throughout the module. // -// The instrumentation will read and write buffers in debug -// descriptor set |desc_set|. It will write |shader_id| in each output record +// The instrumentation will write |shader_id| in each output record // to identify the shader module which generated the record. -Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t desc_set, - uint32_t shader_id); +Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t shader_id); // Create a pass to instrument physical buffer address checking // This pass instruments all physical buffer address references to check that @@ -791,8 +789,7 @@ Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t desc_set, // The instrumentation will read and write buffers in debug // descriptor set |desc_set|. It will write |shader_id| in each output record // to identify the shader module which generated the record. -Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set, - uint32_t shader_id); +Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t shader_id); // Create a pass to instrument OpDebugPrintf instructions. // This pass replaces all OpDebugPrintf instructions with instructions to write @@ -992,6 +989,17 @@ Optimizer::PassToken CreateFixFuncCallArgumentsPass(); // the unknown capability interacts with one of the trimmed capabilities. Optimizer::PassToken CreateTrimCapabilitiesPass(); +// Creates a switch-descriptorset pass. +// This pass changes any DescriptorSet decorations with the value |ds_from| to +// use the new value |ds_to|. +Optimizer::PassToken CreateSwitchDescriptorSetPass(uint32_t ds_from, + uint32_t ds_to); + +// Creates an invocation interlock placement pass. +// This pass ensures that an entry point will have at most one +// OpBeginInterlockInvocationEXT and one OpEndInterlockInvocationEXT, in that +// order. +Optimizer::PassToken CreateInvocationInterlockPlacementPass(); } // namespace spvtools #endif // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_ diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 748fbf2652..f4ee3c84cf 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -418,12 +418,6 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") endif() endif() -if (ANDROID) - foreach(target ${SPIRV_TOOLS_TARGETS}) - target_link_libraries(${target} PRIVATE android log) - endforeach() -endif() - if(ENABLE_SPIRV_TOOLS_INSTALL) install(TARGETS ${SPIRV_TOOLS_TARGETS} EXPORT ${SPIRV_TOOLS}Targets) export(EXPORT ${SPIRV_TOOLS}Targets FILE ${SPIRV_TOOLS}Target.cmake) diff --git a/source/assembly_grammar.cpp b/source/assembly_grammar.cpp index 7596b31c81..0092d01a50 100644 --- a/source/assembly_grammar.cpp +++ b/source/assembly_grammar.cpp @@ -21,6 +21,7 @@ #include "source/ext_inst.h" #include "source/opcode.h" #include "source/operand.h" +#include "source/spirv_target_env.h" #include "source/table.h" namespace spvtools { @@ -176,15 +177,18 @@ bool AssemblyGrammar::isValid() const { CapabilitySet AssemblyGrammar::filterCapsAgainstTargetEnv( const spv::Capability* cap_array, uint32_t count) const { CapabilitySet cap_set; + const auto version = spvVersionForTargetEnv(target_env_); for (uint32_t i = 0; i < count; ++i) { - spv_operand_desc cap_desc = {}; + spv_operand_desc entry = {}; if (SPV_SUCCESS == lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, static_cast(cap_array[i]), - &cap_desc)) { - // spvOperandTableValueLookup() filters capabilities internally - // according to the current target environment by itself. So we - // should be safe to add this capability if the lookup succeeds. - cap_set.insert(cap_array[i]); + &entry)) { + // This token is visible in this environment if it's in an appropriate + // core version, or it is enabled by a capability or an extension. + if ((version >= entry->minVersion && version <= entry->lastVersion) || + entry->numExtensions > 0u || entry->numCapabilities > 0u) { + cap_set.insert(cap_array[i]); + } } } return cap_set; diff --git a/source/link/linker.cpp b/source/link/linker.cpp index e50391a1b3..58930e452e 100644 --- a/source/link/linker.cpp +++ b/source/link/linker.cpp @@ -91,7 +91,8 @@ spv_result_t ShiftIdsInModules(const MessageConsumer& consumer, // should be non-null. |max_id_bound| should be strictly greater than 0. spv_result_t GenerateHeader(const MessageConsumer& consumer, const std::vector& modules, - uint32_t max_id_bound, opt::ModuleHeader* header); + uint32_t max_id_bound, opt::ModuleHeader* header, + const LinkerOptions& options); // Merge all the modules from |in_modules| into a single module owned by // |linked_context|. @@ -202,7 +203,8 @@ spv_result_t ShiftIdsInModules(const MessageConsumer& consumer, spv_result_t GenerateHeader(const MessageConsumer& consumer, const std::vector& modules, - uint32_t max_id_bound, opt::ModuleHeader* header) { + uint32_t max_id_bound, opt::ModuleHeader* header, + const LinkerOptions& options) { spv_position_t position = {}; if (modules.empty()) @@ -212,10 +214,12 @@ spv_result_t GenerateHeader(const MessageConsumer& consumer, return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_DATA) << "|max_id_bound| of GenerateHeader should not be null."; - const uint32_t linked_version = modules.front()->version(); + uint32_t linked_version = modules.front()->version(); for (std::size_t i = 1; i < modules.size(); ++i) { const uint32_t module_version = modules[i]->version(); - if (module_version != linked_version) + if (options.GetUseHighestVersion()) { + linked_version = std::max(linked_version, module_version); + } else if (module_version != linked_version) { return DiagnosticStream({0, 0, 1}, consumer, "", SPV_ERROR_INTERNAL) << "Conflicting SPIR-V versions: " << SPV_SPIRV_VERSION_MAJOR_PART(linked_version) << "." @@ -224,6 +228,7 @@ spv_result_t GenerateHeader(const MessageConsumer& consumer, << SPV_SPIRV_VERSION_MAJOR_PART(module_version) << "." << SPV_SPIRV_VERSION_MINOR_PART(module_version) << " (input module " << (i + 1) << ")."; + } } header->magic_number = spv::MagicNumber; @@ -753,7 +758,7 @@ spv_result_t Link(const Context& context, const uint32_t* const* binaries, // Phase 2: Generate the header opt::ModuleHeader header; - res = GenerateHeader(consumer, modules, max_id_bound, &header); + res = GenerateHeader(consumer, modules, max_id_bound, &header, options); if (res != SPV_SUCCESS) return res; IRContext linked_context(c_context->target_env, consumer); linked_context.module()->SetHeader(header); diff --git a/source/operand.cpp b/source/operand.cpp index c2e5a99da7..6577f8f7db 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -26,7 +26,6 @@ #include "source/macro.h" #include "source/opcode.h" #include "source/spirv_constant.h" -#include "source/spirv_target_env.h" // For now, assume unified1 contains up to SPIR-V 1.3 and no later // SPIR-V version. @@ -48,7 +47,7 @@ spv_result_t spvOperandTableGet(spv_operand_table* pOperandTable, return SPV_SUCCESS; } -spv_result_t spvOperandTableNameLookup(spv_target_env env, +spv_result_t spvOperandTableNameLookup(spv_target_env, const spv_operand_table table, const spv_operand_type_t type, const char* name, @@ -57,31 +56,18 @@ spv_result_t spvOperandTableNameLookup(spv_target_env env, if (!table) return SPV_ERROR_INVALID_TABLE; if (!name || !pEntry) return SPV_ERROR_INVALID_POINTER; - const auto version = spvVersionForTargetEnv(env); for (uint64_t typeIndex = 0; typeIndex < table->count; ++typeIndex) { const auto& group = table->types[typeIndex]; if (type != group.type) continue; for (uint64_t index = 0; index < group.count; ++index) { const auto& entry = group.entries[index]; // We consider the current operand as available as long as - // 1. The target environment satisfies the minimal requirement of the - // operand; or - // 2. There is at least one extension enabling this operand; or - // 3. There is at least one capability enabling this operand. - // - // Note that the second rule assumes the extension enabling this operand - // is indeed requested in the SPIR-V code; checking that should be - // validator's work. + // it is in the grammar. It might not be *valid* to use, + // but that should be checked by the validator, not by parsing. if (nameLength == strlen(entry.name) && !strncmp(entry.name, name, nameLength)) { - if ((version >= entry.minVersion && version <= entry.lastVersion) || - entry.numExtensions > 0u || entry.numCapabilities > 0u) { - *pEntry = &entry; - return SPV_SUCCESS; - } else { - // if there is no extension/capability then the version is wrong - return SPV_ERROR_WRONG_VERSION; - } + *pEntry = &entry; + return SPV_SUCCESS; } } } @@ -89,7 +75,7 @@ spv_result_t spvOperandTableNameLookup(spv_target_env env, return SPV_ERROR_INVALID_LOOKUP; } -spv_result_t spvOperandTableValueLookup(spv_target_env env, +spv_result_t spvOperandTableValueLookup(spv_target_env, const spv_operand_table table, const spv_operand_type_t type, const uint32_t value, @@ -110,33 +96,15 @@ spv_result_t spvOperandTableValueLookup(spv_target_env env, const auto beg = group.entries; const auto end = group.entries + group.count; - // We need to loop here because there can exist multiple symbols for the - // same operand value, and they can be introduced in different target - // environments, which means they can have different minimal version - // requirements. For example, SubgroupEqMaskKHR can exist in any SPIR-V - // version as long as the SPV_KHR_shader_ballot extension is there; but - // starting from SPIR-V 1.3, SubgroupEqMask, which has the same numeric - // value as SubgroupEqMaskKHR, is available in core SPIR-V without extension - // requirements. // Assumes the underlying table is already sorted ascendingly according to // opcode value. - const auto version = spvVersionForTargetEnv(env); - for (auto it = std::lower_bound(beg, end, needle, comp); - it != end && it->value == value; ++it) { - // We consider the current operand as available as long as - // 1. The target environment satisfies the minimal requirement of the - // operand; or - // 2. There is at least one extension enabling this operand; or - // 3. There is at least one capability enabling this operand. - // - // Note that the second rule assumes the extension enabling this operand - // is indeed requested in the SPIR-V code; checking that should be - // validator's work. - if ((version >= it->minVersion && version <= it->lastVersion) || - it->numExtensions > 0u || it->numCapabilities > 0u) { - *pEntry = it; - return SPV_SUCCESS; - } + auto it = std::lower_bound(beg, end, needle, comp); + if (it != end && it->value == value) { + // The current operand is considered available as long as + // it is in the grammar. It might not be *valid* to use, + // but that should be checked by the validator, not by parsing. + *pEntry = it; + return SPV_SUCCESS; } } @@ -244,6 +212,14 @@ const char* spvOperandTypeStr(spv_operand_type_t type) { return "cooperative matrix layout"; case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_USE: return "cooperative matrix use"; + case SPV_OPERAND_TYPE_INITIALIZATION_MODE_QUALIFIER: + return "initialization mode qualifier"; + case SPV_OPERAND_TYPE_HOST_ACCESS_QUALIFIER: + return "host access qualifier"; + case SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL: + return "load cache control"; + case SPV_OPERAND_TYPE_STORE_CACHE_CONTROL: + return "store cache control"; case SPV_OPERAND_TYPE_IMAGE: case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: return "image"; @@ -380,6 +356,10 @@ bool spvOperandIsConcrete(spv_operand_type_t type) { case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT: case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_LAYOUT: case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_USE: + case SPV_OPERAND_TYPE_INITIALIZATION_MODE_QUALIFIER: + case SPV_OPERAND_TYPE_HOST_ACCESS_QUALIFIER: + case SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL: + case SPV_OPERAND_TYPE_STORE_CACHE_CONTROL: return true; default: break; diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt index 99a74cd7f8..6ebbfbf005 100644 --- a/source/opt/CMakeLists.txt +++ b/source/opt/CMakeLists.txt @@ -71,6 +71,7 @@ set(SPIRV_TOOLS_OPT_SOURCES instruction_list.h instrument_pass.h interface_var_sroa.h + invocation_interlock_placement_pass.h interp_fixup_pass.h ir_builder.h ir_context.h @@ -121,6 +122,7 @@ set(SPIRV_TOOLS_OPT_SOURCES strip_debug_info_pass.h strip_nonsemantic_info_pass.h struct_cfg_analysis.h + switch_descriptorset_pass.h tree_iterator.h trim_capabilities_pass.h type_manager.h @@ -190,6 +192,7 @@ set(SPIRV_TOOLS_OPT_SOURCES instruction_list.cpp instrument_pass.cpp interface_var_sroa.cpp + invocation_interlock_placement_pass.cpp interp_fixup_pass.cpp ir_context.cpp ir_loader.cpp @@ -237,6 +240,7 @@ set(SPIRV_TOOLS_OPT_SOURCES strip_debug_info_pass.cpp strip_nonsemantic_info_pass.cpp struct_cfg_analysis.cpp + switch_descriptorset_pass.cpp trim_capabilities_pass.cpp type_manager.cpp types.cpp diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp index 87324cdb13..b372571f51 100644 --- a/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/source/opt/aggressive_dead_code_elim_pass.cpp @@ -941,6 +941,8 @@ Pass::Status AggressiveDCEPass::Process() { void AggressiveDCEPass::InitExtensions() { extensions_allowlist_.clear(); + + // clang-format off extensions_allowlist_.insert({ "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_trinary_minmax", @@ -988,6 +990,7 @@ void AggressiveDCEPass::InitExtensions() { "SPV_KHR_ray_query", "SPV_EXT_fragment_invocation_density", "SPV_EXT_physical_storage_buffer", + "SPV_KHR_physical_storage_buffer", "SPV_KHR_terminate_invocation", "SPV_KHR_shader_clock", "SPV_KHR_vulkan_memory_model", @@ -999,7 +1002,10 @@ void AggressiveDCEPass::InitExtensions() { "SPV_KHR_fragment_shader_barycentric", "SPV_NV_bindless_texture", "SPV_EXT_shader_atomic_float_add", + "SPV_EXT_fragment_shader_interlock", + "SPV_NV_compute_shader_derivatives" }); + // clang-format on } Instruction* AggressiveDCEPass::GetHeaderBranch(BasicBlock* blk) { diff --git a/source/opt/dead_insert_elim_pass.cpp b/source/opt/dead_insert_elim_pass.cpp index a48690374e..f985e4c268 100644 --- a/source/opt/dead_insert_elim_pass.cpp +++ b/source/opt/dead_insert_elim_pass.cpp @@ -213,7 +213,8 @@ bool DeadInsertElimPass::EliminateDeadInsertsOnePass(Function* func) { } break; default: { // Mark inserts in chain for all components - MarkInsertChain(&*ii, nullptr, 0, nullptr); + std::unordered_set visited_phis; + MarkInsertChain(&*ii, nullptr, 0, &visited_phis); } break; } }); diff --git a/source/opt/decoration_manager.cpp b/source/opt/decoration_manager.cpp index 1393d480e6..3e95dbc352 100644 --- a/source/opt/decoration_manager.cpp +++ b/source/opt/decoration_manager.cpp @@ -461,7 +461,7 @@ std::vector DecorationManager::InternalGetDecorationsFor( bool DecorationManager::WhileEachDecoration( uint32_t id, uint32_t decoration, - std::function f) { + std::function f) const { for (const Instruction* inst : GetDecorationsFor(id, true)) { switch (inst->opcode()) { case spv::Op::OpMemberDecorate: @@ -485,14 +485,19 @@ bool DecorationManager::WhileEachDecoration( void DecorationManager::ForEachDecoration( uint32_t id, uint32_t decoration, - std::function f) { + std::function f) const { WhileEachDecoration(id, decoration, [&f](const Instruction& inst) { f(inst); return true; }); } -bool DecorationManager::HasDecoration(uint32_t id, uint32_t decoration) { +bool DecorationManager::HasDecoration(uint32_t id, + spv::Decoration decoration) const { + return HasDecoration(id, static_cast(decoration)); +} + +bool DecorationManager::HasDecoration(uint32_t id, uint32_t decoration) const { bool has_decoration = false; ForEachDecoration(id, decoration, [&has_decoration](const Instruction&) { has_decoration = true; diff --git a/source/opt/decoration_manager.h b/source/opt/decoration_manager.h index 1a0d1b1838..2be016a71a 100644 --- a/source/opt/decoration_manager.h +++ b/source/opt/decoration_manager.h @@ -92,20 +92,21 @@ class DecorationManager { // Returns whether a decoration instruction for |id| with decoration // |decoration| exists or not. - bool HasDecoration(uint32_t id, uint32_t decoration); + bool HasDecoration(uint32_t id, uint32_t decoration) const; + bool HasDecoration(uint32_t id, spv::Decoration decoration) const; // |f| is run on each decoration instruction for |id| with decoration // |decoration|. Processed are all decorations which target |id| either // directly or indirectly by Decoration Groups. void ForEachDecoration(uint32_t id, uint32_t decoration, - std::function f); + std::function f) const; // |f| is run on each decoration instruction for |id| with decoration // |decoration|. Processes all decoration which target |id| either directly or // indirectly through decoration groups. If |f| returns false, iteration is // terminated and this function returns false. bool WhileEachDecoration(uint32_t id, uint32_t decoration, - std::function f); + std::function f) const; // |f| is run on each decoration instruction for |id| with decoration // |decoration|. Processes all decoration which target |id| either directly or @@ -141,7 +142,7 @@ class DecorationManager { uint32_t decoration_value); // Add |decoration, decoration_value| of |inst_id, member| to module. - void AddMemberDecoration(uint32_t member, uint32_t inst_id, + void AddMemberDecoration(uint32_t inst_id, uint32_t member, uint32_t decoration, uint32_t decoration_value); friend bool operator==(const DecorationManager&, const DecorationManager&); diff --git a/source/opt/fix_storage_class.cpp b/source/opt/fix_storage_class.cpp index 5597e825b2..564cd1b8a3 100644 --- a/source/opt/fix_storage_class.cpp +++ b/source/opt/fix_storage_class.cpp @@ -318,7 +318,13 @@ uint32_t FixStorageClass::WalkAccessChainType(Instruction* inst, uint32_t id) { const analysis::Constant* index_const = context()->get_constant_mgr()->FindDeclaredConstant( inst->GetSingleWordInOperand(i)); - uint32_t index = index_const->GetU32(); + // It is highly unlikely that any type would have more fields than could + // be indexed by a 32-bit integer, and GetSingleWordInOperand only takes + // a 32-bit value, so we would not be able to handle it anyway. But the + // specification does allow any scalar integer type, treated as signed, + // so we simply downcast the index to 32-bits. + uint32_t index = + static_cast(index_const->GetSignExtendedValue()); id = type_inst->GetSingleWordInOperand(index); break; } diff --git a/source/opt/fold_spec_constant_op_and_composite_pass.cpp b/source/opt/fold_spec_constant_op_and_composite_pass.cpp index f6d61554a4..770e1fe50c 100644 --- a/source/opt/fold_spec_constant_op_and_composite_pass.cpp +++ b/source/opt/fold_spec_constant_op_and_composite_pass.cpp @@ -176,8 +176,9 @@ Instruction* FoldSpecConstantOpAndCompositePass::FoldWithInstructionFolder( Instruction* new_const_inst = context()->get_instruction_folder().FoldInstructionToConstant( inst.get(), identity_map); - assert(new_const_inst != nullptr && - "Failed to fold instruction that must be folded."); + + // new_const_inst == null indicates we cannot fold this spec constant + if (!new_const_inst) return nullptr; // Get the instruction before |pos| to insert after. |pos| cannot be the // first instruction in the list because its type has to come first. diff --git a/source/opt/folding_rules.cpp b/source/opt/folding_rules.cpp index 293236d9f2..5c68e291cd 100644 --- a/source/opt/folding_rules.cpp +++ b/source/opt/folding_rules.cpp @@ -2067,7 +2067,8 @@ FoldingRule FMixFeedingExtract() { } // Returns the number of elements in the composite type |type|. Returns 0 if -// |type| is a scalar value. +// |type| is a scalar value. Return UINT32_MAX when the size is unknown at +// compile time. uint32_t GetNumberOfElements(const analysis::Type* type) { if (auto* vector_type = type->AsVector()) { return vector_type->element_count(); @@ -2079,21 +2080,27 @@ uint32_t GetNumberOfElements(const analysis::Type* type) { return static_cast(struct_type->element_types().size()); } if (auto* array_type = type->AsArray()) { - return array_type->length_info().words[0]; + if (array_type->length_info().words[0] == + analysis::Array::LengthInfo::kConstant && + array_type->length_info().words.size() == 2) { + return array_type->length_info().words[1]; + } + return UINT32_MAX; } return 0; } // Returns a map with the set of values that were inserted into an object by // the chain of OpCompositeInsertInstruction starting with |inst|. -// The map will map the index to the value inserted at that index. +// The map will map the index to the value inserted at that index. An empty map +// will be returned if the map could not be properly generated. std::map GetInsertedValues(Instruction* inst) { analysis::DefUseManager* def_use_mgr = inst->context()->get_def_use_mgr(); std::map values_inserted; Instruction* current_inst = inst; while (current_inst->opcode() == spv::Op::OpCompositeInsert) { if (current_inst->NumInOperands() > inst->NumInOperands()) { - // This is the catch the case + // This is to catch the case // %2 = OpCompositeInsert %m2x2int %v2int_1_0 %m2x2int_undef 0 // %3 = OpCompositeInsert %m2x2int %int_4 %2 0 0 // %4 = OpCompositeInsert %m2x2int %v2int_2_3 %3 1 diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp index 339fb1b62c..8e7d4f83e8 100644 --- a/source/opt/inst_bindless_check_pass.cpp +++ b/source/opt/inst_bindless_check_pass.cpp @@ -39,149 +39,11 @@ constexpr int kSpvTypeImageArrayed = 3; constexpr int kSpvTypeImageMS = 4; } // namespace -void InstBindlessCheckPass::SetupInputBufferIds() { - if (input_buffer_id_ != 0) { - return; - } - AddStorageBufferExt(); - if (!get_feature_mgr()->HasExtension(kSPV_KHR_physical_storage_buffer)) { - context()->AddExtension("SPV_KHR_physical_storage_buffer"); - } - context()->AddCapability(spv::Capability::PhysicalStorageBufferAddresses); - Instruction* memory_model = get_module()->GetMemoryModel(); - // TODO should this be just Physical64? - memory_model->SetInOperand( - 0u, {uint32_t(spv::AddressingModel::PhysicalStorageBuffer64)}); - - analysis::DecorationManager* deco_mgr = get_decoration_mgr(); - analysis::TypeManager* type_mgr = context()->get_type_mgr(); - constexpr uint32_t width = 32u; - - // declare the DescriptorSetData struct - analysis::Struct* desc_set_struct = - GetStruct({type_mgr->GetUIntType(), GetUintRuntimeArrayType(width)}); - desc_set_type_id_ = type_mgr->GetTypeInstruction(desc_set_struct); - // By the Vulkan spec, a pre-existing struct containing a RuntimeArray - // must be a block, and will therefore be decorated with Block. Therefore - // the undecorated type returned here will not be pre-existing and can - // safely be decorated. Since this type is now decorated, it is out of - // sync with the TypeManager and therefore the TypeManager must be - // invalidated after this pass. - assert(context()->get_def_use_mgr()->NumUses(desc_set_type_id_) == 0 && - "used struct type returned"); - deco_mgr->AddDecoration(desc_set_type_id_, uint32_t(spv::Decoration::Block)); - deco_mgr->AddMemberDecoration(desc_set_type_id_, 0, - uint32_t(spv::Decoration::Offset), 0); - deco_mgr->AddMemberDecoration(desc_set_type_id_, 1, - uint32_t(spv::Decoration::Offset), 4); - context()->AddDebug2Inst( - NewGlobalName(desc_set_type_id_, "DescriptorSetData")); - context()->AddDebug2Inst(NewMemberName(desc_set_type_id_, 0, "num_bindings")); - context()->AddDebug2Inst(NewMemberName(desc_set_type_id_, 1, "data")); - - // declare buffer address reference to DescriptorSetData - desc_set_ptr_id_ = type_mgr->FindPointerToType( - desc_set_type_id_, spv::StorageClass::PhysicalStorageBuffer); - // runtime array of buffer addresses - analysis::Type* rarr_ty = GetArray(type_mgr->GetType(desc_set_ptr_id_), - kDebugInputBindlessMaxDescSets); - deco_mgr->AddDecorationVal(type_mgr->GetId(rarr_ty), - uint32_t(spv::Decoration::ArrayStride), 8u); - - // declare the InputBuffer type, a struct wrapper around the runtime array - analysis::Struct* input_buffer_struct = GetStruct({rarr_ty}); - input_buffer_struct_id_ = type_mgr->GetTypeInstruction(input_buffer_struct); - deco_mgr->AddDecoration(input_buffer_struct_id_, - uint32_t(spv::Decoration::Block)); - deco_mgr->AddMemberDecoration(input_buffer_struct_id_, 0, - uint32_t(spv::Decoration::Offset), 0); - context()->AddDebug2Inst( - NewGlobalName(input_buffer_struct_id_, "InputBuffer")); - context()->AddDebug2Inst( - NewMemberName(input_buffer_struct_id_, 0, "desc_sets")); - - input_buffer_ptr_id_ = type_mgr->FindPointerToType( - input_buffer_struct_id_, spv::StorageClass::StorageBuffer); - - // declare the input_buffer global variable - input_buffer_id_ = TakeNextId(); - - const std::vector var_operands = { - {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, - {uint32_t(spv::StorageClass::StorageBuffer)}}, - }; - auto new_var_op = spvtools::MakeUnique( - context(), spv::Op::OpVariable, input_buffer_ptr_id_, input_buffer_id_, - var_operands); - - context()->AddGlobalValue(std::move(new_var_op)); - context()->AddDebug2Inst(NewGlobalName(input_buffer_id_, "input_buffer")); - deco_mgr->AddDecorationVal( - input_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_); - deco_mgr->AddDecorationVal(input_buffer_id_, - uint32_t(spv::Decoration::Binding), - GetInputBufferBinding()); - if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) { - // Add the new buffer to all entry points. - for (auto& entry : get_module()->entry_points()) { - entry.AddOperand({SPV_OPERAND_TYPE_ID, {input_buffer_id_}}); - context()->AnalyzeUses(&entry); - } - } -} - +// This is a stub function for use with Import linkage // clang-format off // GLSL: -//bool inst_bindless_check_desc(uint shader_id, uint inst_num, uvec4 stage_info, uint desc_set, uint binding, uint desc_index, -// uint byte_offset) -//{ -// uint error = 0u; -// uint param5 = 0u; -// uint param6 = 0u; -// uint num_bindings = 0u; -// uint init_state = 0u; -// if (desc_set >= 32u) { -// error = 1u; -// } -// inst_bindless_DescriptorSetData set_data; -// if (error == 0u) { -// set_data = inst_bindless_input_buffer.desc_sets[desc_set]; -// uvec2 ptr_vec = uvec2(set_data); -// if ((ptr_vec.x == 0u) && (ptr_vec.y == 0u)) { -// error = 1u; -// } -// } -// if (error == 0u) { -// num_bindings = set_data.num_bindings; -// if (binding >= num_bindings) { -// error = 1u; -// } -// } -// if (error == 0u) { -// if (desc_index >= set_data.data[binding]) { -// error = 1u; -// param5 = set_data.data[binding]; -// } -// } -// if (0u == error) { -// uint state_index = set_data.data[num_bindings + binding] + desc_index; -// init_state = set_data.data[state_index]; -// if (init_state == 0u) { -// error = 2u; -// } -// } -// if (error == 0u) { -// if (byte_offset >= init_state) { -// error = 4u; -// param5 = byte_offset; -// param6 = init_state; -// } -// } -// if (0u != error) { -// inst_bindless_stream_write_6(shader_id, inst_num, stage_info, error, desc_set, binding, desc_index, param5, param6); -// return false; -// } -// return true; +//bool inst_bindless_check_desc(const uint shader_id, const uint inst_num, const uvec4 stage_info, const uint desc_set, +// const uint binding, const uint desc_index, const uint byte_offset) { //} // clang-format on uint32_t InstBindlessCheckPass::GenDescCheckFunctionId() { @@ -195,11 +57,10 @@ uint32_t InstBindlessCheckPass::GenDescCheckFunctionId() { kByteOffset = 6, kNumArgs }; - if (desc_check_func_id_ != 0) { - return desc_check_func_id_; + if (check_desc_func_id_ != 0) { + return check_desc_func_id_; } - SetupInputBufferIds(); analysis::TypeManager* type_mgr = context()->get_type_mgr(); const analysis::Integer* uint_type = GetInteger(32, false); const analysis::Vector v4uint(uint_type, 4); @@ -211,454 +72,32 @@ uint32_t InstBindlessCheckPass::GenDescCheckFunctionId() { std::unique_ptr func = StartFunction(func_id, type_mgr->GetBoolType(), param_types); - const std::vector param_ids = AddParameters(*func, param_types); - - const uint32_t func_uint_ptr = - type_mgr->FindPointerToType(GetUintId(), spv::StorageClass::Function); - // Create block - auto new_blk_ptr = MakeUnique(NewLabel(TakeNextId())); - InstructionBuilder builder( - context(), new_blk_ptr.get(), - IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); - Instruction* inst; - const uint32_t zero_id = builder.GetUintConstantId(0); - const uint32_t false_id = builder.GetBoolConstantId(false); - const uint32_t true_id = builder.GetBoolConstantId(true); - const uint32_t uint_ptr = type_mgr->FindPointerToType( - GetUintId(), spv::StorageClass::PhysicalStorageBuffer); - - inst = builder.AddBinaryOp(func_uint_ptr, spv::Op::OpVariable, - uint32_t(spv::StorageClass::Function), zero_id); - const uint32_t error_var = inst->result_id(); - - inst = builder.AddBinaryOp(func_uint_ptr, spv::Op::OpVariable, - uint32_t(spv::StorageClass::Function), zero_id); - const uint32_t param5_var = inst->result_id(); - - inst = builder.AddBinaryOp(func_uint_ptr, spv::Op::OpVariable, - uint32_t(spv::StorageClass::Function), zero_id); - const uint32_t param6_var = inst->result_id(); - - inst = builder.AddBinaryOp(func_uint_ptr, spv::Op::OpVariable, - uint32_t(spv::StorageClass::Function), zero_id); - const uint32_t num_bindings_var = inst->result_id(); - inst = builder.AddBinaryOp(func_uint_ptr, spv::Op::OpVariable, - uint32_t(spv::StorageClass::Function), zero_id); - const uint32_t init_status_var = inst->result_id(); - - const uint32_t desc_set_ptr_ptr = type_mgr->FindPointerToType( - desc_set_ptr_id_, spv::StorageClass::Function); - - inst = builder.AddUnaryOp(desc_set_ptr_ptr, spv::Op::OpVariable, - uint32_t(spv::StorageClass::Function)); - const uint32_t desc_set_ptr_var = inst->result_id(); - get_decoration_mgr()->AddDecoration( - desc_set_ptr_var, uint32_t(spv::Decoration::AliasedPointer)); - - uint32_t check_label_id = TakeNextId(); - auto check_label = NewLabel(check_label_id); - uint32_t skip_label_id = TakeNextId(); - auto skip_label = NewLabel(skip_label_id); - inst = builder.AddBinaryOp( - GetBoolId(), spv::Op::OpUGreaterThanEqual, param_ids[kDescSet], - builder.GetUintConstantId(kDebugInputBindlessMaxDescSets)); - const uint32_t desc_cmp_id = inst->result_id(); - - (void)builder.AddConditionalBranch(desc_cmp_id, check_label_id, skip_label_id, - skip_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - - // set error - new_blk_ptr = MakeUnique(std::move(check_label)); - builder.SetInsertPoint(&*new_blk_ptr); - builder.AddStore(error_var, - builder.GetUintConstantId(kInstErrorBindlessBounds)); - builder.AddBranch(skip_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - - // check descriptor set table entry is non-null - new_blk_ptr = MakeUnique(std::move(skip_label)); - builder.SetInsertPoint(&*new_blk_ptr); - - check_label_id = TakeNextId(); - check_label = NewLabel(check_label_id); - skip_label_id = TakeNextId(); - skip_label = NewLabel(skip_label_id); - inst = builder.AddLoad(GetUintId(), error_var); - uint32_t error_val_id = inst->result_id(); - - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, error_val_id, - zero_id); - uint32_t no_error_id = inst->result_id(); - (void)builder.AddConditionalBranch(no_error_id, check_label_id, skip_label_id, - skip_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - - new_blk_ptr = MakeUnique(std::move(check_label)); - builder.SetInsertPoint(&*new_blk_ptr); - - { - const uint32_t desc_set_ptr_ptr_sb = type_mgr->FindPointerToType( - desc_set_ptr_id_, spv::StorageClass::StorageBuffer); - - inst = builder.AddAccessChain(desc_set_ptr_ptr_sb, input_buffer_id_, - {zero_id, param_ids[kDescSet]}); - const uint32_t set_access_chain_id = inst->result_id(); - - inst = builder.AddLoad(desc_set_ptr_id_, set_access_chain_id); - const uint32_t desc_set_ptr_id = inst->result_id(); - - builder.AddStore(desc_set_ptr_var, desc_set_ptr_id); - - inst = builder.AddUnaryOp(GetVecUintId(2), spv::Op::OpBitcast, - desc_set_ptr_id); - const uint32_t ptr_as_uvec_id = inst->result_id(); - - inst = builder.AddCompositeExtract(GetUintId(), ptr_as_uvec_id, {0}); - const uint32_t uvec_x = inst->result_id(); - - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, uvec_x, zero_id); - const uint32_t x_is_zero_id = inst->result_id(); - - inst = builder.AddCompositeExtract(GetUintId(), ptr_as_uvec_id, {1}); - const uint32_t uvec_y = inst->result_id(); - - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, uvec_y, zero_id); - const uint32_t y_is_zero_id = inst->result_id(); - - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpLogicalAnd, x_is_zero_id, - y_is_zero_id); - const uint32_t is_null_id = inst->result_id(); - - const uint32_t error_label_id = TakeNextId(); - auto error_label = NewLabel(error_label_id); - const uint32_t merge_label_id = TakeNextId(); - auto merge_label = NewLabel(merge_label_id); - (void)builder.AddConditionalBranch(is_null_id, error_label_id, - merge_label_id, merge_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - // set error - new_blk_ptr = MakeUnique(std::move(error_label)); - builder.SetInsertPoint(&*new_blk_ptr); - builder.AddStore(error_var, - builder.GetUintConstantId(kInstErrorBindlessBounds)); - builder.AddBranch(merge_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - - new_blk_ptr = MakeUnique(std::move(merge_label)); - builder.SetInsertPoint(&*new_blk_ptr); - builder.AddBranch(skip_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - } - - new_blk_ptr = MakeUnique(std::move(skip_label)); - builder.SetInsertPoint(&*new_blk_ptr); - - check_label_id = TakeNextId(); - check_label = NewLabel(check_label_id); - skip_label_id = TakeNextId(); - skip_label = NewLabel(skip_label_id); - - inst = builder.AddLoad(GetUintId(), error_var); - error_val_id = inst->result_id(); - - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, error_val_id, - zero_id); - no_error_id = inst->result_id(); - (void)builder.AddConditionalBranch(no_error_id, check_label_id, skip_label_id, - skip_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - - // check binding is in range - new_blk_ptr = MakeUnique(std::move(check_label)); - builder.SetInsertPoint(&*new_blk_ptr); - { - inst = builder.AddLoad(desc_set_ptr_id_, desc_set_ptr_var); - const uint32_t desc_set_ptr_id = inst->result_id(); - - inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id, {zero_id}); - const uint32_t binding_access_chain_id = inst->result_id(); - - inst = builder.AddLoad(GetUintId(), binding_access_chain_id, 8); - const uint32_t num_bindings_id = inst->result_id(); - - builder.AddStore(num_bindings_var, num_bindings_id); - - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual, - param_ids[kDescBinding], num_bindings_id); - const uint32_t bindings_cmp_id = inst->result_id(); - - const uint32_t error_label_id = TakeNextId(); - auto error_label = NewLabel(error_label_id); - const uint32_t merge_label_id = TakeNextId(); - auto merge_label = NewLabel(merge_label_id); - (void)builder.AddConditionalBranch(bindings_cmp_id, error_label_id, - merge_label_id, merge_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - // set error - new_blk_ptr = MakeUnique(std::move(error_label)); - builder.SetInsertPoint(&*new_blk_ptr); - builder.AddStore(error_var, - builder.GetUintConstantId(kInstErrorBindlessBounds)); - builder.AddBranch(merge_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - - new_blk_ptr = MakeUnique(std::move(merge_label)); - builder.SetInsertPoint(&*new_blk_ptr); - builder.AddBranch(skip_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - } - - // read binding length - new_blk_ptr = MakeUnique(std::move(skip_label)); - builder.SetInsertPoint(&*new_blk_ptr); - - check_label_id = TakeNextId(); - check_label = NewLabel(check_label_id); - skip_label_id = TakeNextId(); - skip_label = NewLabel(skip_label_id); - - inst = builder.AddLoad(GetUintId(), error_var); - error_val_id = inst->result_id(); - - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, error_val_id, - zero_id); - no_error_id = inst->result_id(); - (void)builder.AddConditionalBranch(no_error_id, check_label_id, skip_label_id, - skip_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - - new_blk_ptr = MakeUnique(std::move(check_label)); - builder.SetInsertPoint(&*new_blk_ptr); - { - inst = builder.AddLoad(desc_set_ptr_id_, desc_set_ptr_var); - const uint32_t desc_set_ptr_id = inst->result_id(); - - inst = builder.AddAccessChain( - uint_ptr, desc_set_ptr_id, - {{builder.GetUintConstantId(1), param_ids[kDescBinding]}}); - const uint32_t length_ac_id = inst->result_id(); - - inst = builder.AddLoad(GetUintId(), length_ac_id, sizeof(uint32_t)); - const uint32_t length_id = inst->result_id(); - - // Check descriptor index in bounds - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual, - param_ids[kDescIndex], length_id); - const uint32_t desc_idx_range_id = inst->result_id(); - - const uint32_t error_label_id = TakeNextId(); - auto error_label = NewLabel(error_label_id); - const uint32_t merge_label_id = TakeNextId(); - auto merge_label = NewLabel(merge_label_id); - (void)builder.AddConditionalBranch(desc_idx_range_id, error_label_id, - merge_label_id, merge_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - // set error - new_blk_ptr = MakeUnique(std::move(error_label)); - builder.SetInsertPoint(&*new_blk_ptr); - builder.AddStore(error_var, - builder.GetUintConstantId(kInstErrorBindlessBounds)); - builder.AddStore(param5_var, length_id); - builder.AddBranch(merge_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - - new_blk_ptr = MakeUnique(std::move(merge_label)); - builder.SetInsertPoint(&*new_blk_ptr); - builder.AddBranch(skip_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - } - - new_blk_ptr = MakeUnique(std::move(skip_label)); - builder.SetInsertPoint(&*new_blk_ptr); - inst = builder.AddLoad(GetUintId(), error_var); - error_val_id = inst->result_id(); - - check_label_id = TakeNextId(); - check_label = NewLabel(check_label_id); - skip_label_id = TakeNextId(); - skip_label = NewLabel(skip_label_id); - - inst = builder.AddLoad(GetUintId(), error_var); - error_val_id = inst->result_id(); - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, zero_id, - error_val_id); - no_error_id = inst->result_id(); - - (void)builder.AddConditionalBranch(no_error_id, check_label_id, skip_label_id, - skip_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - - // Read descriptor init status - new_blk_ptr = MakeUnique(std::move(check_label)); - builder.SetInsertPoint(&*new_blk_ptr); - { - inst = builder.AddLoad(desc_set_ptr_id_, desc_set_ptr_var); - const uint32_t desc_set_ptr_id = inst->result_id(); - - inst = builder.AddLoad(GetUintId(), num_bindings_var); - const uint32_t num_bindings_id = inst->result_id(); - - inst = - builder.AddIAdd(GetUintId(), num_bindings_id, param_ids[kDescBinding]); - const uint32_t state_offset_id = inst->result_id(); - - inst = builder.AddAccessChain( - uint_ptr, desc_set_ptr_id, - {{builder.GetUintConstantId(1), state_offset_id}}); - const uint32_t state_start_ac_id = inst->result_id(); - - inst = builder.AddLoad(GetUintId(), state_start_ac_id, sizeof(uint32_t)); - const uint32_t state_start_id = inst->result_id(); - - inst = builder.AddIAdd(GetUintId(), state_start_id, param_ids[kDescIndex]); - const uint32_t state_entry_id = inst->result_id(); - - // Note: length starts from the beginning of the buffer, not the beginning - // of the data array - inst = builder.AddAccessChain( - uint_ptr, desc_set_ptr_id, - {{builder.GetUintConstantId(1), state_entry_id}}); - const uint32_t init_ac_id = inst->result_id(); - - inst = builder.AddLoad(GetUintId(), init_ac_id, sizeof(uint32_t)); - const uint32_t init_status_id = inst->result_id(); - - builder.AddStore(init_status_var, init_status_id); - - // Check for uninitialized descriptor - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, init_status_id, - zero_id); - const uint32_t uninit_check_id = inst->result_id(); - const uint32_t error_label_id = TakeNextId(); - auto error_label = NewLabel(error_label_id); - const uint32_t merge_label_id = TakeNextId(); - auto merge_label = NewLabel(merge_label_id); - (void)builder.AddConditionalBranch(uninit_check_id, error_label_id, - merge_label_id, merge_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - new_blk_ptr = MakeUnique(std::move(error_label)); - builder.SetInsertPoint(&*new_blk_ptr); - builder.AddStore(error_var, - builder.GetUintConstantId(kInstErrorBindlessUninit)); - builder.AddBranch(merge_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - - new_blk_ptr = MakeUnique(std::move(merge_label)); - builder.SetInsertPoint(&*new_blk_ptr); - builder.AddBranch(skip_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - } - - // Check for OOB. - new_blk_ptr = MakeUnique(std::move(skip_label)); - builder.SetInsertPoint(&*new_blk_ptr); - - check_label_id = TakeNextId(); - check_label = NewLabel(check_label_id); - skip_label_id = TakeNextId(); - skip_label = NewLabel(skip_label_id); - - inst = builder.AddLoad(GetUintId(), error_var); - error_val_id = inst->result_id(); - - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, error_val_id, - zero_id); - no_error_id = inst->result_id(); - (void)builder.AddConditionalBranch(no_error_id, check_label_id, skip_label_id, - skip_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - - new_blk_ptr = MakeUnique(std::move(check_label)); - builder.SetInsertPoint(&*new_blk_ptr); - { - inst = builder.AddLoad(GetUintId(), init_status_var); - const uint32_t init_status_id = inst->result_id(); - - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual, - param_ids[kByteOffset], init_status_id); - const uint32_t buf_offset_range_id = inst->result_id(); - - const uint32_t error_label_id = TakeNextId(); - const uint32_t merge_label_id = TakeNextId(); - auto error_label = NewLabel(error_label_id); - auto merge_label = NewLabel(merge_label_id); - (void)builder.AddConditionalBranch(buf_offset_range_id, error_label_id, - merge_label_id, merge_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - - // set error - new_blk_ptr = MakeUnique(std::move(error_label)); - builder.SetInsertPoint(&*new_blk_ptr); - builder.AddStore(error_var, builder.GetUintConstantId(kInstErrorOOB)); - builder.AddStore(param5_var, param_ids[kByteOffset]); - builder.AddStore(param6_var, init_status_id); - builder.AddBranch(merge_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - - new_blk_ptr = MakeUnique(std::move(merge_label)); - builder.SetInsertPoint(&*new_blk_ptr); - builder.AddBranch(skip_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - } - - // check for error - new_blk_ptr = MakeUnique(std::move(skip_label)); - builder.SetInsertPoint(&*new_blk_ptr); - inst = builder.AddLoad(GetUintId(), error_var); - error_val_id = inst->result_id(); - - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpINotEqual, zero_id, - error_val_id); - const uint32_t is_error_id = inst->result_id(); - - const uint32_t error_label_id = TakeNextId(); - auto error_label = NewLabel(error_label_id); - const uint32_t merge_label_id = TakeNextId(); - auto merge_label = NewLabel(merge_label_id); - (void)builder.AddConditionalBranch(is_error_id, error_label_id, - merge_label_id, merge_label_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - - new_blk_ptr = MakeUnique(std::move(error_label)); - builder.SetInsertPoint(&*new_blk_ptr); - - // error output - inst = builder.AddLoad(GetUintId(), param5_var); - const uint32_t param5_val_id = inst->result_id(); - - inst = builder.AddLoad(GetUintId(), param6_var); - const uint32_t param6_val_id = inst->result_id(); - - GenDebugStreamWrite( - param_ids[kShaderId], param_ids[kInstructionIndex], param_ids[kStageInfo], - {error_val_id, param_ids[kDescSet], param_ids[kDescBinding], - param_ids[kDescIndex], param5_val_id, param6_val_id}, - &builder); - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, false_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - - // Success return - new_blk_ptr = MakeUnique(std::move(merge_label)); - builder.SetInsertPoint(&*new_blk_ptr); - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, true_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - func->SetFunctionEnd(EndFunction()); - context()->AddFunction(std::move(func)); - context()->AddDebug2Inst(NewGlobalName(func_id, "desc_check")); + static const std::string func_name{"inst_bindless_check_desc"}; + context()->AddFunctionDeclaration(std::move(func)); + context()->AddDebug2Inst(NewName(func_id, func_name)); + std::vector operands{ + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {func_id}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, + {uint32_t(spv::Decoration::LinkageAttributes)}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_STRING, + utils::MakeVector(func_name.c_str())}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LINKAGE_TYPE, + {uint32_t(spv::LinkageType::Import)}}, + }; + get_decoration_mgr()->AddDecoration(spv::Op::OpDecorate, operands); - desc_check_func_id_ = func_id; + check_desc_func_id_ = func_id; // Make sure function doesn't get processed by // InstrumentPass::InstProcessCallTreeFromRoots() param2output_func_id_[3] = func_id; - return desc_check_func_id_; + return check_desc_func_id_; } // clang-format off // GLSL: -// result = inst_bindless_desc_check(shader_id, inst_idx, stage_info, desc_set, binding, desc_idx, offset); +// result = inst_bindless_check_desc(shader_id, inst_idx, stage_info, desc_set, binding, desc_idx, offset); // // clang-format on uint32_t InstBindlessCheckPass::GenDescCheckCall( @@ -1134,8 +573,7 @@ uint32_t InstBindlessCheckPass::GenLastByteIdx(RefAnalysis* ref, } void InstBindlessCheckPass::GenCheckCode( - uint32_t check_id, uint32_t error_id, uint32_t offset_id, - uint32_t length_id, uint32_t stage_idx, RefAnalysis* ref, + uint32_t check_id, RefAnalysis* ref, std::vector>* new_blocks) { BasicBlock* back_blk_ptr = &*new_blocks->back(); InstructionBuilder builder( @@ -1164,31 +602,7 @@ void InstBindlessCheckPass::GenCheckCode( // Gen invalid block new_blk_ptr.reset(new BasicBlock(std::move(invalid_label))); builder.SetInsertPoint(&*new_blk_ptr); - if (error_id != 0) { - const uint32_t u_shader_id = builder.GetUintConstantId(shader_id_); - const uint32_t u_inst_id = - builder.GetUintConstantId(ref->ref_inst->unique_id()); - const uint32_t shader_info_id = GenStageInfo(stage_idx, &builder); - const uint32_t u_set_id = builder.GetUintConstantId(ref->set); - const uint32_t u_binding_id = builder.GetUintConstantId(ref->binding); - const uint32_t u_index_id = GenUintCastCode(ref->desc_idx_id, &builder); - const uint32_t u_length_id = GenUintCastCode(length_id, &builder); - if (offset_id != 0) { - const uint32_t u_offset_id = GenUintCastCode(offset_id, &builder); - // Buffer OOB - GenDebugStreamWrite(u_shader_id, u_inst_id, shader_info_id, - {error_id, u_set_id, u_binding_id, u_index_id, - u_offset_id, u_length_id}, - &builder); - } else { - // Uninitialized Descriptor - Return additional unused zero so all error - // modes will use same debug stream write function - GenDebugStreamWrite(u_shader_id, u_inst_id, shader_info_id, - {error_id, u_set_id, u_binding_id, u_index_id, - u_length_id, builder.GetUintConstantId(0)}, - &builder); - } - } + // Generate a ConstantNull, converting to uint64 if the type cannot be a null. if (new_ref_id != 0) { analysis::TypeManager* type_mgr = context()->get_type_mgr(); @@ -1283,7 +697,7 @@ void InstBindlessCheckPass::GenDescCheckCode( // Generate runtime initialization/bounds test code with true branch // being full reference and false branch being zero // for the referenced value. - GenCheckCode(check_id, 0, 0, 0, stage_idx, &ref, new_blocks); + GenCheckCode(check_id, &ref, new_blocks); // Move original block's remaining code into remainder/merge block and add // to new blocks @@ -1310,7 +724,20 @@ void InstBindlessCheckPass::InitializeInstBindlessCheck() { } Pass::Status InstBindlessCheckPass::ProcessImpl() { - bool modified = false; + // The memory model and linkage must always be updated for spirv-link to work + // correctly. + AddStorageBufferExt(); + if (!get_feature_mgr()->HasExtension(kSPV_KHR_physical_storage_buffer)) { + context()->AddExtension("SPV_KHR_physical_storage_buffer"); + } + + context()->AddCapability(spv::Capability::PhysicalStorageBufferAddresses); + Instruction* memory_model = get_module()->GetMemoryModel(); + memory_model->SetInOperand( + 0u, {uint32_t(spv::AddressingModel::PhysicalStorageBuffer64)}); + + context()->AddCapability(spv::Capability::Linkage); + InstProcessFunction pfn = [this](BasicBlock::iterator ref_inst_itr, UptrVectorIterator ref_block_itr, uint32_t stage_idx, @@ -1319,8 +746,10 @@ Pass::Status InstBindlessCheckPass::ProcessImpl() { new_blocks); }; - modified = InstProcessEntryPointCallTree(pfn); - return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; + InstProcessEntryPointCallTree(pfn); + // This pass always changes the memory model, so that linking will work + // properly. + return Status::SuccessWithChange; } Pass::Status InstBindlessCheckPass::Process() { diff --git a/source/opt/inst_bindless_check_pass.h b/source/opt/inst_bindless_check_pass.h index 289f02f1ab..243cba7671 100644 --- a/source/opt/inst_bindless_check_pass.h +++ b/source/opt/inst_bindless_check_pass.h @@ -28,8 +28,8 @@ namespace opt { // external design may change as the layer evolves. class InstBindlessCheckPass : public InstrumentPass { public: - InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id) - : InstrumentPass(desc_set, shader_id, kInstValidationIdBindless, true) {} + InstBindlessCheckPass(uint32_t shader_id) + : InstrumentPass(0, shader_id, true, true) {} ~InstBindlessCheckPass() override = default; @@ -44,8 +44,6 @@ class InstBindlessCheckPass : public InstrumentPass { uint32_t stage_idx, std::vector>* new_blocks); - void SetupInputBufferIds(); - uint32_t GenDescCheckFunctionId(); uint32_t GenDescCheckCall(uint32_t inst_idx, uint32_t stage_idx, @@ -107,8 +105,7 @@ class InstBindlessCheckPass : public InstrumentPass { // writes debug error output utilizing |ref|, |error_id|, |length_id| and // |stage_idx|. Generate merge block for valid and invalid branches. Kill // original reference. - void GenCheckCode(uint32_t check_id, uint32_t error_id, uint32_t offset_id, - uint32_t length_id, uint32_t stage_idx, RefAnalysis* ref, + void GenCheckCode(uint32_t check_id, RefAnalysis* ref, std::vector>* new_blocks); // Initialize state for instrumenting bindless checking @@ -124,11 +121,7 @@ class InstBindlessCheckPass : public InstrumentPass { // Mapping from variable to binding std::unordered_map var2binding_; - uint32_t desc_check_func_id_{0}; - uint32_t desc_set_type_id_{0}; - uint32_t desc_set_ptr_id_{0}; - uint32_t input_buffer_struct_id_{0}; - uint32_t input_buffer_ptr_id_{0}; + uint32_t check_desc_func_id_{0}; }; } // namespace opt diff --git a/source/opt/inst_buff_addr_check_pass.cpp b/source/opt/inst_buff_addr_check_pass.cpp index 6b90e5888e..e6c550878a 100644 --- a/source/opt/inst_buff_addr_check_pass.cpp +++ b/source/opt/inst_buff_addr_check_pass.cpp @@ -19,24 +19,6 @@ namespace spvtools { namespace opt { -bool InstBuffAddrCheckPass::InstrumentFunction(Function* func, - uint32_t stage_idx, - InstProcessFunction& pfn) { - // The bindless instrumentation pass adds functions that use - // BufferDeviceAddress They should not be instrumented by this pass. - Instruction* func_name_inst = - context()->GetNames(func->DefInst().result_id()).begin()->second; - if (func_name_inst) { - static const std::string kPrefix{"inst_bindless_"}; - std::string func_name = func_name_inst->GetOperand(1).AsString(); - if (func_name.size() >= kPrefix.size() && - func_name.compare(0, kPrefix.size(), kPrefix) == 0) { - return false; - } - } - return InstrumentPass::InstrumentFunction(func, stage_idx, pfn); -} - uint32_t InstBuffAddrCheckPass::CloneOriginalReference( Instruction* ref_inst, InstructionBuilder* builder) { // Clone original ref with new result id (if load) @@ -76,8 +58,7 @@ bool InstBuffAddrCheckPass::IsPhysicalBuffAddrReference(Instruction* ref_inst) { // TODO(greg-lunarg): Refactor with InstBindlessCheckPass::GenCheckCode() ?? void InstBuffAddrCheckPass::GenCheckCode( - uint32_t check_id, uint32_t error_id, uint32_t ref_uptr_id, - uint32_t stage_idx, Instruction* ref_inst, + uint32_t check_id, Instruction* ref_inst, std::vector>* new_blocks) { BasicBlock* back_blk_ptr = &*new_blocks->back(); InstructionBuilder builder( @@ -104,20 +85,6 @@ void InstBuffAddrCheckPass::GenCheckCode( // Gen invalid block new_blk_ptr.reset(new BasicBlock(std::move(invalid_label))); builder.SetInsertPoint(&*new_blk_ptr); - // Convert uptr from uint64 to 2 uint32 - Instruction* lo_uptr_inst = - builder.AddUnaryOp(GetUintId(), spv::Op::OpUConvert, ref_uptr_id); - Instruction* rshift_uptr_inst = - builder.AddBinaryOp(GetUint64Id(), spv::Op::OpShiftRightLogical, - ref_uptr_id, builder.GetUintConstantId(32)); - Instruction* hi_uptr_inst = builder.AddUnaryOp( - GetUintId(), spv::Op::OpUConvert, rshift_uptr_inst->result_id()); - GenDebugStreamWrite( - builder.GetUintConstantId(shader_id_), - builder.GetUintConstantId(uid2offset_[ref_inst->unique_id()]), - GenStageInfo(stage_idx, &builder), - {error_id, lo_uptr_inst->result_id(), hi_uptr_inst->result_id()}, - &builder); // Gen zero for invalid load. If pointer type, need to convert uint64 // zero to pointer; cannot create ConstantNull of pointer type. uint32_t null_id = 0; @@ -206,201 +173,86 @@ void InstBuffAddrCheckPass::AddParam(uint32_t type_id, (*input_func)->AddParameter(std::move(param_inst)); } +// This is a stub function for use with Import linkage +// clang-format off +// GLSL: +//bool inst_bindless_search_and_test(const uint shader_id, const uint inst_num, const uvec4 stage_info, +// const uint64 ref_ptr, const uint length) { +//} +// clang-format on uint32_t InstBuffAddrCheckPass::GetSearchAndTestFuncId() { - if (search_test_func_id_ == 0) { - // Generate function "bool search_and_test(uint64_t ref_ptr, uint32_t len)" - // which searches input buffer for buffer which most likely contains the - // pointer value |ref_ptr| and verifies that the entire reference of - // length |len| bytes is contained in the buffer. - search_test_func_id_ = TakeNextId(); - analysis::TypeManager* type_mgr = context()->get_type_mgr(); - std::vector param_types = { - type_mgr->GetType(GetUint64Id()), type_mgr->GetType(GetUintId())}; - analysis::Function func_ty(type_mgr->GetType(GetBoolId()), param_types); - analysis::Type* reg_func_ty = type_mgr->GetRegisteredType(&func_ty); - std::unique_ptr func_inst( - new Instruction(get_module()->context(), spv::Op::OpFunction, - GetBoolId(), search_test_func_id_, - {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, - {uint32_t(spv::FunctionControlMask::MaskNone)}}, - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, - {type_mgr->GetTypeInstruction(reg_func_ty)}}})); - get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst); - std::unique_ptr input_func = - MakeUnique(std::move(func_inst)); - std::vector param_vec; - // Add ref_ptr and length parameters - AddParam(GetUint64Id(), ¶m_vec, &input_func); - AddParam(GetUintId(), ¶m_vec, &input_func); - // Empty first block. - uint32_t first_blk_id = TakeNextId(); - std::unique_ptr first_blk_label(NewLabel(first_blk_id)); - std::unique_ptr first_blk_ptr = - MakeUnique(std::move(first_blk_label)); - InstructionBuilder builder( - context(), &*first_blk_ptr, - IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); - uint32_t hdr_blk_id = TakeNextId(); - // Branch to search loop header - std::unique_ptr hdr_blk_label(NewLabel(hdr_blk_id)); - (void)builder.AddBranch(hdr_blk_id); - input_func->AddBasicBlock(std::move(first_blk_ptr)); - // Linear search loop header block - // TODO(greg-lunarg): Implement binary search - std::unique_ptr hdr_blk_ptr = - MakeUnique(std::move(hdr_blk_label)); - builder.SetInsertPoint(&*hdr_blk_ptr); - // Phi for search index. Starts with 1. - uint32_t cont_blk_id = TakeNextId(); - std::unique_ptr cont_blk_label(NewLabel(cont_blk_id)); - // Deal with def-use cycle caused by search loop index computation. - // Create Add and Phi instructions first, then do Def analysis on Add. - // Add Phi and Add instructions and do Use analysis later. - uint32_t idx_phi_id = TakeNextId(); - uint32_t idx_inc_id = TakeNextId(); - std::unique_ptr idx_inc_inst(new Instruction( - context(), spv::Op::OpIAdd, GetUintId(), idx_inc_id, - {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {idx_phi_id}}, - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, - {builder.GetUintConstantId(1u)}}})); - std::unique_ptr idx_phi_inst(new Instruction( - context(), spv::Op::OpPhi, GetUintId(), idx_phi_id, - {{spv_operand_type_t::SPV_OPERAND_TYPE_ID, - {builder.GetUintConstantId(1u)}}, - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {first_blk_id}}, - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {idx_inc_id}}, - {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {cont_blk_id}}})); - get_def_use_mgr()->AnalyzeInstDef(&*idx_inc_inst); - // Add (previously created) search index phi - (void)builder.AddInstruction(std::move(idx_phi_inst)); - // LoopMerge - uint32_t bound_test_blk_id = TakeNextId(); - std::unique_ptr bound_test_blk_label( - NewLabel(bound_test_blk_id)); - (void)builder.AddLoopMerge(bound_test_blk_id, cont_blk_id, - uint32_t(spv::LoopControlMask::MaskNone)); - // Branch to continue/work block - (void)builder.AddBranch(cont_blk_id); - input_func->AddBasicBlock(std::move(hdr_blk_ptr)); - // Continue/Work Block. Read next buffer pointer and break if greater - // than ref_ptr arg. - std::unique_ptr cont_blk_ptr = - MakeUnique(std::move(cont_blk_label)); - builder.SetInsertPoint(&*cont_blk_ptr); - // Add (previously created) search index increment now. - (void)builder.AddInstruction(std::move(idx_inc_inst)); - // Load next buffer address from debug input buffer - uint32_t ibuf_id = GetInputBufferId(); - uint32_t ibuf_ptr_id = GetInputBufferPtrId(); - Instruction* uptr_ac_inst = builder.AddTernaryOp( - ibuf_ptr_id, spv::Op::OpAccessChain, ibuf_id, - builder.GetUintConstantId(kDebugInputDataOffset), idx_inc_id); - uint32_t ibuf_type_id = GetInputBufferTypeId(); - Instruction* uptr_load_inst = builder.AddUnaryOp( - ibuf_type_id, spv::Op::OpLoad, uptr_ac_inst->result_id()); - // If loaded address greater than ref_ptr arg, break, else branch back to - // loop header - Instruction* uptr_test_inst = - builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThan, - uptr_load_inst->result_id(), param_vec[0]); - (void)builder.AddConditionalBranch( - uptr_test_inst->result_id(), bound_test_blk_id, hdr_blk_id, kInvalidId, - uint32_t(spv::SelectionControlMask::MaskNone)); - input_func->AddBasicBlock(std::move(cont_blk_ptr)); - // Bounds test block. Read length of selected buffer and test that - // all len arg bytes are in buffer. - std::unique_ptr bound_test_blk_ptr = - MakeUnique(std::move(bound_test_blk_label)); - builder.SetInsertPoint(&*bound_test_blk_ptr); - // Decrement index to point to previous/candidate buffer address - Instruction* cand_idx_inst = - builder.AddBinaryOp(GetUintId(), spv::Op::OpISub, idx_inc_id, - builder.GetUintConstantId(1u)); - // Load candidate buffer address - Instruction* cand_ac_inst = - builder.AddTernaryOp(ibuf_ptr_id, spv::Op::OpAccessChain, ibuf_id, - builder.GetUintConstantId(kDebugInputDataOffset), - cand_idx_inst->result_id()); - Instruction* cand_load_inst = builder.AddUnaryOp( - ibuf_type_id, spv::Op::OpLoad, cand_ac_inst->result_id()); - // Compute offset of ref_ptr from candidate buffer address - Instruction* offset_inst = - builder.AddBinaryOp(ibuf_type_id, spv::Op::OpISub, param_vec[0], - cand_load_inst->result_id()); - // Convert ref length to uint64 - Instruction* ref_len_64_inst = - builder.AddUnaryOp(ibuf_type_id, spv::Op::OpUConvert, param_vec[1]); - // Add ref length to ref offset to compute end of reference - Instruction* ref_end_inst = builder.AddBinaryOp( - ibuf_type_id, spv::Op::OpIAdd, offset_inst->result_id(), - ref_len_64_inst->result_id()); - // Load starting index of lengths in input buffer and convert to uint32 - Instruction* len_start_ac_inst = - builder.AddTernaryOp(ibuf_ptr_id, spv::Op::OpAccessChain, ibuf_id, - builder.GetUintConstantId(kDebugInputDataOffset), - builder.GetUintConstantId(0u)); - Instruction* len_start_load_inst = builder.AddUnaryOp( - ibuf_type_id, spv::Op::OpLoad, len_start_ac_inst->result_id()); - Instruction* len_start_32_inst = builder.AddUnaryOp( - GetUintId(), spv::Op::OpUConvert, len_start_load_inst->result_id()); - // Decrement search index to get candidate buffer length index - Instruction* cand_len_idx_inst = builder.AddBinaryOp( - GetUintId(), spv::Op::OpISub, cand_idx_inst->result_id(), - builder.GetUintConstantId(1u)); - // Add candidate length index to start index - Instruction* len_idx_inst = builder.AddBinaryOp( - GetUintId(), spv::Op::OpIAdd, cand_len_idx_inst->result_id(), - len_start_32_inst->result_id()); - // Load candidate buffer length - Instruction* len_ac_inst = - builder.AddTernaryOp(ibuf_ptr_id, spv::Op::OpAccessChain, ibuf_id, - builder.GetUintConstantId(kDebugInputDataOffset), - len_idx_inst->result_id()); - Instruction* len_load_inst = builder.AddUnaryOp( - ibuf_type_id, spv::Op::OpLoad, len_ac_inst->result_id()); - // Test if reference end within candidate buffer length - Instruction* len_test_inst = builder.AddBinaryOp( - GetBoolId(), spv::Op::OpULessThanEqual, ref_end_inst->result_id(), - len_load_inst->result_id()); - // Return test result - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, - len_test_inst->result_id()); - // Close block - input_func->AddBasicBlock(std::move(bound_test_blk_ptr)); - // Close function and add function to module - std::unique_ptr func_end_inst(new Instruction( - get_module()->context(), spv::Op::OpFunctionEnd, 0, 0, {})); - get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst); - input_func->SetFunctionEnd(std::move(func_end_inst)); - context()->AddFunction(std::move(input_func)); - context()->AddDebug2Inst( - NewGlobalName(search_test_func_id_, "search_and_test")); + enum { + kShaderId = 0, + kInstructionIndex = 1, + kStageInfo = 2, + kRefPtr = 3, + kLength = 4, + kNumArgs + }; + if (search_test_func_id_ != 0) { + return search_test_func_id_; } + // Generate function "bool search_and_test(uint64_t ref_ptr, uint32_t len)" + // which searches input buffer for buffer which most likely contains the + // pointer value |ref_ptr| and verifies that the entire reference of + // length |len| bytes is contained in the buffer. + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + const analysis::Integer* uint_type = GetInteger(32, false); + const analysis::Vector v4uint(uint_type, 4); + const analysis::Type* v4uint_type = type_mgr->GetRegisteredType(&v4uint); + + std::vector param_types = { + uint_type, uint_type, v4uint_type, type_mgr->GetType(GetUint64Id()), + uint_type}; + + const std::string func_name{"inst_buff_addr_search_and_test"}; + const uint32_t func_id = TakeNextId(); + std::unique_ptr func = + StartFunction(func_id, type_mgr->GetBoolType(), param_types); + func->SetFunctionEnd(EndFunction()); + context()->AddFunctionDeclaration(std::move(func)); + context()->AddDebug2Inst(NewName(func_id, func_name)); + + std::vector operands{ + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {func_id}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, + {uint32_t(spv::Decoration::LinkageAttributes)}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_STRING, + utils::MakeVector(func_name.c_str())}, + {spv_operand_type_t::SPV_OPERAND_TYPE_LINKAGE_TYPE, + {uint32_t(spv::LinkageType::Import)}}, + }; + get_decoration_mgr()->AddDecoration(spv::Op::OpDecorate, operands); + + search_test_func_id_ = func_id; return search_test_func_id_; } uint32_t InstBuffAddrCheckPass::GenSearchAndTest(Instruction* ref_inst, InstructionBuilder* builder, - uint32_t* ref_uptr_id) { + uint32_t* ref_uptr_id, + uint32_t stage_idx) { // Enable Int64 if necessary - context()->AddCapability(spv::Capability::Int64); // Convert reference pointer to uint64 - uint32_t ref_ptr_id = ref_inst->GetSingleWordInOperand(0); + const uint32_t ref_ptr_id = ref_inst->GetSingleWordInOperand(0); Instruction* ref_uptr_inst = builder->AddUnaryOp(GetUint64Id(), spv::Op::OpConvertPtrToU, ref_ptr_id); *ref_uptr_id = ref_uptr_inst->result_id(); // Compute reference length in bytes analysis::DefUseManager* du_mgr = get_def_use_mgr(); Instruction* ref_ptr_inst = du_mgr->GetDef(ref_ptr_id); - uint32_t ref_ptr_ty_id = ref_ptr_inst->type_id(); + const uint32_t ref_ptr_ty_id = ref_ptr_inst->type_id(); Instruction* ref_ptr_ty_inst = du_mgr->GetDef(ref_ptr_ty_id); - uint32_t ref_len = GetTypeLength(ref_ptr_ty_inst->GetSingleWordInOperand(1)); - uint32_t ref_len_id = builder->GetUintConstantId(ref_len); + const uint32_t ref_len = + GetTypeLength(ref_ptr_ty_inst->GetSingleWordInOperand(1)); // Gen call to search and test function - Instruction* call_inst = builder->AddFunctionCall( - GetBoolId(), GetSearchAndTestFuncId(), {*ref_uptr_id, ref_len_id}); - uint32_t retval = call_inst->result_id(); - return retval; + const uint32_t func_id = GetSearchAndTestFuncId(); + const std::vector args = { + builder->GetUintConstantId(shader_id_), + builder->GetUintConstantId(ref_inst->unique_id()), + GenStageInfo(stage_idx, builder), *ref_uptr_id, + builder->GetUintConstantId(ref_len)}; + return GenReadFunctionCall(GetBoolId(), func_id, args, builder); } void InstBuffAddrCheckPass::GenBuffAddrCheckCode( @@ -418,16 +270,16 @@ void InstBuffAddrCheckPass::GenBuffAddrCheckCode( context(), &*new_blk_ptr, IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); new_blocks->push_back(std::move(new_blk_ptr)); - uint32_t error_id = builder.GetUintConstantId(kInstErrorBuffAddrUnallocRef); // Generate code to do search and test if all bytes of reference // are within a listed buffer. Return reference pointer converted to uint64. uint32_t ref_uptr_id; - uint32_t valid_id = GenSearchAndTest(ref_inst, &builder, &ref_uptr_id); + uint32_t valid_id = + GenSearchAndTest(ref_inst, &builder, &ref_uptr_id, stage_idx); // Generate test of search results with true branch // being full reference and false branch being debug output and zero // for the referenced value. - GenCheckCode(valid_id, error_id, ref_uptr_id, stage_idx, ref_inst, - new_blocks); + GenCheckCode(valid_id, ref_inst, new_blocks); + // Move original block's remaining code into remainder/merge block and add // to new blocks BasicBlock* back_blk_ptr = &*new_blocks->back(); @@ -442,6 +294,20 @@ void InstBuffAddrCheckPass::InitInstBuffAddrCheck() { } Pass::Status InstBuffAddrCheckPass::ProcessImpl() { + // The memory model and linkage must always be updated for spirv-link to work + // correctly. + AddStorageBufferExt(); + if (!get_feature_mgr()->HasExtension(kSPV_KHR_physical_storage_buffer)) { + context()->AddExtension("SPV_KHR_physical_storage_buffer"); + } + + context()->AddCapability(spv::Capability::PhysicalStorageBufferAddresses); + Instruction* memory_model = get_module()->GetMemoryModel(); + memory_model->SetInOperand( + 0u, {uint32_t(spv::AddressingModel::PhysicalStorageBuffer64)}); + + context()->AddCapability(spv::Capability::Int64); + context()->AddCapability(spv::Capability::Linkage); // Perform bindless bounds check on each entry point function in module InstProcessFunction pfn = [this](BasicBlock::iterator ref_inst_itr, @@ -450,14 +316,13 @@ Pass::Status InstBuffAddrCheckPass::ProcessImpl() { return GenBuffAddrCheckCode(ref_inst_itr, ref_block_itr, stage_idx, new_blocks); }; - bool modified = InstProcessEntryPointCallTree(pfn); - return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; + InstProcessEntryPointCallTree(pfn); + // This pass always changes the memory model, so that linking will work + // properly. + return Status::SuccessWithChange; } Pass::Status InstBuffAddrCheckPass::Process() { - if (!get_feature_mgr()->HasCapability( - spv::Capability::PhysicalStorageBufferAddressesEXT)) - return Status::SuccessWithoutChange; InitInstBuffAddrCheck(); return ProcessImpl(); } diff --git a/source/opt/inst_buff_addr_check_pass.h b/source/opt/inst_buff_addr_check_pass.h index 9c4b3ed9a9..f07f98a0f2 100644 --- a/source/opt/inst_buff_addr_check_pass.h +++ b/source/opt/inst_buff_addr_check_pass.h @@ -29,10 +29,10 @@ namespace opt { class InstBuffAddrCheckPass : public InstrumentPass { public: // For test harness only - InstBuffAddrCheckPass() : InstrumentPass(7, 23, kInstValidationIdBuffAddr) {} + InstBuffAddrCheckPass() : InstrumentPass(0, 23, false, true) {} // For all other interfaces - InstBuffAddrCheckPass(uint32_t desc_set, uint32_t shader_id) - : InstrumentPass(desc_set, shader_id, kInstValidationIdBuffAddr) {} + InstBuffAddrCheckPass(uint32_t shader_id) + : InstrumentPass(0, shader_id, false, true) {} ~InstBuffAddrCheckPass() override = default; @@ -41,9 +41,6 @@ class InstBuffAddrCheckPass : public InstrumentPass { const char* name() const override { return "inst-buff-addr-check-pass"; } - bool InstrumentFunction(Function* func, uint32_t stage_idx, - InstProcessFunction& pfn) override; - private: // Return byte length of type |type_id|. Must be int, float, vector, matrix, // struct, array or physical pointer. Uses std430 alignment and sizes. @@ -61,7 +58,7 @@ class InstBuffAddrCheckPass : public InstrumentPass { // are within the buffer. Returns id of boolean value which is true if // search and test is successful, false otherwise. uint32_t GenSearchAndTest(Instruction* ref_inst, InstructionBuilder* builder, - uint32_t* ref_uptr_id); + uint32_t* ref_uptr_id, uint32_t stage_idx); // This function does checking instrumentation on a single // instruction which references through a physical storage buffer address. @@ -114,8 +111,7 @@ class InstBuffAddrCheckPass : public InstrumentPass { // writes debug error output utilizing |ref_inst|, |error_id| and // |stage_idx|. Generate merge block for valid and invalid reference blocks. // Kill original reference. - void GenCheckCode(uint32_t check_id, uint32_t error_id, uint32_t length_id, - uint32_t stage_idx, Instruction* ref_inst, + void GenCheckCode(uint32_t check_id, Instruction* ref_inst, std::vector>* new_blocks); // Initialize state for instrumenting physical buffer address checking diff --git a/source/opt/inst_debug_printf_pass.cpp b/source/opt/inst_debug_printf_pass.cpp index f7c227455e..abd25e9396 100644 --- a/source/opt/inst_debug_printf_pass.cpp +++ b/source/opt/inst_debug_printf_pass.cpp @@ -16,6 +16,7 @@ #include "inst_debug_printf_pass.h" +#include "source/spirv_constant.h" #include "source/util/string_utils.h" #include "spirv/unified1/NonSemanticDebugPrintf.h" @@ -137,7 +138,7 @@ void InstDebugPrintfPass::GenOutputValues(Instruction* val_inst, } void InstDebugPrintfPass::GenOutputCode( - Instruction* printf_inst, uint32_t stage_idx, + Instruction* printf_inst, std::vector>* new_blocks) { BasicBlock* back_blk_ptr = &*new_blocks->back(); InstructionBuilder builder( @@ -167,14 +168,14 @@ void InstDebugPrintfPass::GenOutputCode( }); GenDebugStreamWrite( builder.GetUintConstantId(shader_id_), - builder.GetUintConstantId(uid2offset_[printf_inst->unique_id()]), - GenStageInfo(stage_idx, &builder), val_ids, &builder); + builder.GetUintConstantId(uid2offset_[printf_inst->unique_id()]), val_ids, + &builder); context()->KillInst(printf_inst); } void InstDebugPrintfPass::GenDebugPrintfCode( BasicBlock::iterator ref_inst_itr, - UptrVectorIterator ref_block_itr, uint32_t stage_idx, + UptrVectorIterator ref_block_itr, std::vector>* new_blocks) { // If not DebugPrintf OpExtInst, return. Instruction* printf_inst = &*ref_inst_itr; @@ -190,7 +191,7 @@ void InstDebugPrintfPass::GenDebugPrintfCode( MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr); new_blocks->push_back(std::move(new_blk_ptr)); // Generate instructions to output printf args to printf buffer - GenOutputCode(printf_inst, stage_idx, new_blocks); + GenOutputCode(printf_inst, new_blocks); // Caller expects at least two blocks with last block containing remaining // code, so end block after instrumentation, create remainder block, and // branch to it @@ -210,19 +211,243 @@ void InstDebugPrintfPass::GenDebugPrintfCode( new_blocks->push_back(std::move(new_blk_ptr)); } +// Return id for output buffer +uint32_t InstDebugPrintfPass::GetOutputBufferId() { + if (output_buffer_id_ == 0) { + // If not created yet, create one + analysis::DecorationManager* deco_mgr = get_decoration_mgr(); + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::RuntimeArray* reg_uint_rarr_ty = GetUintRuntimeArrayType(32); + analysis::Integer* reg_uint_ty = GetInteger(32, false); + analysis::Type* reg_buf_ty = + GetStruct({reg_uint_ty, reg_uint_ty, reg_uint_rarr_ty}); + uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_buf_ty); + // By the Vulkan spec, a pre-existing struct containing a RuntimeArray + // must be a block, and will therefore be decorated with Block. Therefore + // the undecorated type returned here will not be pre-existing and can + // safely be decorated. Since this type is now decorated, it is out of + // sync with the TypeManager and therefore the TypeManager must be + // invalidated after this pass. + assert(context()->get_def_use_mgr()->NumUses(obufTyId) == 0 && + "used struct type returned"); + deco_mgr->AddDecoration(obufTyId, uint32_t(spv::Decoration::Block)); + deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputFlagsOffset, + uint32_t(spv::Decoration::Offset), 0); + deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset, + uint32_t(spv::Decoration::Offset), 4); + deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset, + uint32_t(spv::Decoration::Offset), 8); + uint32_t obufTyPtrId_ = + type_mgr->FindPointerToType(obufTyId, spv::StorageClass::StorageBuffer); + output_buffer_id_ = TakeNextId(); + std::unique_ptr newVarOp(new Instruction( + context(), spv::Op::OpVariable, obufTyPtrId_, output_buffer_id_, + {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, + {uint32_t(spv::StorageClass::StorageBuffer)}}})); + context()->AddGlobalValue(std::move(newVarOp)); + context()->AddDebug2Inst(NewGlobalName(obufTyId, "OutputBuffer")); + context()->AddDebug2Inst(NewMemberName(obufTyId, 0, "flags")); + context()->AddDebug2Inst(NewMemberName(obufTyId, 1, "written_count")); + context()->AddDebug2Inst(NewMemberName(obufTyId, 2, "data")); + context()->AddDebug2Inst(NewGlobalName(output_buffer_id_, "output_buffer")); + deco_mgr->AddDecorationVal( + output_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_); + deco_mgr->AddDecorationVal(output_buffer_id_, + uint32_t(spv::Decoration::Binding), + GetOutputBufferBinding()); + AddStorageBufferExt(); + if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) { + // Add the new buffer to all entry points. + for (auto& entry : get_module()->entry_points()) { + entry.AddOperand({SPV_OPERAND_TYPE_ID, {output_buffer_id_}}); + context()->AnalyzeUses(&entry); + } + } + } + return output_buffer_id_; +} + +uint32_t InstDebugPrintfPass::GetOutputBufferPtrId() { + if (output_buffer_ptr_id_ == 0) { + output_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType( + GetUintId(), spv::StorageClass::StorageBuffer); + } + return output_buffer_ptr_id_; +} + +uint32_t InstDebugPrintfPass::GetOutputBufferBinding() { + return kDebugOutputPrintfStream; +} + +void InstDebugPrintfPass::GenDebugOutputFieldCode(uint32_t base_offset_id, + uint32_t field_offset, + uint32_t field_value_id, + InstructionBuilder* builder) { + // Cast value to 32-bit unsigned if necessary + uint32_t val_id = GenUintCastCode(field_value_id, builder); + // Store value + Instruction* data_idx_inst = builder->AddIAdd( + GetUintId(), base_offset_id, builder->GetUintConstantId(field_offset)); + uint32_t buf_id = GetOutputBufferId(); + uint32_t buf_uint_ptr_id = GetOutputBufferPtrId(); + Instruction* achain_inst = builder->AddAccessChain( + buf_uint_ptr_id, buf_id, + {builder->GetUintConstantId(kDebugOutputDataOffset), + data_idx_inst->result_id()}); + (void)builder->AddStore(achain_inst->result_id(), val_id); +} + +uint32_t InstDebugPrintfPass::GetStreamWriteFunctionId(uint32_t param_cnt) { + enum { + kShaderId = 0, + kInstructionIndex = 1, + kFirstParam = 2, + }; + // Total param count is common params plus validation-specific + // params + if (param2output_func_id_[param_cnt] == 0) { + // Create function + param2output_func_id_[param_cnt] = TakeNextId(); + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + + const analysis::Type* uint_type = GetInteger(32, false); + + std::vector param_types(kFirstParam + param_cnt, + uint_type); + std::unique_ptr output_func = StartFunction( + param2output_func_id_[param_cnt], type_mgr->GetVoidType(), param_types); + + std::vector param_ids = AddParameters(*output_func, param_types); + + // Create first block + auto new_blk_ptr = MakeUnique(NewLabel(TakeNextId())); + + InstructionBuilder builder( + context(), &*new_blk_ptr, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + // Gen test if debug output buffer size will not be exceeded. + const uint32_t first_param_offset = kInstCommonOutInstructionIdx + 1; + const uint32_t obuf_record_sz = first_param_offset + param_cnt; + const uint32_t buf_id = GetOutputBufferId(); + const uint32_t buf_uint_ptr_id = GetOutputBufferPtrId(); + Instruction* obuf_curr_sz_ac_inst = builder.AddAccessChain( + buf_uint_ptr_id, buf_id, + {builder.GetUintConstantId(kDebugOutputSizeOffset)}); + // Fetch the current debug buffer written size atomically, adding the + // size of the record to be written. + uint32_t obuf_record_sz_id = builder.GetUintConstantId(obuf_record_sz); + uint32_t mask_none_id = + builder.GetUintConstantId(uint32_t(spv::MemoryAccessMask::MaskNone)); + uint32_t scope_invok_id = + builder.GetUintConstantId(uint32_t(spv::Scope::Invocation)); + Instruction* obuf_curr_sz_inst = builder.AddQuadOp( + GetUintId(), spv::Op::OpAtomicIAdd, obuf_curr_sz_ac_inst->result_id(), + scope_invok_id, mask_none_id, obuf_record_sz_id); + uint32_t obuf_curr_sz_id = obuf_curr_sz_inst->result_id(); + // Compute new written size + Instruction* obuf_new_sz_inst = + builder.AddIAdd(GetUintId(), obuf_curr_sz_id, + builder.GetUintConstantId(obuf_record_sz)); + // Fetch the data bound + Instruction* obuf_bnd_inst = + builder.AddIdLiteralOp(GetUintId(), spv::Op::OpArrayLength, + GetOutputBufferId(), kDebugOutputDataOffset); + // Test that new written size is less than or equal to debug output + // data bound + Instruction* obuf_safe_inst = builder.AddBinaryOp( + GetBoolId(), spv::Op::OpULessThanEqual, obuf_new_sz_inst->result_id(), + obuf_bnd_inst->result_id()); + uint32_t merge_blk_id = TakeNextId(); + uint32_t write_blk_id = TakeNextId(); + std::unique_ptr merge_label(NewLabel(merge_blk_id)); + std::unique_ptr write_label(NewLabel(write_blk_id)); + (void)builder.AddConditionalBranch( + obuf_safe_inst->result_id(), write_blk_id, merge_blk_id, merge_blk_id, + uint32_t(spv::SelectionControlMask::MaskNone)); + // Close safety test block and gen write block + output_func->AddBasicBlock(std::move(new_blk_ptr)); + new_blk_ptr = MakeUnique(std::move(write_label)); + builder.SetInsertPoint(&*new_blk_ptr); + // Generate common and stage-specific debug record members + GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutSize, + builder.GetUintConstantId(obuf_record_sz), + &builder); + // Store Shader Id + GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutShaderId, + param_ids[kShaderId], &builder); + // Store Instruction Idx + GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutInstructionIdx, + param_ids[kInstructionIndex], &builder); + // Gen writes of validation specific data + for (uint32_t i = 0; i < param_cnt; ++i) { + GenDebugOutputFieldCode(obuf_curr_sz_id, first_param_offset + i, + param_ids[kFirstParam + i], &builder); + } + // Close write block and gen merge block + (void)builder.AddBranch(merge_blk_id); + output_func->AddBasicBlock(std::move(new_blk_ptr)); + new_blk_ptr = MakeUnique(std::move(merge_label)); + builder.SetInsertPoint(&*new_blk_ptr); + // Close merge block and function and add function to module + (void)builder.AddNullaryOp(0, spv::Op::OpReturn); + + output_func->AddBasicBlock(std::move(new_blk_ptr)); + output_func->SetFunctionEnd(EndFunction()); + context()->AddFunction(std::move(output_func)); + + std::string name("stream_write_"); + name += std::to_string(param_cnt); + + context()->AddDebug2Inst( + NewGlobalName(param2output_func_id_[param_cnt], name)); + } + return param2output_func_id_[param_cnt]; +} + +void InstDebugPrintfPass::GenDebugStreamWrite( + uint32_t shader_id, uint32_t instruction_idx_id, + const std::vector& validation_ids, InstructionBuilder* builder) { + // Call debug output function. Pass func_idx, instruction_idx and + // validation ids as args. + uint32_t val_id_cnt = static_cast(validation_ids.size()); + std::vector args = {shader_id, instruction_idx_id}; + (void)args.insert(args.end(), validation_ids.begin(), validation_ids.end()); + (void)builder->AddFunctionCall(GetVoidId(), + GetStreamWriteFunctionId(val_id_cnt), args); +} + +std::unique_ptr InstDebugPrintfPass::NewGlobalName( + uint32_t id, const std::string& name_str) { + std::string prefixed_name{"inst_printf_"}; + prefixed_name += name_str; + return NewName(id, prefixed_name); +} + +std::unique_ptr InstDebugPrintfPass::NewMemberName( + uint32_t id, uint32_t member_index, const std::string& name_str) { + return MakeUnique( + context(), spv::Op::OpMemberName, 0, 0, + std::initializer_list{ + {SPV_OPERAND_TYPE_ID, {id}}, + {SPV_OPERAND_TYPE_LITERAL_INTEGER, {member_index}}, + {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}}); +} + void InstDebugPrintfPass::InitializeInstDebugPrintf() { // Initialize base class InitializeInstrument(); + output_buffer_id_ = 0; + output_buffer_ptr_id_ = 0; } Pass::Status InstDebugPrintfPass::ProcessImpl() { // Perform printf instrumentation on each entry point function in module InstProcessFunction pfn = [this](BasicBlock::iterator ref_inst_itr, - UptrVectorIterator ref_block_itr, uint32_t stage_idx, + UptrVectorIterator ref_block_itr, + [[maybe_unused]] uint32_t stage_idx, std::vector>* new_blocks) { - return GenDebugPrintfCode(ref_inst_itr, ref_block_itr, stage_idx, - new_blocks); + return GenDebugPrintfCode(ref_inst_itr, ref_block_itr, new_blocks); }; (void)InstProcessEntryPointCallTree(pfn); // Remove DebugPrintf OpExtInstImport instruction diff --git a/source/opt/inst_debug_printf_pass.h b/source/opt/inst_debug_printf_pass.h index 70b0a72bd7..5688d38410 100644 --- a/source/opt/inst_debug_printf_pass.h +++ b/source/opt/inst_debug_printf_pass.h @@ -28,10 +28,10 @@ namespace opt { class InstDebugPrintfPass : public InstrumentPass { public: // For test harness only - InstDebugPrintfPass() : InstrumentPass(7, 23, kInstValidationIdDebugPrintf) {} + InstDebugPrintfPass() : InstrumentPass(7, 23, false, false) {} // For all other interfaces InstDebugPrintfPass(uint32_t desc_set, uint32_t shader_id) - : InstrumentPass(desc_set, shader_id, kInstValidationIdDebugPrintf) {} + : InstrumentPass(desc_set, shader_id, false, false) {} ~InstDebugPrintfPass() override = default; @@ -41,12 +41,92 @@ class InstDebugPrintfPass : public InstrumentPass { const char* name() const override { return "inst-printf-pass"; } private: + // Gen code into |builder| to write |field_value_id| into debug output + // buffer at |base_offset_id| + |field_offset|. + void GenDebugOutputFieldCode(uint32_t base_offset_id, uint32_t field_offset, + uint32_t field_value_id, + InstructionBuilder* builder); + + // Generate instructions in |builder| which will atomically fetch and + // increment the size of the debug output buffer stream of the current + // validation and write a record to the end of the stream, if enough space + // in the buffer remains. The record will contain the index of the function + // and instruction within that function |func_idx, instruction_idx| which + // generated the record. Finally, the record will contain validation-specific + // data contained in |validation_ids| which will identify the validation + // error as well as the values involved in the error. + // + // The output buffer binding written to by the code generated by the function + // is determined by the validation id specified when each specific + // instrumentation pass is created. + // + // The output buffer is a sequence of 32-bit values with the following + // format (where all elements are unsigned 32-bit unless otherwise noted): + // + // Size + // Record0 + // Record1 + // Record2 + // ... + // + // Size is the number of 32-bit values that have been written or + // attempted to be written to the output buffer, excluding the Size. It is + // initialized to 0. If the size of attempts to write the buffer exceeds + // the actual size of the buffer, it is possible that this field can exceed + // the actual size of the buffer. + // + // Each Record* is a variable-length sequence of 32-bit values with the + // following format defined using static const offsets in the .cpp file: + // + // Record Size + // Shader ID + // Instruction Index + // ... + // Validation Error Code + // Validation-specific Word 0 + // Validation-specific Word 1 + // Validation-specific Word 2 + // ... + // + // Each record consists of two subsections: members common across all + // validation and members specific to a + // validation. + // + // The Record Size is the number of 32-bit words in the record, including + // the Record Size word. + // + // Shader ID is a value that identifies which shader has generated the + // validation error. It is passed when the instrumentation pass is created. + // + // The Instruction Index is the position of the instruction within the + // SPIR-V file which is in error. + // + // The Validation Error Code specifies the exact error which has occurred. + // These are enumerated with the kInstError* static consts. This allows + // multiple validation layers to use the same, single output buffer. + // + // The Validation-specific Words are a validation-specific number of 32-bit + // words which give further information on the validation error that + // occurred. These are documented further in each file containing the + // validation-specific class which derives from this base class. + // + // Because the code that is generated checks against the size of the buffer + // before writing, the size of the debug out buffer can be used by the + // validation layer to control the number of error records that are written. + void GenDebugStreamWrite(uint32_t shader_id, uint32_t instruction_idx_id, + const std::vector& validation_ids, + InstructionBuilder* builder); + + // Return id for output function. Define if it doesn't exist with + // |val_spec_param_cnt| validation-specific uint32 parameters. + uint32_t GetStreamWriteFunctionId(uint32_t val_spec_param_cnt); + // Generate instructions for OpDebugPrintf. // // If |ref_inst_itr| is an OpDebugPrintf, return in |new_blocks| the result // of replacing it with buffer write instructions within its block at // |ref_block_itr|. The instructions write a record to the printf - // output buffer stream including |function_idx, instruction_idx, stage_idx| + // output buffer stream including |function_idx, instruction_idx| // and removes the OpDebugPrintf. The block at |ref_block_itr| can just be // replaced with the block in |new_blocks|. Besides the buffer writes, this // block will comprise all instructions preceding and following @@ -64,7 +144,6 @@ class InstDebugPrintfPass : public InstrumentPass { // DebugPrintf. void GenDebugPrintfCode(BasicBlock::iterator ref_inst_itr, UptrVectorIterator ref_block_itr, - uint32_t stage_idx, std::vector>* new_blocks); // Generate a sequence of uint32 instructions in |builder| (if necessary) @@ -77,16 +156,40 @@ class InstDebugPrintfPass : public InstrumentPass { // Generate instructions to write a record containing the operands of // |printf_inst| arguments to printf buffer, adding new code to the end of // the last block in |new_blocks|. Kill OpDebugPrintf instruction. - void GenOutputCode(Instruction* printf_inst, uint32_t stage_idx, + void GenOutputCode(Instruction* printf_inst, std::vector>* new_blocks); + // Set the name for a function or global variable, names will be + // prefixed to identify which instrumentation pass generated them. + std::unique_ptr NewGlobalName(uint32_t id, + const std::string& name_str); + + // Set the name for a structure member + std::unique_ptr NewMemberName(uint32_t id, uint32_t member_index, + const std::string& name_str); + + // Return id for debug output buffer + uint32_t GetOutputBufferId(); + + // Return id for buffer uint type + uint32_t GetOutputBufferPtrId(); + + // Return binding for output buffer for current validation. + uint32_t GetOutputBufferBinding(); + // Initialize state for instrumenting bindless checking void InitializeInstDebugPrintf(); // Apply GenDebugPrintfCode to every instruction in module. Pass::Status ProcessImpl(); - uint32_t ext_inst_printf_id_; + uint32_t ext_inst_printf_id_{0}; + + // id for output buffer variable + uint32_t output_buffer_id_{0}; + + // ptr type id for output buffer element + uint32_t output_buffer_ptr_id_{0}; }; } // namespace opt diff --git a/source/opt/instrument_pass.cpp b/source/opt/instrument_pass.cpp index bd01ee64f5..b6845a5997 100644 --- a/source/opt/instrument_pass.cpp +++ b/source/opt/instrument_pass.cpp @@ -131,38 +131,6 @@ std::unique_ptr InstrumentPass::NewName( {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}}); } -std::unique_ptr InstrumentPass::NewGlobalName( - uint32_t id, const std::string& name_str) { - std::string prefixed_name; - switch (validation_id_) { - case kInstValidationIdBindless: - prefixed_name = "inst_bindless_"; - break; - case kInstValidationIdBuffAddr: - prefixed_name = "inst_buff_addr_"; - break; - case kInstValidationIdDebugPrintf: - prefixed_name = "inst_printf_"; - break; - default: - assert(false); // add new instrumentation pass here - prefixed_name = "inst_pass_"; - break; - } - prefixed_name += name_str; - return NewName(id, prefixed_name); -} - -std::unique_ptr InstrumentPass::NewMemberName( - uint32_t id, uint32_t member_index, const std::string& name_str) { - return MakeUnique( - context(), spv::Op::OpMemberName, 0, 0, - std::initializer_list{ - {SPV_OPERAND_TYPE_ID, {id}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, {member_index}}, - {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}}); -} - uint32_t InstrumentPass::Gen32BitCvtCode(uint32_t val_id, InstructionBuilder* builder) { // Convert integer value to 32-bit if necessary @@ -195,24 +163,6 @@ uint32_t InstrumentPass::GenUintCastCode(uint32_t val_id, ->result_id(); } -void InstrumentPass::GenDebugOutputFieldCode(uint32_t base_offset_id, - uint32_t field_offset, - uint32_t field_value_id, - InstructionBuilder* builder) { - // Cast value to 32-bit unsigned if necessary - uint32_t val_id = GenUintCastCode(field_value_id, builder); - // Store value - Instruction* data_idx_inst = builder->AddIAdd( - GetUintId(), base_offset_id, builder->GetUintConstantId(field_offset)); - uint32_t buf_id = GetOutputBufferId(); - uint32_t buf_uint_ptr_id = GetOutputBufferPtrId(); - Instruction* achain_inst = builder->AddAccessChain( - buf_uint_ptr_id, buf_id, - {builder->GetUintConstantId(kDebugOutputDataOffset), - data_idx_inst->result_id()}); - (void)builder->AddStore(achain_inst->result_id(), val_id); -} - uint32_t InstrumentPass::GenVarLoad(uint32_t var_id, InstructionBuilder* builder) { Instruction* var_inst = get_def_use_mgr()->GetDef(var_id); @@ -263,14 +213,14 @@ uint32_t InstrumentPass::GenStageInfo(uint32_t stage_idx, load_id = GenVarLoad( context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::InvocationId)), builder); - ids[2] = load_id; + ids[2] = GenUintCastCode(load_id, builder); } break; case spv::ExecutionModel::TessellationControl: { // Load and store InvocationId and PrimitiveId uint32_t load_id = GenVarLoad( context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::InvocationId)), builder); - ids[1] = load_id; + ids[1] = GenUintCastCode(load_id, builder); load_id = GenVarLoad( context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)), builder); @@ -329,18 +279,6 @@ uint32_t InstrumentPass::GenStageInfo(uint32_t stage_idx, return builder->AddCompositeConstruct(GetVec4UintId(), ids)->result_id(); } -void InstrumentPass::GenDebugStreamWrite( - uint32_t shader_id, uint32_t instruction_idx_id, uint32_t stage_info_id, - const std::vector& validation_ids, InstructionBuilder* builder) { - // Call debug output function. Pass func_idx, instruction_idx and - // validation ids as args. - uint32_t val_id_cnt = static_cast(validation_ids.size()); - std::vector args = {shader_id, instruction_idx_id, stage_info_id}; - (void)args.insert(args.end(), validation_ids.begin(), validation_ids.end()); - (void)builder->AddFunctionCall(GetVoidId(), - GetStreamWriteFunctionId(val_id_cnt), args); -} - bool InstrumentPass::AllConstant(const std::vector& ids) { for (auto& id : ids) { Instruction* id_inst = context()->get_def_use_mgr()->GetDef(id); @@ -349,14 +287,6 @@ bool InstrumentPass::AllConstant(const std::vector& ids) { return true; } -uint32_t InstrumentPass::GenDebugDirectRead( - const std::vector& offset_ids, InstructionBuilder* builder) { - // Call debug input function. Pass func_idx and offset ids as args. - const uint32_t off_id_cnt = static_cast(offset_ids.size()); - const uint32_t input_func_id = GetDirectReadFunctionId(off_id_cnt); - return GenReadFunctionCall(GetUintId(), input_func_id, offset_ids, builder); -} - uint32_t InstrumentPass::GenReadFunctionCall( uint32_t return_id, uint32_t func_id, const std::vector& func_call_args, @@ -450,53 +380,6 @@ void InstrumentPass::UpdateSucceedingPhis( }); } -uint32_t InstrumentPass::GetOutputBufferPtrId() { - if (output_buffer_ptr_id_ == 0) { - output_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType( - GetUintId(), spv::StorageClass::StorageBuffer); - } - return output_buffer_ptr_id_; -} - -uint32_t InstrumentPass::GetInputBufferTypeId() { - return (validation_id_ == kInstValidationIdBuffAddr) ? GetUint64Id() - : GetUintId(); -} - -uint32_t InstrumentPass::GetInputBufferPtrId() { - if (input_buffer_ptr_id_ == 0) { - input_buffer_ptr_id_ = context()->get_type_mgr()->FindPointerToType( - GetInputBufferTypeId(), spv::StorageClass::StorageBuffer); - } - return input_buffer_ptr_id_; -} - -uint32_t InstrumentPass::GetOutputBufferBinding() { - switch (validation_id_) { - case kInstValidationIdBindless: - return kDebugOutputBindingStream; - case kInstValidationIdBuffAddr: - return kDebugOutputBindingStream; - case kInstValidationIdDebugPrintf: - return kDebugOutputPrintfStream; - default: - assert(false && "unexpected validation id"); - } - return 0; -} - -uint32_t InstrumentPass::GetInputBufferBinding() { - switch (validation_id_) { - case kInstValidationIdBindless: - return kDebugInputBindingBindless; - case kInstValidationIdBuffAddr: - return kDebugInputBindingBuffAddr; - default: - assert(false && "unexpected validation id"); - } - return 0; -} - analysis::Integer* InstrumentPass::GetInteger(uint32_t width, bool is_signed) { analysis::Integer i(width, is_signed); analysis::Type* type = context()->get_type_mgr()->GetRegisteredType(&i); @@ -577,110 +460,6 @@ void InstrumentPass::AddStorageBufferExt() { storage_buffer_ext_defined_ = true; } -// Return id for output buffer -uint32_t InstrumentPass::GetOutputBufferId() { - if (output_buffer_id_ == 0) { - // If not created yet, create one - analysis::DecorationManager* deco_mgr = get_decoration_mgr(); - analysis::TypeManager* type_mgr = context()->get_type_mgr(); - analysis::RuntimeArray* reg_uint_rarr_ty = GetUintRuntimeArrayType(32); - analysis::Integer* reg_uint_ty = GetInteger(32, false); - analysis::Type* reg_buf_ty = - GetStruct({reg_uint_ty, reg_uint_ty, reg_uint_rarr_ty}); - uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_buf_ty); - // By the Vulkan spec, a pre-existing struct containing a RuntimeArray - // must be a block, and will therefore be decorated with Block. Therefore - // the undecorated type returned here will not be pre-existing and can - // safely be decorated. Since this type is now decorated, it is out of - // sync with the TypeManager and therefore the TypeManager must be - // invalidated after this pass. - assert(context()->get_def_use_mgr()->NumUses(obufTyId) == 0 && - "used struct type returned"); - deco_mgr->AddDecoration(obufTyId, uint32_t(spv::Decoration::Block)); - deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputFlagsOffset, - uint32_t(spv::Decoration::Offset), 0); - deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputSizeOffset, - uint32_t(spv::Decoration::Offset), 4); - deco_mgr->AddMemberDecoration(obufTyId, kDebugOutputDataOffset, - uint32_t(spv::Decoration::Offset), 8); - uint32_t obufTyPtrId_ = - type_mgr->FindPointerToType(obufTyId, spv::StorageClass::StorageBuffer); - output_buffer_id_ = TakeNextId(); - std::unique_ptr newVarOp(new Instruction( - context(), spv::Op::OpVariable, obufTyPtrId_, output_buffer_id_, - {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, - {uint32_t(spv::StorageClass::StorageBuffer)}}})); - context()->AddGlobalValue(std::move(newVarOp)); - context()->AddDebug2Inst(NewGlobalName(obufTyId, "OutputBuffer")); - context()->AddDebug2Inst(NewMemberName(obufTyId, 0, "flags")); - context()->AddDebug2Inst(NewMemberName(obufTyId, 1, "written_count")); - context()->AddDebug2Inst(NewMemberName(obufTyId, 2, "data")); - context()->AddDebug2Inst(NewGlobalName(output_buffer_id_, "output_buffer")); - deco_mgr->AddDecorationVal( - output_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_); - deco_mgr->AddDecorationVal(output_buffer_id_, - uint32_t(spv::Decoration::Binding), - GetOutputBufferBinding()); - AddStorageBufferExt(); - if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) { - // Add the new buffer to all entry points. - for (auto& entry : get_module()->entry_points()) { - entry.AddOperand({SPV_OPERAND_TYPE_ID, {output_buffer_id_}}); - context()->AnalyzeUses(&entry); - } - } - } - return output_buffer_id_; -} - -uint32_t InstrumentPass::GetInputBufferId() { - if (input_buffer_id_ == 0) { - // If not created yet, create one - analysis::DecorationManager* deco_mgr = get_decoration_mgr(); - analysis::TypeManager* type_mgr = context()->get_type_mgr(); - uint32_t width = (validation_id_ == kInstValidationIdBuffAddr) ? 64u : 32u; - analysis::Type* reg_uint_rarr_ty = GetUintRuntimeArrayType(width); - analysis::Struct* reg_buf_ty = GetStruct({reg_uint_rarr_ty}); - uint32_t ibufTyId = type_mgr->GetTypeInstruction(reg_buf_ty); - // By the Vulkan spec, a pre-existing struct containing a RuntimeArray - // must be a block, and will therefore be decorated with Block. Therefore - // the undecorated type returned here will not be pre-existing and can - // safely be decorated. Since this type is now decorated, it is out of - // sync with the TypeManager and therefore the TypeManager must be - // invalidated after this pass. - assert(context()->get_def_use_mgr()->NumUses(ibufTyId) == 0 && - "used struct type returned"); - deco_mgr->AddDecoration(ibufTyId, uint32_t(spv::Decoration::Block)); - deco_mgr->AddMemberDecoration(ibufTyId, 0, - uint32_t(spv::Decoration::Offset), 0); - uint32_t ibufTyPtrId_ = - type_mgr->FindPointerToType(ibufTyId, spv::StorageClass::StorageBuffer); - input_buffer_id_ = TakeNextId(); - std::unique_ptr newVarOp(new Instruction( - context(), spv::Op::OpVariable, ibufTyPtrId_, input_buffer_id_, - {{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, - {uint32_t(spv::StorageClass::StorageBuffer)}}})); - context()->AddGlobalValue(std::move(newVarOp)); - context()->AddDebug2Inst(NewGlobalName(ibufTyId, "InputBuffer")); - context()->AddDebug2Inst(NewMemberName(ibufTyId, 0, "data")); - context()->AddDebug2Inst(NewGlobalName(input_buffer_id_, "input_buffer")); - deco_mgr->AddDecorationVal( - input_buffer_id_, uint32_t(spv::Decoration::DescriptorSet), desc_set_); - deco_mgr->AddDecorationVal(input_buffer_id_, - uint32_t(spv::Decoration::Binding), - GetInputBufferBinding()); - AddStorageBufferExt(); - if (get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4)) { - // Add the new buffer to all entry points. - for (auto& entry : get_module()->entry_points()) { - entry.AddOperand({SPV_OPERAND_TYPE_ID, {input_buffer_id_}}); - context()->AnalyzeUses(&entry); - } - } - } - return input_buffer_id_; -} - uint32_t InstrumentPass::GetFloatId() { if (float_id_ == 0) { analysis::TypeManager* type_mgr = context()->get_type_mgr(); @@ -773,181 +552,6 @@ uint32_t InstrumentPass::GetVoidId() { return void_id_; } -uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t param_cnt) { - enum { - kShaderId = 0, - kInstructionIndex = 1, - kStageInfo = 2, - kFirstParam = 3, - }; - // Total param count is common params plus validation-specific - // params - if (param2output_func_id_[param_cnt] == 0) { - // Create function - param2output_func_id_[param_cnt] = TakeNextId(); - analysis::TypeManager* type_mgr = context()->get_type_mgr(); - - const analysis::Type* uint_type = GetInteger(32, false); - const analysis::Vector v4uint(uint_type, 4); - const analysis::Type* v4uint_type = type_mgr->GetRegisteredType(&v4uint); - - std::vector param_types(kFirstParam + param_cnt, - uint_type); - param_types[kStageInfo] = v4uint_type; - std::unique_ptr output_func = StartFunction( - param2output_func_id_[param_cnt], type_mgr->GetVoidType(), param_types); - - std::vector param_ids = AddParameters(*output_func, param_types); - - // Create first block - auto new_blk_ptr = MakeUnique(NewLabel(TakeNextId())); - - InstructionBuilder builder( - context(), &*new_blk_ptr, - IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); - // Gen test if debug output buffer size will not be exceeded. - const uint32_t val_spec_offset = kInstStageOutCnt; - const uint32_t obuf_record_sz = val_spec_offset + param_cnt; - const uint32_t buf_id = GetOutputBufferId(); - const uint32_t buf_uint_ptr_id = GetOutputBufferPtrId(); - Instruction* obuf_curr_sz_ac_inst = builder.AddAccessChain( - buf_uint_ptr_id, buf_id, - {builder.GetUintConstantId(kDebugOutputSizeOffset)}); - // Fetch the current debug buffer written size atomically, adding the - // size of the record to be written. - uint32_t obuf_record_sz_id = builder.GetUintConstantId(obuf_record_sz); - uint32_t mask_none_id = - builder.GetUintConstantId(uint32_t(spv::MemoryAccessMask::MaskNone)); - uint32_t scope_invok_id = - builder.GetUintConstantId(uint32_t(spv::Scope::Invocation)); - Instruction* obuf_curr_sz_inst = builder.AddQuadOp( - GetUintId(), spv::Op::OpAtomicIAdd, obuf_curr_sz_ac_inst->result_id(), - scope_invok_id, mask_none_id, obuf_record_sz_id); - uint32_t obuf_curr_sz_id = obuf_curr_sz_inst->result_id(); - // Compute new written size - Instruction* obuf_new_sz_inst = - builder.AddIAdd(GetUintId(), obuf_curr_sz_id, - builder.GetUintConstantId(obuf_record_sz)); - // Fetch the data bound - Instruction* obuf_bnd_inst = - builder.AddIdLiteralOp(GetUintId(), spv::Op::OpArrayLength, - GetOutputBufferId(), kDebugOutputDataOffset); - // Test that new written size is less than or equal to debug output - // data bound - Instruction* obuf_safe_inst = builder.AddBinaryOp( - GetBoolId(), spv::Op::OpULessThanEqual, obuf_new_sz_inst->result_id(), - obuf_bnd_inst->result_id()); - uint32_t merge_blk_id = TakeNextId(); - uint32_t write_blk_id = TakeNextId(); - std::unique_ptr merge_label(NewLabel(merge_blk_id)); - std::unique_ptr write_label(NewLabel(write_blk_id)); - (void)builder.AddConditionalBranch( - obuf_safe_inst->result_id(), write_blk_id, merge_blk_id, merge_blk_id, - uint32_t(spv::SelectionControlMask::MaskNone)); - // Close safety test block and gen write block - output_func->AddBasicBlock(std::move(new_blk_ptr)); - new_blk_ptr = MakeUnique(std::move(write_label)); - builder.SetInsertPoint(&*new_blk_ptr); - // Generate common and stage-specific debug record members - GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutSize, - builder.GetUintConstantId(obuf_record_sz), - &builder); - // Store Shader Id - GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutShaderId, - param_ids[kShaderId], &builder); - // Store Instruction Idx - GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutInstructionIdx, - param_ids[kInstructionIndex], &builder); - // Store stage info. Stage Idx + 3 words of stage-specific data. - for (uint32_t i = 0; i < 4; ++i) { - Instruction* field = - builder.AddCompositeExtract(GetUintId(), param_ids[kStageInfo], {i}); - GenDebugOutputFieldCode(obuf_curr_sz_id, kInstCommonOutStageIdx + i, - field->result_id(), &builder); - } - // Gen writes of validation specific data - for (uint32_t i = 0; i < param_cnt; ++i) { - GenDebugOutputFieldCode(obuf_curr_sz_id, val_spec_offset + i, - param_ids[kFirstParam + i], &builder); - } - // Close write block and gen merge block - (void)builder.AddBranch(merge_blk_id); - output_func->AddBasicBlock(std::move(new_blk_ptr)); - new_blk_ptr = MakeUnique(std::move(merge_label)); - builder.SetInsertPoint(&*new_blk_ptr); - // Close merge block and function and add function to module - (void)builder.AddNullaryOp(0, spv::Op::OpReturn); - - output_func->AddBasicBlock(std::move(new_blk_ptr)); - output_func->SetFunctionEnd(EndFunction()); - context()->AddFunction(std::move(output_func)); - - std::string name("stream_write_"); - name += std::to_string(param_cnt); - - context()->AddDebug2Inst( - NewGlobalName(param2output_func_id_[param_cnt], name)); - } - return param2output_func_id_[param_cnt]; -} - -uint32_t InstrumentPass::GetDirectReadFunctionId(uint32_t param_cnt) { - uint32_t func_id = param2input_func_id_[param_cnt]; - if (func_id != 0) return func_id; - // Create input function for param_cnt. - func_id = TakeNextId(); - analysis::Integer* uint_type = GetInteger(32, false); - std::vector param_types(param_cnt, uint_type); - - std::unique_ptr input_func = - StartFunction(func_id, uint_type, param_types); - std::vector param_ids = AddParameters(*input_func, param_types); - - // Create block - auto new_blk_ptr = MakeUnique(NewLabel(TakeNextId())); - InstructionBuilder builder( - context(), &*new_blk_ptr, - IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); - // For each offset parameter, generate new offset with parameter, adding last - // loaded value if it exists, and load value from input buffer at new offset. - // Return last loaded value. - uint32_t ibuf_type_id = GetInputBufferTypeId(); - uint32_t buf_id = GetInputBufferId(); - uint32_t buf_ptr_id = GetInputBufferPtrId(); - uint32_t last_value_id = 0; - for (uint32_t p = 0; p < param_cnt; ++p) { - uint32_t offset_id; - if (p == 0) { - offset_id = param_ids[0]; - } else { - if (ibuf_type_id != GetUintId()) { - last_value_id = - builder.AddUnaryOp(GetUintId(), spv::Op::OpUConvert, last_value_id) - ->result_id(); - } - offset_id = builder.AddIAdd(GetUintId(), last_value_id, param_ids[p]) - ->result_id(); - } - Instruction* ac_inst = builder.AddAccessChain( - buf_ptr_id, buf_id, - {builder.GetUintConstantId(kDebugInputDataOffset), offset_id}); - last_value_id = - builder.AddLoad(ibuf_type_id, ac_inst->result_id())->result_id(); - } - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, last_value_id); - // Close block and function and add function to module - input_func->AddBasicBlock(std::move(new_blk_ptr)); - input_func->SetFunctionEnd(EndFunction()); - context()->AddFunction(std::move(input_func)); - - std::string name("direct_read_"); - name += std::to_string(param_cnt); - context()->AddDebug2Inst(NewGlobalName(func_id, name)); - - param2input_func_id_[param_cnt] = func_id; - return func_id; -} - void InstrumentPass::SplitBlock( BasicBlock::iterator inst_itr, UptrVectorIterator block_itr, std::vector>* new_blocks) { @@ -1049,52 +653,54 @@ bool InstrumentPass::InstProcessCallTreeFromRoots(InstProcessFunction& pfn, } bool InstrumentPass::InstProcessEntryPointCallTree(InstProcessFunction& pfn) { - // Make sure all entry points have the same execution model. Do not - // instrument if they do not. - // TODO(greg-lunarg): Handle mixed stages. Technically, a shader module - // can contain entry points with different execution models, although - // such modules will likely be rare as GLSL and HLSL are geared toward - // one model per module. In such cases we will need - // to clone any functions which are in the call trees of entrypoints - // with differing execution models. - spv::ExecutionModel stage = context()->GetStage(); - // Check for supported stages - if (stage != spv::ExecutionModel::Vertex && - stage != spv::ExecutionModel::Fragment && - stage != spv::ExecutionModel::Geometry && - stage != spv::ExecutionModel::GLCompute && - stage != spv::ExecutionModel::TessellationControl && - stage != spv::ExecutionModel::TessellationEvaluation && - stage != spv::ExecutionModel::TaskNV && - stage != spv::ExecutionModel::MeshNV && - stage != spv::ExecutionModel::RayGenerationNV && - stage != spv::ExecutionModel::IntersectionNV && - stage != spv::ExecutionModel::AnyHitNV && - stage != spv::ExecutionModel::ClosestHitNV && - stage != spv::ExecutionModel::MissNV && - stage != spv::ExecutionModel::CallableNV && - stage != spv::ExecutionModel::TaskEXT && - stage != spv::ExecutionModel::MeshEXT) { - if (consumer()) { - std::string message = "Stage not supported by instrumentation"; - consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str()); + uint32_t stage_id; + if (use_stage_info_) { + // Make sure all entry points have the same execution model. Do not + // instrument if they do not. + // TODO(greg-lunarg): Handle mixed stages. Technically, a shader module + // can contain entry points with different execution models, although + // such modules will likely be rare as GLSL and HLSL are geared toward + // one model per module. In such cases we will need + // to clone any functions which are in the call trees of entrypoints + // with differing execution models. + spv::ExecutionModel stage = context()->GetStage(); + // Check for supported stages + if (stage != spv::ExecutionModel::Vertex && + stage != spv::ExecutionModel::Fragment && + stage != spv::ExecutionModel::Geometry && + stage != spv::ExecutionModel::GLCompute && + stage != spv::ExecutionModel::TessellationControl && + stage != spv::ExecutionModel::TessellationEvaluation && + stage != spv::ExecutionModel::TaskNV && + stage != spv::ExecutionModel::MeshNV && + stage != spv::ExecutionModel::RayGenerationNV && + stage != spv::ExecutionModel::IntersectionNV && + stage != spv::ExecutionModel::AnyHitNV && + stage != spv::ExecutionModel::ClosestHitNV && + stage != spv::ExecutionModel::MissNV && + stage != spv::ExecutionModel::CallableNV && + stage != spv::ExecutionModel::TaskEXT && + stage != spv::ExecutionModel::MeshEXT) { + if (consumer()) { + std::string message = "Stage not supported by instrumentation"; + consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str()); + } + return false; } - return false; + stage_id = static_cast(stage); + } else { + stage_id = 0; } // Add together the roots of all entry points std::queue roots; for (auto& e : get_module()->entry_points()) { roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx)); } - bool modified = InstProcessCallTreeFromRoots(pfn, &roots, uint32_t(stage)); + bool modified = InstProcessCallTreeFromRoots(pfn, &roots, stage_id); return modified; } void InstrumentPass::InitializeInstrument() { - output_buffer_id_ = 0; - output_buffer_ptr_id_ = 0; - input_buffer_ptr_id_ = 0; - input_buffer_id_ = 0; float_id_ = 0; v4float_id_ = 0; uint_id_ = 0; diff --git a/source/opt/instrument_pass.h b/source/opt/instrument_pass.h index 092b361dee..e4408c93eb 100644 --- a/source/opt/instrument_pass.h +++ b/source/opt/instrument_pass.h @@ -55,14 +55,6 @@ namespace spvtools { namespace opt { -namespace { -// Validation Ids -// These are used to identify the general validation being done and map to -// its output buffers. -constexpr uint32_t kInstValidationIdBindless = 0; -constexpr uint32_t kInstValidationIdBuffAddr = 1; -constexpr uint32_t kInstValidationIdDebugPrintf = 2; -} // namespace class InstrumentPass : public Pass { using cbb_ptr = const BasicBlock*; @@ -85,13 +77,13 @@ class InstrumentPass : public Pass { // set |desc_set| for debug input and output buffers and writes |shader_id| // into debug output records. |opt_direct_reads| indicates that the pass // will see direct input buffer reads and should prepare to optimize them. - InstrumentPass(uint32_t desc_set, uint32_t shader_id, uint32_t validation_id, - bool opt_direct_reads = false) + InstrumentPass(uint32_t desc_set, uint32_t shader_id, bool opt_direct_reads, + bool use_stage_info) : Pass(), desc_set_(desc_set), shader_id_(shader_id), - validation_id_(validation_id), - opt_direct_reads_(opt_direct_reads) {} + opt_direct_reads_(opt_direct_reads), + use_stage_info_(use_stage_info) {} // Initialize state for instrumentation of module. void InitializeInstrument(); @@ -113,108 +105,9 @@ class InstrumentPass : public Pass { void MovePostludeCode(UptrVectorIterator ref_block_itr, BasicBlock* new_blk_ptr); - // Generate instructions in |builder| which will atomically fetch and - // increment the size of the debug output buffer stream of the current - // validation and write a record to the end of the stream, if enough space - // in the buffer remains. The record will contain the index of the function - // and instruction within that function |func_idx, instruction_idx| which - // generated the record. It will also contain additional information to - // identify the instance of the shader, depending on the stage |stage_idx| - // of the shader. Finally, the record will contain validation-specific - // data contained in |validation_ids| which will identify the validation - // error as well as the values involved in the error. - // - // The output buffer binding written to by the code generated by the function - // is determined by the validation id specified when each specific - // instrumentation pass is created. - // - // The output buffer is a sequence of 32-bit values with the following - // format (where all elements are unsigned 32-bit unless otherwise noted): - // - // Size - // Record0 - // Record1 - // Record2 - // ... - // - // Size is the number of 32-bit values that have been written or - // attempted to be written to the output buffer, excluding the Size. It is - // initialized to 0. If the size of attempts to write the buffer exceeds - // the actual size of the buffer, it is possible that this field can exceed - // the actual size of the buffer. - // - // Each Record* is a variable-length sequence of 32-bit values with the - // following format defined using static const offsets in the .cpp file: - // - // Record Size - // Shader ID - // Instruction Index - // Stage - // Stage-specific Word 0 - // Stage-specific Word 1 - // ... - // Validation Error Code - // Validation-specific Word 0 - // Validation-specific Word 1 - // Validation-specific Word 2 - // ... - // - // Each record consists of three subsections: members common across all - // validation, members specific to the stage, and members specific to a - // validation. - // - // The Record Size is the number of 32-bit words in the record, including - // the Record Size word. - // - // Shader ID is a value that identifies which shader has generated the - // validation error. It is passed when the instrumentation pass is created. - // - // The Instruction Index is the position of the instruction within the - // SPIR-V file which is in error. - // - // The Stage is the pipeline stage which has generated the error as defined - // by the SpvExecutionModel_ enumeration. This is used to interpret the - // following Stage-specific words. - // - // The Stage-specific Words identify which invocation of the shader generated - // the error. Every stage will write a fixed number of words. Vertex shaders - // will write the Vertex and Instance ID. Fragment shaders will write - // FragCoord.xy. Compute shaders will write the GlobalInvocation ID. - // The tessellation eval shader will write the Primitive ID and TessCoords.uv. - // The tessellation control shader and geometry shader will write the - // Primitive ID and Invocation ID. - // - // The Validation Error Code specifies the exact error which has occurred. - // These are enumerated with the kInstError* static consts. This allows - // multiple validation layers to use the same, single output buffer. - // - // The Validation-specific Words are a validation-specific number of 32-bit - // words which give further information on the validation error that - // occurred. These are documented further in each file containing the - // validation-specific class which derives from this base class. - // - // Because the code that is generated checks against the size of the buffer - // before writing, the size of the debug out buffer can be used by the - // validation layer to control the number of error records that are written. - void GenDebugStreamWrite(uint32_t shader_id, uint32_t instruction_idx_id, - uint32_t stage_info_id, - const std::vector& validation_ids, - InstructionBuilder* builder); - // Return true if all instructions in |ids| are constants or spec constants. bool AllConstant(const std::vector& ids); - // Generate in |builder| instructions to read the unsigned integer from the - // input buffer specified by the offsets in |offset_ids|. Given offsets - // o0, o1, ... oN, and input buffer ibuf, return the id for the value: - // - // ibuf[...ibuf[ibuf[o0]+o1]...+oN] - // - // The binding and the format of the input buffer is determined by each - // specific validation, which is specified at the creation of the pass. - uint32_t GenDebugDirectRead(const std::vector& offset_ids, - InstructionBuilder* builder); - uint32_t GenReadFunctionCall(uint32_t return_id, uint32_t func_id, const std::vector& args, InstructionBuilder* builder); @@ -243,15 +136,6 @@ class InstrumentPass : public Pass { std::unique_ptr NewName(uint32_t id, const std::string& name_str); - // Set the name for a function or global variable, names will be - // prefixed to identify which instrumentation pass generated them. - std::unique_ptr NewGlobalName(uint32_t id, - const std::string& name_str); - - // Set the name for a structure member - std::unique_ptr NewMemberName(uint32_t id, uint32_t member_index, - const std::string& name_str); - // Return id for 32-bit unsigned type uint32_t GetUintId(); @@ -283,30 +167,9 @@ class InstrumentPass : public Pass { // Return pointer to type for runtime array of uint analysis::RuntimeArray* GetUintRuntimeArrayType(uint32_t width); - // Return id for buffer uint type - uint32_t GetOutputBufferPtrId(); - - // Return id for buffer uint type - uint32_t GetInputBufferTypeId(); - - // Return id for buffer uint type - uint32_t GetInputBufferPtrId(); - - // Return binding for output buffer for current validation. - uint32_t GetOutputBufferBinding(); - - // Return binding for input buffer for current validation. - uint32_t GetInputBufferBinding(); - // Add storage buffer extension if needed void AddStorageBufferExt(); - // Return id for debug output buffer - uint32_t GetOutputBufferId(); - - // Return id for debug input buffer - uint32_t GetInputBufferId(); - // Return id for 32-bit float type uint32_t GetFloatId(); @@ -322,14 +185,6 @@ class InstrumentPass : public Pass { // Return id for v3uint type uint32_t GetVec3UintId(); - // Return id for output function. Define if it doesn't exist with - // |val_spec_param_cnt| validation-specific uint32 parameters. - uint32_t GetStreamWriteFunctionId(uint32_t val_spec_param_cnt); - - // Return id for input function taking |param_cnt| uint32 parameters. Define - // if it doesn't exist. - uint32_t GetDirectReadFunctionId(uint32_t param_cnt); - // Split block |block_itr| into two new blocks where the second block // contains |inst_itr| and place in |new_blocks|. void SplitBlock(BasicBlock::iterator inst_itr, @@ -349,12 +204,6 @@ class InstrumentPass : public Pass { std::queue* roots, uint32_t stage_idx); - // Gen code into |builder| to write |field_value_id| into debug output - // buffer at |base_offset_id| + |field_offset|. - void GenDebugOutputFieldCode(uint32_t base_offset_id, uint32_t field_offset, - uint32_t field_value_id, - InstructionBuilder* builder); - // Generate instructions into |builder| which will load |var_id| and return // its result id. uint32_t GenVarLoad(uint32_t var_id, InstructionBuilder* builder); @@ -395,62 +244,47 @@ class InstrumentPass : public Pass { // Map from instruction's unique id to offset in original file. std::unordered_map uid2offset_; - // result id for OpConstantFalse - uint32_t validation_id_; - - // id for output buffer variable - uint32_t output_buffer_id_; - - // ptr type id for output buffer element - uint32_t output_buffer_ptr_id_; - - // ptr type id for input buffer element - uint32_t input_buffer_ptr_id_; - // id for debug output function std::unordered_map param2output_func_id_; // ids for debug input functions std::unordered_map param2input_func_id_; - // id for input buffer variable - uint32_t input_buffer_id_; - // id for 32-bit float type - uint32_t float_id_; + uint32_t float_id_{0}; // id for v4float type - uint32_t v4float_id_; + uint32_t v4float_id_{0}; // id for v4uint type - uint32_t v4uint_id_; + uint32_t v4uint_id_{0}; // id for v3uint type - uint32_t v3uint_id_; + uint32_t v3uint_id_{0}; // id for 32-bit unsigned type - uint32_t uint_id_; + uint32_t uint_id_{0}; // id for 64-bit unsigned type - uint32_t uint64_id_; + uint32_t uint64_id_{0}; // id for 8-bit unsigned type - uint32_t uint8_id_; + uint32_t uint8_id_{0}; // id for bool type - uint32_t bool_id_; + uint32_t bool_id_{0}; // id for void type - uint32_t void_id_; + uint32_t void_id_{0}; // boolean to remember storage buffer extension - bool storage_buffer_ext_defined_; + bool storage_buffer_ext_defined_{false}; // runtime array of uint type - analysis::RuntimeArray* uint64_rarr_ty_; + analysis::RuntimeArray* uint64_rarr_ty_{nullptr}; // runtime array of uint type - analysis::RuntimeArray* uint32_rarr_ty_; + analysis::RuntimeArray* uint32_rarr_ty_{nullptr}; // Pre-instrumentation same-block insts std::unordered_map same_block_pre_; @@ -475,11 +309,15 @@ class InstrumentPass : public Pass { std::unordered_map, uint32_t, vector_hash_> call2id_; // Function currently being instrumented - Function* curr_func_; + Function* curr_func_{nullptr}; // Optimize direct debug input buffer reads. Specifically, move all such // reads with constant args to first block and reuse them. - bool opt_direct_reads_; + const bool opt_direct_reads_; + + // Set true if the instrumentation needs to know the current stage. + // Note that this does not work with multi-stage modules. + const bool use_stage_info_; }; } // namespace opt diff --git a/source/opt/invocation_interlock_placement_pass.cpp b/source/opt/invocation_interlock_placement_pass.cpp new file mode 100644 index 0000000000..642e2d23a5 --- /dev/null +++ b/source/opt/invocation_interlock_placement_pass.cpp @@ -0,0 +1,493 @@ +// Copyright (c) 2023 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. + +#include "source/opt/invocation_interlock_placement_pass.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "source/enum_set.h" +#include "source/enum_string_mapping.h" +#include "source/opt/ir_context.h" +#include "source/opt/reflect.h" +#include "source/spirv_target_env.h" +#include "source/util/string_utils.h" + +namespace spvtools { +namespace opt { + +namespace { +constexpr uint32_t kEntryPointExecutionModelInIdx = 0; +constexpr uint32_t kEntryPointFunctionIdInIdx = 1; +constexpr uint32_t kFunctionCallFunctionIdInIdx = 0; +} // namespace + +bool InvocationInterlockPlacementPass::hasSingleNextBlock(uint32_t block_id, + bool reverse_cfg) { + if (reverse_cfg) { + // We are traversing forward, so check whether there is a single successor. + BasicBlock* block = cfg()->block(block_id); + + switch (block->tail()->opcode()) { + case spv::Op::OpBranchConditional: + return false; + case spv::Op::OpSwitch: + return block->tail()->NumInOperandWords() == 1; + default: + return !block->tail()->IsReturnOrAbort(); + } + } else { + // We are traversing backward, so check whether there is a single + // predecessor. + return cfg()->preds(block_id).size() == 1; + } +} + +void InvocationInterlockPlacementPass::forEachNext( + uint32_t block_id, bool reverse_cfg, std::function f) { + if (reverse_cfg) { + BasicBlock* block = cfg()->block(block_id); + + block->ForEachSuccessorLabel([f](uint32_t succ_id) { f(succ_id); }); + } else { + for (uint32_t pred_id : cfg()->preds(block_id)) { + f(pred_id); + } + } +} + +void InvocationInterlockPlacementPass::addInstructionAtBlockBoundary( + BasicBlock* block, spv::Op opcode, bool at_end) { + if (at_end) { + assert(block->begin()->opcode() != spv::Op::OpPhi && + "addInstructionAtBlockBoundary expects to be called with at_end == " + "true only if there is a single successor to block"); + // Insert a begin instruction at the end of the block. + Instruction* begin_inst = new Instruction(context(), opcode); + begin_inst->InsertAfter(&*--block->tail()); + } else { + assert(block->begin()->opcode() != spv::Op::OpPhi && + "addInstructionAtBlockBoundary expects to be called with at_end == " + "false only if there is a single predecessor to block"); + // Insert an end instruction at the beginning of the block. + Instruction* end_inst = new Instruction(context(), opcode); + end_inst->InsertBefore(&*block->begin()); + } +} + +bool InvocationInterlockPlacementPass::killDuplicateBegin(BasicBlock* block) { + bool found = false; + + return context()->KillInstructionIf( + block->begin(), block->end(), [&found](Instruction* inst) { + if (inst->opcode() == spv::Op::OpBeginInvocationInterlockEXT) { + if (found) { + return true; + } + found = true; + } + return false; + }); +} + +bool InvocationInterlockPlacementPass::killDuplicateEnd(BasicBlock* block) { + std::vector to_kill; + block->ForEachInst([&to_kill](Instruction* inst) { + if (inst->opcode() == spv::Op::OpEndInvocationInterlockEXT) { + to_kill.push_back(inst); + } + }); + + if (to_kill.size() <= 1) { + return false; + } + + to_kill.pop_back(); + + for (Instruction* inst : to_kill) { + context()->KillInst(inst); + } + + return true; +} + +void InvocationInterlockPlacementPass::recordBeginOrEndInFunction( + Function* func) { + if (extracted_functions_.count(func)) { + return; + } + + bool had_begin = false; + bool had_end = false; + + func->ForEachInst([this, &had_begin, &had_end](Instruction* inst) { + switch (inst->opcode()) { + case spv::Op::OpBeginInvocationInterlockEXT: + had_begin = true; + break; + case spv::Op::OpEndInvocationInterlockEXT: + had_end = true; + break; + case spv::Op::OpFunctionCall: { + uint32_t function_id = + inst->GetSingleWordInOperand(kFunctionCallFunctionIdInIdx); + Function* inner_func = context()->GetFunction(function_id); + recordBeginOrEndInFunction(inner_func); + ExtractionResult result = extracted_functions_[inner_func]; + had_begin = had_begin || result.had_begin; + had_end = had_end || result.had_end; + break; + } + default: + break; + } + }); + + ExtractionResult result = {had_begin, had_end}; + extracted_functions_[func] = result; +} + +bool InvocationInterlockPlacementPass:: + removeBeginAndEndInstructionsFromFunction(Function* func) { + bool modified = false; + func->ForEachInst([this, &modified](Instruction* inst) { + switch (inst->opcode()) { + case spv::Op::OpBeginInvocationInterlockEXT: + context()->KillInst(inst); + modified = true; + break; + case spv::Op::OpEndInvocationInterlockEXT: + context()->KillInst(inst); + modified = true; + break; + default: + break; + } + }); + return modified; +} + +bool InvocationInterlockPlacementPass::extractInstructionsFromCalls( + std::vector blocks) { + bool modified = false; + + for (BasicBlock* block : blocks) { + block->ForEachInst([this, &modified](Instruction* inst) { + if (inst->opcode() == spv::Op::OpFunctionCall) { + uint32_t function_id = + inst->GetSingleWordInOperand(kFunctionCallFunctionIdInIdx); + Function* func = context()->GetFunction(function_id); + ExtractionResult result = extracted_functions_[func]; + + if (result.had_begin) { + Instruction* new_inst = new Instruction( + context(), spv::Op::OpBeginInvocationInterlockEXT); + new_inst->InsertBefore(inst); + modified = true; + } + if (result.had_end) { + Instruction* new_inst = + new Instruction(context(), spv::Op::OpEndInvocationInterlockEXT); + new_inst->InsertAfter(inst); + modified = true; + } + } + }); + } + return modified; +} + +void InvocationInterlockPlacementPass::recordExistingBeginAndEndBlock( + std::vector blocks) { + for (BasicBlock* block : blocks) { + block->ForEachInst([this, block](Instruction* inst) { + switch (inst->opcode()) { + case spv::Op::OpBeginInvocationInterlockEXT: + begin_.insert(block->id()); + break; + case spv::Op::OpEndInvocationInterlockEXT: + end_.insert(block->id()); + break; + default: + break; + } + }); + } +} + +InvocationInterlockPlacementPass::BlockSet +InvocationInterlockPlacementPass::computeReachableBlocks( + BlockSet& previous_inside, const BlockSet& starting_nodes, + bool reverse_cfg) { + BlockSet inside = starting_nodes; + + std::deque worklist; + worklist.insert(worklist.begin(), starting_nodes.begin(), + starting_nodes.end()); + + while (!worklist.empty()) { + uint32_t block_id = worklist.front(); + worklist.pop_front(); + + forEachNext(block_id, reverse_cfg, + [&inside, &previous_inside, &worklist](uint32_t next_id) { + previous_inside.insert(next_id); + if (inside.insert(next_id).second) { + worklist.push_back(next_id); + } + }); + } + + return inside; +} + +bool InvocationInterlockPlacementPass::removeUnneededInstructions( + BasicBlock* block) { + bool modified = false; + if (!predecessors_after_begin_.count(block->id()) && + after_begin_.count(block->id())) { + // None of the previous blocks are in the critical section, but this block + // is. This can only happen if this block already has at least one begin + // instruction. Leave the first begin instruction, and remove any others. + modified |= killDuplicateBegin(block); + } else if (predecessors_after_begin_.count(block->id())) { + // At least one previous block is in the critical section; remove all + // begin instructions in this block. + modified |= context()->KillInstructionIf( + block->begin(), block->end(), [](Instruction* inst) { + return inst->opcode() == spv::Op::OpBeginInvocationInterlockEXT; + }); + } + + if (!successors_before_end_.count(block->id()) && + before_end_.count(block->id())) { + // Same as above + modified |= killDuplicateEnd(block); + } else if (successors_before_end_.count(block->id())) { + modified |= context()->KillInstructionIf( + block->begin(), block->end(), [](Instruction* inst) { + return inst->opcode() == spv::Op::OpEndInvocationInterlockEXT; + }); + } + return modified; +} + +BasicBlock* InvocationInterlockPlacementPass::splitEdge(BasicBlock* block, + uint32_t succ_id) { + // Create a new block to replace the critical edge. + auto new_succ_temp = MakeUnique( + MakeUnique(context(), spv::Op::OpLabel, 0, TakeNextId(), + std::initializer_list{})); + auto* new_succ = new_succ_temp.get(); + + // Insert the new block into the function. + block->GetParent()->InsertBasicBlockAfter(std::move(new_succ_temp), block); + + new_succ->AddInstruction(MakeUnique( + context(), spv::Op::OpBranch, 0, 0, + std::initializer_list{ + Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, {succ_id})})); + + assert(block->tail()->opcode() == spv::Op::OpBranchConditional || + block->tail()->opcode() == spv::Op::OpSwitch); + + // Update the first branch to successor to instead branch to + // the new successor. If there are multiple edges, we arbitrarily choose the + // first time it appears in the list. The other edges to `succ_id` will have + // to be split by another call to `splitEdge`. + block->tail()->WhileEachInId([new_succ, succ_id](uint32_t* branch_id) { + if (*branch_id == succ_id) { + *branch_id = new_succ->id(); + return false; + } + return true; + }); + + return new_succ; +} + +bool InvocationInterlockPlacementPass::placeInstructionsForEdge( + BasicBlock* block, uint32_t next_id, BlockSet& inside, + BlockSet& previous_inside, spv::Op opcode, bool reverse_cfg) { + bool modified = false; + + if (previous_inside.count(next_id) && !inside.count(block->id())) { + // This block is not in the critical section but the next has at least one + // other previous block that is, so this block should be enter it as well. + // We need to add begin or end instructions to the edge. + + modified = true; + + if (hasSingleNextBlock(block->id(), reverse_cfg)) { + // This is the only next block. + + // Additionally, because `next_id` is in `previous_inside`, we know that + // `next_id` has at least one previous block in `inside`. And because + // 'block` is not in `inside`, that means the `next_id` has to have at + // least one other previous block in `inside`. + + // This is solely for a debug assertion. It is essentially recomputing the + // value of `previous_inside` to verify that it was computed correctly + // such that the above statement is true. + bool next_has_previous_inside = false; + // By passing !reverse_cfg to forEachNext, we are actually iterating over + // the previous blocks. + forEachNext(next_id, !reverse_cfg, + [&next_has_previous_inside, inside](uint32_t previous_id) { + if (inside.count(previous_id)) { + next_has_previous_inside = true; + } + }); + assert(next_has_previous_inside && + "`previous_inside` must be the set of blocks with at least one " + "previous block in `inside`"); + + addInstructionAtBlockBoundary(block, opcode, reverse_cfg); + } else { + // This block has multiple next blocks. Split the edge and insert the + // instruction in the new next block. + BasicBlock* new_branch; + if (reverse_cfg) { + new_branch = splitEdge(block, next_id); + } else { + new_branch = splitEdge(cfg()->block(next_id), block->id()); + } + + auto inst = new Instruction(context(), opcode); + inst->InsertBefore(&*new_branch->tail()); + } + } + + return modified; +} + +bool InvocationInterlockPlacementPass::placeInstructions(BasicBlock* block) { + bool modified = false; + + block->ForEachSuccessorLabel([this, block, &modified](uint32_t succ_id) { + modified |= placeInstructionsForEdge( + block, succ_id, after_begin_, predecessors_after_begin_, + spv::Op::OpBeginInvocationInterlockEXT, /* reverse_cfg= */ true); + modified |= placeInstructionsForEdge(cfg()->block(succ_id), block->id(), + before_end_, successors_before_end_, + spv::Op::OpEndInvocationInterlockEXT, + /* reverse_cfg= */ false); + }); + + return modified; +} + +bool InvocationInterlockPlacementPass::processFragmentShaderEntry( + Function* entry_func) { + bool modified = false; + + // Save the original order of blocks in the function, so we don't iterate over + // newly-added blocks. + std::vector original_blocks; + for (auto bi = entry_func->begin(); bi != entry_func->end(); ++bi) { + original_blocks.push_back(&*bi); + } + + modified |= extractInstructionsFromCalls(original_blocks); + recordExistingBeginAndEndBlock(original_blocks); + + after_begin_ = computeReachableBlocks(predecessors_after_begin_, begin_, + /* reverse_cfg= */ true); + before_end_ = computeReachableBlocks(successors_before_end_, end_, + /* reverse_cfg= */ false); + + for (BasicBlock* block : original_blocks) { + modified |= removeUnneededInstructions(block); + modified |= placeInstructions(block); + } + return modified; +} + +bool InvocationInterlockPlacementPass::isFragmentShaderInterlockEnabled() { + if (!context()->get_feature_mgr()->HasExtension( + kSPV_EXT_fragment_shader_interlock)) { + return false; + } + + if (context()->get_feature_mgr()->HasCapability( + spv::Capability::FragmentShaderSampleInterlockEXT)) { + return true; + } + + if (context()->get_feature_mgr()->HasCapability( + spv::Capability::FragmentShaderPixelInterlockEXT)) { + return true; + } + + if (context()->get_feature_mgr()->HasCapability( + spv::Capability::FragmentShaderShadingRateInterlockEXT)) { + return true; + } + + return false; +} + +Pass::Status InvocationInterlockPlacementPass::Process() { + // Skip this pass if the necessary extension or capability is missing + if (!isFragmentShaderInterlockEnabled()) { + return Status::SuccessWithoutChange; + } + + bool modified = false; + + std::unordered_set entry_points; + for (Instruction& entry_inst : context()->module()->entry_points()) { + uint32_t entry_id = + entry_inst.GetSingleWordInOperand(kEntryPointFunctionIdInIdx); + entry_points.insert(context()->GetFunction(entry_id)); + } + + for (auto fi = context()->module()->begin(); fi != context()->module()->end(); + ++fi) { + Function* func = &*fi; + recordBeginOrEndInFunction(func); + if (!entry_points.count(func) && extracted_functions_.count(func)) { + modified |= removeBeginAndEndInstructionsFromFunction(func); + } + } + + for (Instruction& entry_inst : context()->module()->entry_points()) { + uint32_t entry_id = + entry_inst.GetSingleWordInOperand(kEntryPointFunctionIdInIdx); + Function* entry_func = context()->GetFunction(entry_id); + + auto execution_model = spv::ExecutionModel( + entry_inst.GetSingleWordInOperand(kEntryPointExecutionModelInIdx)); + + if (execution_model != spv::ExecutionModel::Fragment) { + continue; + } + + modified |= processFragmentShaderEntry(entry_func); + } + + return modified ? Pass::Status::SuccessWithChange + : Pass::Status::SuccessWithoutChange; +} + +} // namespace opt +} // namespace spvtools diff --git a/source/opt/invocation_interlock_placement_pass.h b/source/opt/invocation_interlock_placement_pass.h new file mode 100644 index 0000000000..4e85be8586 --- /dev/null +++ b/source/opt/invocation_interlock_placement_pass.h @@ -0,0 +1,158 @@ +// Copyright (c) 2023 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. + +#ifndef SOURCE_OPT_DEDUPE_INTERLOCK_INVOCATION_PASS_H_ +#define SOURCE_OPT_DEDUPE_INTERLOCK_INVOCATION_PASS_H_ + +#include +#include +#include +#include +#include +#include + +#include "source/enum_set.h" +#include "source/extensions.h" +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/opt/pass.h" +#include "source/spirv_target_env.h" + +namespace spvtools { +namespace opt { + +// This pass will ensure that an entry point will only have at most one +// OpBeginInterlockInvocationEXT and one OpEndInterlockInvocationEXT, in that +// order +class InvocationInterlockPlacementPass : public Pass { + public: + InvocationInterlockPlacementPass() {} + InvocationInterlockPlacementPass(const InvocationInterlockPlacementPass&) = + delete; + InvocationInterlockPlacementPass(InvocationInterlockPlacementPass&&) = delete; + + const char* name() const override { return "dedupe-interlock-invocation"; } + Status Process() override; + + private: + using BlockSet = std::unordered_set; + + // Specifies whether a function originally had a begin or end instruction. + struct ExtractionResult { + bool had_begin : 1; + bool had_end : 2; + }; + + // Check if a block has only a single next block, depending on the directing + // that we are traversing the CFG. If reverse_cfg is true, we are walking + // forward through the CFG, and will return if the block has only one + // successor. Otherwise, we are walking backward through the CFG, and will + // return if the block has only one predecessor. + bool hasSingleNextBlock(uint32_t block_id, bool reverse_cfg); + + // Iterate over each of a block's predecessors or successors, depending on + // direction. If reverse_cfg is true, we are walking forward through the CFG, + // and need to iterate over the successors. Otherwise, we are walking backward + // through the CFG, and need to iterate over the predecessors. + void forEachNext(uint32_t block_id, bool reverse_cfg, + std::function f); + + // Add either a begin or end instruction to the edge of the basic block. If + // at_end is true, add the instruction to the end of the block; otherwise add + // the instruction to the beginning of the basic block. + void addInstructionAtBlockBoundary(BasicBlock* block, spv::Op opcode, + bool at_end); + + // Remove every OpBeginInvocationInterlockEXT instruction in block after the + // first. Returns whether any instructions were removed. + bool killDuplicateBegin(BasicBlock* block); + // Remove every OpBeginInvocationInterlockEXT instruction in block before the + // last. Returns whether any instructions were removed. + bool killDuplicateEnd(BasicBlock* block); + + // Records whether a function will potentially execute a begin or end + // instruction. + void recordBeginOrEndInFunction(Function* func); + + // Recursively removes any begin or end instructions from func and any + // function func calls. Returns whether any instructions were removed. + bool removeBeginAndEndInstructionsFromFunction(Function* func); + + // For every function call in any of the passed blocks, move any begin or end + // instructions outside of the function call. Returns whether any extractions + // occurred. + bool extractInstructionsFromCalls(std::vector blocks); + + // Finds the sets of blocks that contain OpBeginInvocationInterlockEXT and + // OpEndInvocationInterlockEXT, storing them in the member variables begin_ + // and end_ respectively. + void recordExistingBeginAndEndBlock(std::vector blocks); + + // Compute the set of blocks including or after the barrier instruction, and + // the set of blocks with any previous blocks inside the barrier instruction. + // If reverse_cfg is true, move forward through the CFG, computing + // after_begin_ and predecessors_after_begin_computing after_begin_ and + // predecessors_after_begin_, otherwise, move backward through the CFG, + // computing before_end_ and successors_before_end_. + BlockSet computeReachableBlocks(BlockSet& in_set, + const BlockSet& starting_nodes, + bool reverse_cfg); + + // Remove unneeded begin and end instructions in block. + bool removeUnneededInstructions(BasicBlock* block); + + // Given a block which branches to multiple successors, and a specific + // successor, creates a new empty block, and update the branch instruction to + // branch to the new block instead. + BasicBlock* splitEdge(BasicBlock* block, uint32_t succ_id); + + // For the edge from block to next_id, places a begin or end instruction on + // the edge, based on the direction we are walking the CFG, specified in + // reverse_cfg. + bool placeInstructionsForEdge(BasicBlock* block, uint32_t next_id, + BlockSet& inside, BlockSet& previous_inside, + spv::Op opcode, bool reverse_cfg); + // Calls placeInstructionsForEdge for each edge in block. + bool placeInstructions(BasicBlock* block); + + // Processes a single fragment shader entry function. + bool processFragmentShaderEntry(Function* entry_func); + + // Returns whether the module has the SPV_EXT_fragment_shader_interlock + // extension and one of the FragmentShader*InterlockEXT capabilities. + bool isFragmentShaderInterlockEnabled(); + + // Maps a function to whether that function originally held a begin or end + // instruction. + std::unordered_map extracted_functions_; + + // The set of blocks which have an OpBeginInvocationInterlockEXT instruction. + BlockSet begin_; + // The set of blocks which have an OpEndInvocationInterlockEXT instruction. + BlockSet end_; + // The set of blocks which either have a begin instruction, or have a + // predecessor which has a begin instruction. + BlockSet after_begin_; + // The set of blocks which either have an end instruction, or have a successor + // which have an end instruction. + BlockSet before_end_; + // The set of blocks which have a predecessor in after_begin_. + BlockSet predecessors_after_begin_; + // The set of blocks which have a successor in before_end_. + BlockSet successors_before_end_; +}; + +} // namespace opt +} // namespace spvtools +#endif // SOURCE_OPT_DEDUPE_INTERLOCK_INVOCATION_PASS_H_ diff --git a/source/opt/ir_context.h b/source/opt/ir_context.h index 7ff411a15f..de3c410665 100644 --- a/source/opt/ir_context.h +++ b/source/opt/ir_context.h @@ -252,6 +252,8 @@ class IRContext { inline void AddType(std::unique_ptr&& t); // Appends a constant, global variable, or OpUndef instruction to this module. inline void AddGlobalValue(std::unique_ptr&& v); + // Prepends a function declaration to this module. + inline void AddFunctionDeclaration(std::unique_ptr&& f); // Appends a function to this module. inline void AddFunction(std::unique_ptr&& f); @@ -1213,6 +1215,10 @@ void IRContext::AddGlobalValue(std::unique_ptr&& v) { module()->AddGlobalValue(std::move(v)); } +void IRContext::AddFunctionDeclaration(std::unique_ptr&& f) { + module()->AddFunctionDeclaration(std::move(f)); +} + void IRContext::AddFunction(std::unique_ptr&& f) { module()->AddFunction(std::move(f)); } diff --git a/source/opt/local_access_chain_convert_pass.cpp b/source/opt/local_access_chain_convert_pass.cpp index d024af60a8..ea1bdeeb3b 100644 --- a/source/opt/local_access_chain_convert_pass.cpp +++ b/source/opt/local_access_chain_convert_pass.cpp @@ -427,7 +427,9 @@ void LocalAccessChainConvertPass::InitExtensions() { "SPV_EXT_shader_image_int64", "SPV_KHR_non_semantic_info", "SPV_KHR_uniform_group_instructions", "SPV_KHR_fragment_shader_barycentric", "SPV_KHR_vulkan_memory_model", - "SPV_NV_bindless_texture", "SPV_EXT_shader_atomic_float_add"}); + "SPV_NV_bindless_texture", "SPV_EXT_shader_atomic_float_add", + "SPV_EXT_fragment_shader_interlock", + "SPV_NV_compute_shader_derivatives"}); } bool LocalAccessChainConvertPass::AnyIndexIsOutOfBounds( diff --git a/source/opt/local_single_block_elim_pass.cpp b/source/opt/local_single_block_elim_pass.cpp index 5e524c4529..7502d0497e 100644 --- a/source/opt/local_single_block_elim_pass.cpp +++ b/source/opt/local_single_block_elim_pass.cpp @@ -278,6 +278,7 @@ void LocalSingleBlockLoadStoreElimPass::InitExtensions() { "SPV_KHR_ray_query", "SPV_EXT_fragment_invocation_density", "SPV_EXT_physical_storage_buffer", + "SPV_KHR_physical_storage_buffer", "SPV_KHR_terminate_invocation", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_integer_dot_product", @@ -287,7 +288,9 @@ void LocalSingleBlockLoadStoreElimPass::InitExtensions() { "SPV_KHR_fragment_shader_barycentric", "SPV_KHR_vulkan_memory_model", "SPV_NV_bindless_texture", - "SPV_EXT_shader_atomic_float_add"}); + "SPV_EXT_shader_atomic_float_add", + "SPV_EXT_fragment_shader_interlock", + "SPV_NV_compute_shader_derivatives"}); } } // namespace opt diff --git a/source/opt/local_single_store_elim_pass.cpp b/source/opt/local_single_store_elim_pass.cpp index fefe2ce9e0..f6fc2760e0 100644 --- a/source/opt/local_single_store_elim_pass.cpp +++ b/source/opt/local_single_store_elim_pass.cpp @@ -128,6 +128,7 @@ void LocalSingleStoreElimPass::InitExtensionAllowList() { "SPV_KHR_ray_query", "SPV_EXT_fragment_invocation_density", "SPV_EXT_physical_storage_buffer", + "SPV_KHR_physical_storage_buffer", "SPV_KHR_terminate_invocation", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_integer_dot_product", @@ -137,7 +138,9 @@ void LocalSingleStoreElimPass::InitExtensionAllowList() { "SPV_KHR_fragment_shader_barycentric", "SPV_KHR_vulkan_memory_model", "SPV_NV_bindless_texture", - "SPV_EXT_shader_atomic_float_add"}); + "SPV_EXT_shader_atomic_float_add", + "SPV_EXT_fragment_shader_interlock", + "SPV_NV_compute_shader_derivatives"}); } bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) { std::vector users; diff --git a/source/opt/log.h b/source/opt/log.h index 68051002e2..4fb66fd455 100644 --- a/source/opt/log.h +++ b/source/opt/log.h @@ -23,7 +23,7 @@ #include "spirv-tools/libspirv.hpp" // Asserts the given condition is true. Otherwise, sends a message to the -// consumer and exits the problem with failure code. Accepts the following +// consumer and exits the program with failure code. Accepts the following // formats: // // SPIRV_ASSERT(, ); @@ -36,7 +36,9 @@ #if !defined(NDEBUG) #define SPIRV_ASSERT(consumer, ...) SPIRV_ASSERT_IMPL(consumer, __VA_ARGS__) #else -#define SPIRV_ASSERT(consumer, ...) +// Adding a use to avoid errors in the release build related to unused +// consumers. +#define SPIRV_ASSERT(consumer, ...) (void)(consumer) #endif // Logs a debug message to the consumer. Accepts the following formats: @@ -49,26 +51,11 @@ #if !defined(NDEBUG) && defined(SPIRV_LOG_DEBUG) #define SPIRV_DEBUG(consumer, ...) SPIRV_DEBUG_IMPL(consumer, __VA_ARGS__) #else -#define SPIRV_DEBUG(consumer, ...) +// Adding a use to avoid errors in the release build related to unused +// consumers. +#define SPIRV_DEBUG(consumer, ...) (void)(consumer) #endif -// Logs an error message to the consumer saying the given feature is -// unimplemented. -#define SPIRV_UNIMPLEMENTED(consumer, feature) \ - do { \ - spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ - {static_cast(__LINE__), 0, 0}, \ - "unimplemented: " feature); \ - } while (0) - -// Logs an error message to the consumer saying the code location -// should be unreachable. -#define SPIRV_UNREACHABLE(consumer) \ - do { \ - spvtools::Log(consumer, SPV_MSG_INTERNAL_ERROR, __FILE__, \ - {static_cast(__LINE__), 0, 0}, "unreachable"); \ - } while (0) - // Helper macros for concatenating arguments. #define SPIRV_CONCATENATE(a, b) SPIRV_CONCATENATE_(a, b) #define SPIRV_CONCATENATE_(a, b) a##b diff --git a/source/opt/module.h b/source/opt/module.h index b9d69129f6..98c16dc4c9 100644 --- a/source/opt/module.h +++ b/source/opt/module.h @@ -120,6 +120,9 @@ class Module { // Appends a constant, global variable, or OpUndef instruction to this module. inline void AddGlobalValue(std::unique_ptr v); + // Prepends a function declaration to this module. + inline void AddFunctionDeclaration(std::unique_ptr f); + // Appends a function to this module. inline void AddFunction(std::unique_ptr f); @@ -380,6 +383,11 @@ inline void Module::AddGlobalValue(std::unique_ptr v) { types_values_.push_back(std::move(v)); } +inline void Module::AddFunctionDeclaration(std::unique_ptr f) { + // function declarations must come before function definitions. + functions_.emplace(functions_.begin(), std::move(f)); +} + inline void Module::AddFunction(std::unique_ptr f) { functions_.emplace_back(std::move(f)); } diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index 6301be6ca1..d865cf1d47 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -15,6 +15,7 @@ #include "spirv-tools/optimizer.hpp" #include +#include #include #include #include @@ -157,7 +158,8 @@ Optimizer& Optimizer::RegisterLegalizationPasses(bool preserve_interface) { .RegisterPass(CreateDeadInsertElimPass()) .RegisterPass(CreateReduceLoadSizePass()) .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) - .RegisterPass(CreateInterpolateFixupPass()); + .RegisterPass(CreateInterpolateFixupPass()) + .RegisterPass(CreateInvocationInterlockPlacementPass()); } Optimizer& Optimizer::RegisterLegalizationPasses() { @@ -433,19 +435,22 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { pass_name == "inst-desc-idx-check" || pass_name == "inst-buff-oob-check") { // preserve legacy names - RegisterPass(CreateInstBindlessCheckPass(7, 23)); + RegisterPass(CreateInstBindlessCheckPass(23)); RegisterPass(CreateSimplificationPass()); RegisterPass(CreateDeadBranchElimPass()); RegisterPass(CreateBlockMergePass()); - RegisterPass(CreateAggressiveDCEPass(true)); } else if (pass_name == "inst-buff-addr-check") { - RegisterPass(CreateInstBuffAddrCheckPass(7, 23)); - RegisterPass(CreateAggressiveDCEPass(true)); + RegisterPass(CreateInstBuffAddrCheckPass(23)); } else if (pass_name == "convert-relaxed-to-half") { RegisterPass(CreateConvertRelaxedToHalfPass()); } else if (pass_name == "relax-float-ops") { RegisterPass(CreateRelaxFloatOpsPass()); } else if (pass_name == "inst-debug-printf") { + // This private option is not for user consumption. + // It is here to assist in debugging and fixing the debug printf + // instrumentation pass. + // For users who wish to utilize debug printf, see the white paper at + // https://www.lunarg.com/wp-content/uploads/2021/08/Using-Debug-Printf-02August2021.pdf RegisterPass(CreateInstDebugPrintfPass(7, 23)); } else if (pass_name == "simplify-instructions") { RegisterPass(CreateSimplificationPass()); @@ -549,6 +554,39 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { pass_args.c_str()); return false; } + } else if (pass_name == "switch-descriptorset") { + if (pass_args.size() == 0) { + Error(consumer(), nullptr, {}, + "--switch-descriptorset requires a from:to argument."); + return false; + } + uint32_t from_set = 0, to_set = 0; + const char* start = pass_args.data(); + const char* end = pass_args.data() + pass_args.size(); + + auto result = std::from_chars(start, end, from_set); + if (result.ec != std::errc()) { + Errorf(consumer(), nullptr, {}, + "Invalid argument for --switch-descriptorset: %s", + pass_args.c_str()); + return false; + } + start = result.ptr; + if (start[0] != ':') { + Errorf(consumer(), nullptr, {}, + "Invalid argument for --switch-descriptorset: %s", + pass_args.c_str()); + return false; + } + start++; + result = std::from_chars(start, end, to_set); + if (result.ec != std::errc() || result.ptr != end) { + Errorf(consumer(), nullptr, {}, + "Invalid argument for --switch-descriptorset: %s", + pass_args.c_str()); + return false; + } + RegisterPass(CreateSwitchDescriptorSetPass(from_set, to_set)); } else { Errorf(consumer(), nullptr, {}, "Unknown flag '--%s'. Use --help for a list of valid flags", @@ -946,10 +984,9 @@ Optimizer::PassToken CreateUpgradeMemoryModelPass() { MakeUnique()); } -Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t desc_set, - uint32_t shader_id) { +Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t shader_id) { return MakeUnique( - MakeUnique(desc_set, shader_id)); + MakeUnique(shader_id)); } Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set, @@ -958,10 +995,9 @@ Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set, MakeUnique(desc_set, shader_id)); } -Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t desc_set, - uint32_t shader_id) { +Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t shader_id) { return MakeUnique( - MakeUnique(desc_set, shader_id)); + MakeUnique(shader_id)); } Optimizer::PassToken CreateConvertRelaxedToHalfPass() { @@ -1076,6 +1112,16 @@ Optimizer::PassToken CreateTrimCapabilitiesPass() { return MakeUnique( MakeUnique()); } + +Optimizer::PassToken CreateSwitchDescriptorSetPass(uint32_t from, uint32_t to) { + return MakeUnique( + MakeUnique(from, to)); +} + +Optimizer::PassToken CreateInvocationInterlockPlacementPass() { + return MakeUnique( + MakeUnique()); +} } // namespace spvtools extern "C" { diff --git a/source/opt/passes.h b/source/opt/passes.h index f87216dd63..305f578279 100644 --- a/source/opt/passes.h +++ b/source/opt/passes.h @@ -53,6 +53,7 @@ #include "source/opt/inst_debug_printf_pass.h" #include "source/opt/interface_var_sroa.h" #include "source/opt/interp_fixup_pass.h" +#include "source/opt/invocation_interlock_placement_pass.h" #include "source/opt/licm_pass.h" #include "source/opt/local_access_chain_convert_pass.h" #include "source/opt/local_redundancy_elimination.h" @@ -82,6 +83,7 @@ #include "source/opt/strength_reduction_pass.h" #include "source/opt/strip_debug_info_pass.h" #include "source/opt/strip_nonsemantic_info_pass.h" +#include "source/opt/switch_descriptorset_pass.h" #include "source/opt/trim_capabilities_pass.h" #include "source/opt/unify_const_pass.h" #include "source/opt/upgrade_memory_model.h" diff --git a/source/opt/switch_descriptorset_pass.cpp b/source/opt/switch_descriptorset_pass.cpp new file mode 100644 index 0000000000..f07c917579 --- /dev/null +++ b/source/opt/switch_descriptorset_pass.cpp @@ -0,0 +1,46 @@ +// Copyright (c) 2023 LunarG 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. + +#include "source/opt/switch_descriptorset_pass.h" + +#include "source/opt/ir_builder.h" +#include "source/util/string_utils.h" + +namespace spvtools { +namespace opt { + +Pass::Status SwitchDescriptorSetPass::Process() { + Status status = Status::SuccessWithoutChange; + auto* deco_mgr = context()->get_decoration_mgr(); + + for (Instruction& var : context()->types_values()) { + if (var.opcode() != spv::Op::OpVariable) { + continue; + } + auto decos = deco_mgr->GetDecorationsFor(var.result_id(), false); + for (const auto& deco : decos) { + spv::Decoration d = spv::Decoration(deco->GetSingleWordInOperand(1u)); + if (d == spv::Decoration::DescriptorSet && + deco->GetSingleWordInOperand(2u) == ds_from_) { + deco->SetInOperand(2u, {ds_to_}); + status = Status::SuccessWithChange; + break; + } + } + } + return status; +} + +} // namespace opt +} // namespace spvtools diff --git a/source/opt/switch_descriptorset_pass.h b/source/opt/switch_descriptorset_pass.h new file mode 100644 index 0000000000..2084e9cda1 --- /dev/null +++ b/source/opt/switch_descriptorset_pass.h @@ -0,0 +1,52 @@ +// Copyright (c) 2023 LunarG 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. + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// See optimizer.hpp for documentation. +class SwitchDescriptorSetPass : public Pass { + public: + SwitchDescriptorSetPass(uint32_t ds_from, uint32_t ds_to) + : ds_from_(ds_from), ds_to_(ds_to) {} + + const char* name() const override { return "switch-descriptorset"; } + + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + // this pass preserves everything except decorations + uint32_t mask = ((IRContext::kAnalysisEnd << 1) - 1); + mask &= ~static_cast(IRContext::kAnalysisDecorations); + return static_cast(mask); + } + + private: + uint32_t ds_from_; + uint32_t ds_to_; +}; + +} // namespace opt +} // namespace spvtools diff --git a/source/opt/trim_capabilities_pass.cpp b/source/opt/trim_capabilities_pass.cpp index 1a7633d65c..05499471d4 100644 --- a/source/opt/trim_capabilities_pass.cpp +++ b/source/opt/trim_capabilities_pass.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include "source/enum_set.h" #include "source/enum_string_mapping.h" #include "source/opt/ir_context.h" +#include "source/opt/reflect.h" #include "source/spirv_target_env.h" #include "source/util/string_utils.h" @@ -34,10 +36,96 @@ namespace spvtools { namespace opt { namespace { -constexpr uint32_t kVariableStorageClassIndex = 0; +constexpr uint32_t kOpTypeFloatSizeIndex = 0; +constexpr uint32_t kOpTypePointerStorageClassIndex = 0; constexpr uint32_t kTypeArrayTypeIndex = 0; constexpr uint32_t kOpTypeScalarBitWidthIndex = 0; -constexpr uint32_t kTypePointerTypeIdInIdx = 1; +constexpr uint32_t kTypePointerTypeIdInIndex = 1; +constexpr uint32_t kOpTypeIntSizeIndex = 0; +constexpr uint32_t kOpTypeImageDimIndex = 1; +constexpr uint32_t kOpTypeImageArrayedIndex = kOpTypeImageDimIndex + 2; +constexpr uint32_t kOpTypeImageMSIndex = kOpTypeImageArrayedIndex + 1; +constexpr uint32_t kOpTypeImageSampledIndex = kOpTypeImageMSIndex + 1; +constexpr uint32_t kOpTypeImageFormatIndex = kOpTypeImageSampledIndex + 1; +constexpr uint32_t kOpImageReadImageIndex = 0; +constexpr uint32_t kOpImageSparseReadImageIndex = 0; + +// DFS visit of the type defined by `instruction`. +// If `condition` is true, children of the current node are visited. +// If `condition` is false, the children of the current node are ignored. +template +static void DFSWhile(const Instruction* instruction, UnaryPredicate condition) { + std::stack instructions_to_visit; + instructions_to_visit.push(instruction->result_id()); + const auto* def_use_mgr = instruction->context()->get_def_use_mgr(); + + while (!instructions_to_visit.empty()) { + const Instruction* item = def_use_mgr->GetDef(instructions_to_visit.top()); + instructions_to_visit.pop(); + + if (!condition(item)) { + continue; + } + + if (item->opcode() == spv::Op::OpTypePointer) { + instructions_to_visit.push( + item->GetSingleWordInOperand(kTypePointerTypeIdInIndex)); + continue; + } + + if (item->opcode() == spv::Op::OpTypeMatrix || + item->opcode() == spv::Op::OpTypeVector || + item->opcode() == spv::Op::OpTypeArray || + item->opcode() == spv::Op::OpTypeRuntimeArray) { + instructions_to_visit.push( + item->GetSingleWordInOperand(kTypeArrayTypeIndex)); + continue; + } + + if (item->opcode() == spv::Op::OpTypeStruct) { + item->ForEachInOperand([&instructions_to_visit](const uint32_t* op_id) { + instructions_to_visit.push(*op_id); + }); + continue; + } + } +} + +// Walks the type defined by `instruction` (OpType* only). +// Returns `true` if any call to `predicate` with the type/subtype returns true. +template +static bool AnyTypeOf(const Instruction* instruction, + UnaryPredicate predicate) { + assert(IsTypeInst(instruction->opcode()) && + "AnyTypeOf called with a non-type instruction."); + + bool found_one = false; + DFSWhile(instruction, [&found_one, predicate](const Instruction* node) { + if (found_one || predicate(node)) { + found_one = true; + return false; + } + + return true; + }); + return found_one; +} + +static bool is16bitType(const Instruction* instruction) { + if (instruction->opcode() != spv::Op::OpTypeInt && + instruction->opcode() != spv::Op::OpTypeFloat) { + return false; + } + + return instruction->GetSingleWordInOperand(kOpTypeScalarBitWidthIndex) == 16; +} + +static bool Has16BitCapability(const FeatureManager* feature_manager) { + const CapabilitySet& capabilities = feature_manager->GetCapabilities(); + return capabilities.contains(spv::Capability::Float16) || + capabilities.contains(spv::Capability::Int16); +} + } // namespace // ============== Begin opcode handler implementations. ======================= @@ -49,76 +137,223 @@ constexpr uint32_t kTypePointerTypeIdInIdx = 1; // Handler names follow the following convention: // Handler__() -static std::optional Handler_OpVariable_StorageInputOutput16( +static std::optional Handler_OpTypeFloat_Float64( const Instruction* instruction) { - assert(instruction->opcode() == spv::Op::OpVariable && - "This handler only support OpVariable opcodes."); + assert(instruction->opcode() == spv::Op::OpTypeFloat && + "This handler only support OpTypeFloat opcodes."); - // This capability is only required if the variable as an Input/Output storage - // class. + const uint32_t size = + instruction->GetSingleWordInOperand(kOpTypeFloatSizeIndex); + return size == 64 ? std::optional(spv::Capability::Float64) : std::nullopt; +} + +static std::optional +Handler_OpTypePointer_StorageInputOutput16(const Instruction* instruction) { + assert(instruction->opcode() == spv::Op::OpTypePointer && + "This handler only support OpTypePointer opcodes."); + + // This capability is only required if the variable has an Input/Output + // storage class. spv::StorageClass storage_class = spv::StorageClass( - instruction->GetSingleWordInOperand(kVariableStorageClassIndex)); + instruction->GetSingleWordInOperand(kOpTypePointerStorageClassIndex)); if (storage_class != spv::StorageClass::Input && storage_class != spv::StorageClass::Output) { return std::nullopt; } - // This capability is only required if the type involves a 16-bit component. - // Quick check: are 16-bit types allowed? - const CapabilitySet& capabilities = - instruction->context()->get_feature_mgr()->GetCapabilities(); - if (!capabilities.contains(spv::Capability::Float16) && - !capabilities.contains(spv::Capability::Int16)) { + if (!Has16BitCapability(instruction->context()->get_feature_mgr())) { return std::nullopt; } - // We need to walk the type definition. - std::queue instructions_to_visit; - instructions_to_visit.push(instruction->type_id()); - const auto* def_use_mgr = instruction->context()->get_def_use_mgr(); - while (!instructions_to_visit.empty()) { - const Instruction* item = - def_use_mgr->GetDef(instructions_to_visit.front()); - instructions_to_visit.pop(); + return AnyTypeOf(instruction, is16bitType) + ? std::optional(spv::Capability::StorageInputOutput16) + : std::nullopt; +} - if (item->opcode() == spv::Op::OpTypePointer) { - instructions_to_visit.push( - item->GetSingleWordInOperand(kTypePointerTypeIdInIdx)); - continue; - } +static std::optional +Handler_OpTypePointer_StoragePushConstant16(const Instruction* instruction) { + assert(instruction->opcode() == spv::Op::OpTypePointer && + "This handler only support OpTypePointer opcodes."); - if (item->opcode() == spv::Op::OpTypeMatrix || - item->opcode() == spv::Op::OpTypeVector || - item->opcode() == spv::Op::OpTypeArray || - item->opcode() == spv::Op::OpTypeRuntimeArray) { - instructions_to_visit.push( - item->GetSingleWordInOperand(kTypeArrayTypeIndex)); - continue; - } + // This capability is only required if the variable has a PushConstant storage + // class. + spv::StorageClass storage_class = spv::StorageClass( + instruction->GetSingleWordInOperand(kOpTypePointerStorageClassIndex)); + if (storage_class != spv::StorageClass::PushConstant) { + return std::nullopt; + } - if (item->opcode() == spv::Op::OpTypeStruct) { - item->ForEachInOperand([&instructions_to_visit](const uint32_t* op_id) { - instructions_to_visit.push(*op_id); + if (!Has16BitCapability(instruction->context()->get_feature_mgr())) { + return std::nullopt; + } + + return AnyTypeOf(instruction, is16bitType) + ? std::optional(spv::Capability::StoragePushConstant16) + : std::nullopt; +} + +static std::optional +Handler_OpTypePointer_StorageUniformBufferBlock16( + const Instruction* instruction) { + assert(instruction->opcode() == spv::Op::OpTypePointer && + "This handler only support OpTypePointer opcodes."); + + // This capability is only required if the variable has a Uniform storage + // class. + spv::StorageClass storage_class = spv::StorageClass( + instruction->GetSingleWordInOperand(kOpTypePointerStorageClassIndex)); + if (storage_class != spv::StorageClass::Uniform) { + return std::nullopt; + } + + if (!Has16BitCapability(instruction->context()->get_feature_mgr())) { + return std::nullopt; + } + + const auto* decoration_mgr = instruction->context()->get_decoration_mgr(); + const bool matchesCondition = + AnyTypeOf(instruction, [decoration_mgr](const Instruction* item) { + if (!decoration_mgr->HasDecoration(item->result_id(), + spv::Decoration::BufferBlock)) { + return false; + } + + return AnyTypeOf(item, is16bitType); }); - continue; + + return matchesCondition + ? std::optional(spv::Capability::StorageUniformBufferBlock16) + : std::nullopt; +} + +static std::optional Handler_OpTypePointer_StorageUniform16( + const Instruction* instruction) { + assert(instruction->opcode() == spv::Op::OpTypePointer && + "This handler only support OpTypePointer opcodes."); + + // This capability is only required if the variable has a Uniform storage + // class. + spv::StorageClass storage_class = spv::StorageClass( + instruction->GetSingleWordInOperand(kOpTypePointerStorageClassIndex)); + if (storage_class != spv::StorageClass::Uniform) { + return std::nullopt; + } + + const auto* feature_manager = instruction->context()->get_feature_mgr(); + if (!Has16BitCapability(feature_manager)) { + return std::nullopt; + } + + const bool hasBufferBlockCapability = + feature_manager->GetCapabilities().contains( + spv::Capability::StorageUniformBufferBlock16); + const auto* decoration_mgr = instruction->context()->get_decoration_mgr(); + bool found16bitType = false; + + DFSWhile(instruction, [decoration_mgr, hasBufferBlockCapability, + &found16bitType](const Instruction* item) { + if (found16bitType) { + return false; } - if (item->opcode() != spv::Op::OpTypeInt && - item->opcode() != spv::Op::OpTypeFloat) { - continue; + if (hasBufferBlockCapability && + decoration_mgr->HasDecoration(item->result_id(), + spv::Decoration::BufferBlock)) { + return false; } - if (item->GetSingleWordInOperand(kOpTypeScalarBitWidthIndex) == 16) { - return spv::Capability::StorageInputOutput16; + if (is16bitType(item)) { + found16bitType = true; + return false; } - } - return std::nullopt; + return true; + }); + + return found16bitType ? std::optional(spv::Capability::StorageUniform16) + : std::nullopt; +} + +static std::optional Handler_OpTypeInt_Int64( + const Instruction* instruction) { + assert(instruction->opcode() == spv::Op::OpTypeInt && + "This handler only support OpTypeInt opcodes."); + + const uint32_t size = + instruction->GetSingleWordInOperand(kOpTypeIntSizeIndex); + return size == 64 ? std::optional(spv::Capability::Int64) : std::nullopt; +} + +static std::optional Handler_OpTypeImage_ImageMSArray( + const Instruction* instruction) { + assert(instruction->opcode() == spv::Op::OpTypeImage && + "This handler only support OpTypeImage opcodes."); + + const uint32_t arrayed = + instruction->GetSingleWordInOperand(kOpTypeImageArrayedIndex); + const uint32_t ms = instruction->GetSingleWordInOperand(kOpTypeImageMSIndex); + const uint32_t sampled = + instruction->GetSingleWordInOperand(kOpTypeImageSampledIndex); + + return arrayed == 1 && sampled == 2 && ms == 1 + ? std::optional(spv::Capability::ImageMSArray) + : std::nullopt; +} + +static std::optional +Handler_OpImageRead_StorageImageReadWithoutFormat( + const Instruction* instruction) { + assert(instruction->opcode() == spv::Op::OpImageRead && + "This handler only support OpImageRead opcodes."); + const auto* def_use_mgr = instruction->context()->get_def_use_mgr(); + + const uint32_t image_index = + instruction->GetSingleWordInOperand(kOpImageReadImageIndex); + const uint32_t type_index = def_use_mgr->GetDef(image_index)->type_id(); + const Instruction* type = def_use_mgr->GetDef(type_index); + const uint32_t dim = type->GetSingleWordInOperand(kOpTypeImageDimIndex); + const uint32_t format = type->GetSingleWordInOperand(kOpTypeImageFormatIndex); + + const bool is_unknown = spv::ImageFormat(format) == spv::ImageFormat::Unknown; + const bool requires_capability_for_unknown = + spv::Dim(dim) != spv::Dim::SubpassData; + return is_unknown && requires_capability_for_unknown + ? std::optional(spv::Capability::StorageImageReadWithoutFormat) + : std::nullopt; +} + +static std::optional +Handler_OpImageSparseRead_StorageImageReadWithoutFormat( + const Instruction* instruction) { + assert(instruction->opcode() == spv::Op::OpImageSparseRead && + "This handler only support OpImageSparseRead opcodes."); + const auto* def_use_mgr = instruction->context()->get_def_use_mgr(); + + const uint32_t image_index = + instruction->GetSingleWordInOperand(kOpImageSparseReadImageIndex); + const uint32_t type_index = def_use_mgr->GetDef(image_index)->type_id(); + const Instruction* type = def_use_mgr->GetDef(type_index); + const uint32_t format = type->GetSingleWordInOperand(kOpTypeImageFormatIndex); + + return spv::ImageFormat(format) == spv::ImageFormat::Unknown + ? std::optional(spv::Capability::StorageImageReadWithoutFormat) + : std::nullopt; } // Opcode of interest to determine capabilities requirements. -constexpr std::array, 1> kOpcodeHandlers{{ - {spv::Op::OpVariable, Handler_OpVariable_StorageInputOutput16}, +constexpr std::array, 10> kOpcodeHandlers{{ + // clang-format off + {spv::Op::OpImageRead, Handler_OpImageRead_StorageImageReadWithoutFormat}, + {spv::Op::OpImageSparseRead, Handler_OpImageSparseRead_StorageImageReadWithoutFormat}, + {spv::Op::OpTypeFloat, Handler_OpTypeFloat_Float64 }, + {spv::Op::OpTypeImage, Handler_OpTypeImage_ImageMSArray}, + {spv::Op::OpTypeInt, Handler_OpTypeInt_Int64 }, + {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageInputOutput16}, + {spv::Op::OpTypePointer, Handler_OpTypePointer_StoragePushConstant16}, + {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniform16}, + {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniform16}, + {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniformBufferBlock16}, + // clang-format on }}; // ============== End opcode handler implementations. ======================= @@ -156,57 +391,89 @@ TrimCapabilitiesPass::TrimCapabilitiesPass() TrimCapabilitiesPass::kUntouchableCapabilities.cend()), opcodeHandlers_(kOpcodeHandlers.cbegin(), kOpcodeHandlers.cend()) {} -void TrimCapabilitiesPass::addInstructionRequirements( - Instruction* instruction, CapabilitySet* capabilities, +void TrimCapabilitiesPass::addInstructionRequirementsForOpcode( + spv::Op opcode, CapabilitySet* capabilities, ExtensionSet* extensions) const { - // Ignoring OpCapability instructions. - if (instruction->opcode() == spv::Op::OpCapability) { + // Ignoring OpBeginInvocationInterlockEXT and OpEndInvocationInterlockEXT + // because they have three possible capabilities, only one of which is needed + if (opcode == spv::Op::OpBeginInvocationInterlockEXT || + opcode == spv::Op::OpEndInvocationInterlockEXT) { return; } - // First case: the opcode is itself gated by a capability. - { - const spv_opcode_desc_t* desc = {}; - auto result = - context()->grammar().lookupOpcode(instruction->opcode(), &desc); - if (result == SPV_SUCCESS) { - addSupportedCapabilitiesToSet(desc->numCapabilities, desc->capabilities, - capabilities); - if (desc->minVersion <= - spvVersionForTargetEnv(context()->GetTargetEnv())) { - extensions->insert(desc->extensions, - desc->extensions + desc->numExtensions); - } - } + const spv_opcode_desc_t* desc = {}; + auto result = context()->grammar().lookupOpcode(opcode, &desc); + if (result != SPV_SUCCESS) { + return; } - // Second case: one of the opcode operand is gated by a capability. - const uint32_t operandCount = instruction->NumOperands(); - for (uint32_t i = 0; i < operandCount; i++) { - const auto& operand = instruction->GetOperand(i); - // No supported capability relies on a 2+-word operand. - if (operand.words.size() != 1) { - continue; - } + addSupportedCapabilitiesToSet(desc, capabilities); + addSupportedExtensionsToSet(desc, extensions); +} - // No supported capability relies on a literal string operand. - if (operand.type == SPV_OPERAND_TYPE_LITERAL_STRING) { - continue; - } +void TrimCapabilitiesPass::addInstructionRequirementsForOperand( + const Operand& operand, CapabilitySet* capabilities, + ExtensionSet* extensions) const { + // No supported capability relies on a 2+-word operand. + if (operand.words.size() != 1) { + return; + } + + // No supported capability relies on a literal string operand or an ID. + if (operand.type == SPV_OPERAND_TYPE_LITERAL_STRING || + operand.type == SPV_OPERAND_TYPE_ID || + operand.type == SPV_OPERAND_TYPE_RESULT_ID) { + return; + } + // case 1: Operand is a single value, can directly lookup. + if (!spvOperandIsConcreteMask(operand.type)) { const spv_operand_desc_t* desc = {}; auto result = context()->grammar().lookupOperand(operand.type, operand.words[0], &desc); if (result != SPV_SUCCESS) { + return; + } + addSupportedCapabilitiesToSet(desc, capabilities); + addSupportedExtensionsToSet(desc, extensions); + return; + } + + // case 2: operand can be a bitmask, we need to decompose the lookup. + for (uint32_t i = 0; i < 32; i++) { + const uint32_t mask = (1 << i) & operand.words[0]; + if (!mask) { continue; } - addSupportedCapabilitiesToSet(desc->numCapabilities, desc->capabilities, - capabilities); - if (desc->minVersion <= spvVersionForTargetEnv(context()->GetTargetEnv())) { - extensions->insert(desc->extensions, - desc->extensions + desc->numExtensions); + const spv_operand_desc_t* desc = {}; + auto result = context()->grammar().lookupOperand(operand.type, mask, &desc); + if (result != SPV_SUCCESS) { + continue; } + + addSupportedCapabilitiesToSet(desc, capabilities); + addSupportedExtensionsToSet(desc, extensions); + } +} + +void TrimCapabilitiesPass::addInstructionRequirements( + Instruction* instruction, CapabilitySet* capabilities, + ExtensionSet* extensions) const { + // Ignoring OpCapability and OpExtension instructions. + if (instruction->opcode() == spv::Op::OpCapability || + instruction->opcode() == spv::Op::OpExtension) { + return; + } + + addInstructionRequirementsForOpcode(instruction->opcode(), capabilities, + extensions); + + // Second case: one of the opcode operand is gated by a capability. + const uint32_t operandCount = instruction->NumOperands(); + for (uint32_t i = 0; i < operandCount; i++) { + addInstructionRequirementsForOperand(instruction->GetOperand(i), + capabilities, extensions); } // Last case: some complex logic needs to be run to determine capabilities. @@ -214,10 +481,23 @@ void TrimCapabilitiesPass::addInstructionRequirements( for (auto it = begin; it != end; it++) { const OpcodeHandler handler = it->second; auto result = handler(instruction); - if (result.has_value()) { - capabilities->insert(*result); + if (!result.has_value()) { + continue; } + + capabilities->insert(*result); + } +} + +void TrimCapabilitiesPass::AddExtensionsForOperand( + const spv_operand_type_t type, const uint32_t value, + ExtensionSet* extensions) const { + const spv_operand_desc_t* desc = nullptr; + spv_result_t result = context()->grammar().lookupOperand(type, value, &desc); + if (result != SPV_SUCCESS) { + return; } + addSupportedExtensionsToSet(desc, extensions); } std::pair @@ -230,6 +510,12 @@ TrimCapabilitiesPass::DetermineRequiredCapabilitiesAndExtensions() const { &required_extensions); }); + for (auto capability : required_capabilities) { + AddExtensionsForOperand(SPV_OPERAND_TYPE_CAPABILITY, + static_cast(capability), + &required_extensions); + } + #if !defined(NDEBUG) // Debug only. We check the outputted required capabilities against the // supported capabilities list. The supported capabilities list is useful for @@ -254,11 +540,6 @@ Pass::Status TrimCapabilitiesPass::TrimUnrequiredCapabilities( const FeatureManager* feature_manager = context()->get_feature_mgr(); CapabilitySet capabilities_to_trim; for (auto capability : feature_manager->GetCapabilities()) { - // Forbidden capability completely prevents trimming. Early exit. - if (forbiddenCapabilities_.contains(capability)) { - return Pass::Status::SuccessWithoutChange; - } - // Some capabilities cannot be safely removed. Leaving them untouched. if (untouchableCapabilities_.contains(capability)) { continue; @@ -291,9 +572,12 @@ Pass::Status TrimCapabilitiesPass::TrimUnrequiredExtensions( bool modified_module = false; for (auto extension : supported_extensions) { - if (!required_extensions.contains(extension)) { + if (required_extensions.contains(extension)) { + continue; + } + + if (context()->RemoveExtension(extension)) { modified_module = true; - context()->RemoveExtension(extension); } } @@ -301,19 +585,31 @@ Pass::Status TrimCapabilitiesPass::TrimUnrequiredExtensions( : Pass::Status::SuccessWithoutChange; } +bool TrimCapabilitiesPass::HasForbiddenCapabilities() const { + // EnumSet.HasAnyOf returns `true` if the given set is empty. + if (forbiddenCapabilities_.size() == 0) { + return false; + } + + const auto& capabilities = context()->get_feature_mgr()->GetCapabilities(); + return capabilities.HasAnyOf(forbiddenCapabilities_); +} + Pass::Status TrimCapabilitiesPass::Process() { + if (HasForbiddenCapabilities()) { + return Status::SuccessWithoutChange; + } + auto[required_capabilities, required_extensions] = DetermineRequiredCapabilitiesAndExtensions(); - Pass::Status status = TrimUnrequiredCapabilities(required_capabilities); - // If no capabilities were removed, we have no extension to trim. - // Note: this is true because this pass only removes unused extensions caused - // by unused capabilities. - // This is not an extension trimming pass. - if (status == Pass::Status::SuccessWithoutChange) { - return status; - } - return TrimUnrequiredExtensions(required_extensions); + Pass::Status capStatus = TrimUnrequiredCapabilities(required_capabilities); + Pass::Status extStatus = TrimUnrequiredExtensions(required_extensions); + + return capStatus == Pass::Status::SuccessWithChange || + extStatus == Pass::Status::SuccessWithChange + ? Pass::Status::SuccessWithChange + : Pass::Status::SuccessWithoutChange; } } // namespace opt diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index 6f188c96bd..73d5dc80d5 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -27,6 +27,7 @@ #include "source/opt/ir_context.h" #include "source/opt/module.h" #include "source/opt/pass.h" +#include "source/spirv_target_env.h" namespace spvtools { namespace opt { @@ -73,12 +74,28 @@ class TrimCapabilitiesPass : public Pass { // contains unsupported instruction, the pass could yield bad results. static constexpr std::array kSupportedCapabilities{ // clang-format off + spv::Capability::ComputeDerivativeGroupLinearNV, + spv::Capability::ComputeDerivativeGroupQuadsNV, + spv::Capability::Float64, + spv::Capability::FragmentShaderPixelInterlockEXT, + spv::Capability::FragmentShaderSampleInterlockEXT, + spv::Capability::FragmentShaderShadingRateInterlockEXT, spv::Capability::Groups, + spv::Capability::ImageMSArray, + spv::Capability::Int64, spv::Capability::Linkage, spv::Capability::MinLod, + spv::Capability::PhysicalStorageBufferAddresses, + spv::Capability::RayQueryKHR, + spv::Capability::RayTracingKHR, + spv::Capability::RayTraversalPrimitiveCullingKHR, spv::Capability::Shader, spv::Capability::ShaderClockKHR, - spv::Capability::StorageInputOutput16 + spv::Capability::StorageImageReadWithoutFormat, + spv::Capability::StorageInputOutput16, + spv::Capability::StoragePushConstant16, + spv::Capability::StorageUniform16, + spv::Capability::StorageUniformBufferBlock16 // clang-format on }; @@ -99,25 +116,55 @@ class TrimCapabilitiesPass : public Pass { TrimCapabilitiesPass(TrimCapabilitiesPass&&) = delete; private: - // Inserts every capability in `capabilities[capabilityCount]` supported by - // this pass into `output`. - inline void addSupportedCapabilitiesToSet( - uint32_t capabilityCount, const spv::Capability* const capabilities, - CapabilitySet* output) const { + // Inserts every capability listed by `descriptor` this pass supports into + // `output`. Expects a Descriptor like `spv_opcode_desc_t` or + // `spv_operand_desc_t`. + template + inline void addSupportedCapabilitiesToSet(const Descriptor* const descriptor, + CapabilitySet* output) const { + const uint32_t capabilityCount = descriptor->numCapabilities; for (uint32_t i = 0; i < capabilityCount; ++i) { - if (supportedCapabilities_.contains(capabilities[i])) { - output->insert(capabilities[i]); + const auto capability = descriptor->capabilities[i]; + if (supportedCapabilities_.contains(capability)) { + output->insert(capability); } } } - // Given an `instruction`, determines the capabilities and extension it - // requires, and output them in `capabilities` and `extensions`. The returned - // capabilities form a subset of kSupportedCapabilities. + // Inserts every extension listed by `descriptor` required by the module into + // `output`. Expects a Descriptor like `spv_opcode_desc_t` or + // `spv_operand_desc_t`. + template + inline void addSupportedExtensionsToSet(const Descriptor* const descriptor, + ExtensionSet* output) const { + if (descriptor->minVersion <= + spvVersionForTargetEnv(context()->GetTargetEnv())) { + return; + } + output->insert(descriptor->extensions, + descriptor->extensions + descriptor->numExtensions); + } + + void addInstructionRequirementsForOpcode(spv::Op opcode, + CapabilitySet* capabilities, + ExtensionSet* extensions) const; + void addInstructionRequirementsForOperand(const Operand& operand, + CapabilitySet* capabilities, + ExtensionSet* extensions) const; + + // Given an `instruction`, determines the capabilities it requires, and output + // them in `capabilities`. The returned capabilities form a subset of + // kSupportedCapabilities. void addInstructionRequirements(Instruction* instruction, CapabilitySet* capabilities, ExtensionSet* extensions) const; + // Given an operand `type` and `value`, adds the extensions it would require + // to `extensions`. + void AddExtensionsForOperand(const spv_operand_type_t type, + const uint32_t value, + ExtensionSet* extensions) const; + // Returns the list of required capabilities and extensions for the module. // The returned capabilities form a subset of kSupportedCapabilities. std::pair @@ -134,6 +181,9 @@ class TrimCapabilitiesPass : public Pass { Pass::Status TrimUnrequiredExtensions( const ExtensionSet& required_extensions) const; + // Returns if the analyzed module contains any forbidden capability. + bool HasForbiddenCapabilities() const; + public: const char* name() const override { return "trim-capabilities"; } Status Process() override; diff --git a/source/opt/type_manager.cpp b/source/opt/type_manager.cpp index 2dcc25940c..ae320772df 100644 --- a/source/opt/type_manager.cpp +++ b/source/opt/type_manager.cpp @@ -901,7 +901,7 @@ Type* TypeManager::RecordIfTypeDefinition(const Instruction& inst) { type = new HitObjectNV(); break; default: - SPIRV_UNIMPLEMENTED(consumer_, "unhandled type"); + assert(false && "Type not handled by the type manager."); break; } @@ -943,12 +943,10 @@ void TypeManager::AttachDecoration(const Instruction& inst, Type* type) { } if (Struct* st = type->AsStruct()) { st->AddMemberDecoration(index, std::move(data)); - } else { - SPIRV_UNIMPLEMENTED(consumer_, "OpMemberDecorate non-struct type"); } } break; default: - SPIRV_UNREACHABLE(consumer_); + assert(false && "Unexpected opcode for a decoration instruction."); break; } } diff --git a/source/print.cpp b/source/print.cpp index 6c94e2b7fc..f36812ef56 100644 --- a/source/print.cpp +++ b/source/print.cpp @@ -17,7 +17,7 @@ #if defined(SPIRV_ANDROID) || defined(SPIRV_LINUX) || defined(SPIRV_MAC) || \ defined(SPIRV_IOS) || defined(SPIRV_TVOS) || defined(SPIRV_FREEBSD) || \ defined(SPIRV_OPENBSD) || defined(SPIRV_EMSCRIPTEN) || \ - defined(SPIRV_FUCHSIA) || defined(SPIRV_GNU) + defined(SPIRV_FUCHSIA) || defined(SPIRV_GNU) || defined(SPIRV_QNX) namespace spvtools { clr::reset::operator const char*() { return "\x1b[0m"; } diff --git a/source/val/validate.cpp b/source/val/validate.cpp index e73e466026..a5f320b9f4 100644 --- a/source/val/validate.cpp +++ b/source/val/validate.cpp @@ -381,6 +381,8 @@ spv_result_t ValidateBinaryUsingContextAndValidationState( for (const auto& inst : vstate->ordered_instructions()) { if (auto error = ValidateExecutionLimitations(*vstate, &inst)) return error; if (auto error = ValidateSmallTypeUses(*vstate, &inst)) return error; + if (auto error = ValidateQCOMImageProcessingTextureUsages(*vstate, &inst)) + return error; } return SPV_SUCCESS; diff --git a/source/val/validate.h b/source/val/validate.h index 2cd229f96a..6b7d7cdacf 100644 --- a/source/val/validate.h +++ b/source/val/validate.h @@ -220,6 +220,14 @@ spv_result_t ValidateExecutionLimitations(ValidationState_t& _, spv_result_t ValidateSmallTypeUses(ValidationState_t& _, const Instruction* inst); +/// Validates restricted uses of QCOM decorated textures +/// +/// The textures that are decorated with some of QCOM image processing +/// decorations must be used in the specified QCOM image processing built-in +/// functions and not used in any other image functions. +spv_result_t ValidateQCOMImageProcessingTextureUsages(ValidationState_t& _, + const Instruction* inst); + /// @brief Validate the ID's within a SPIR-V binary /// /// @param[in] pInstructions array of instructions diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp index 605b79ebff..caa4a6f184 100644 --- a/source/val/validate_decorations.cpp +++ b/source/val/validate_decorations.cpp @@ -922,9 +922,9 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { } } - if (vstate.HasCapability( - spv::Capability::WorkgroupMemoryExplicitLayoutKHR) && - num_workgroup_variables > 0 && + const bool workgroup_blocks_allowed = vstate.HasCapability( + spv::Capability::WorkgroupMemoryExplicitLayoutKHR); + if (workgroup_blocks_allowed && num_workgroup_variables > 0 && num_workgroup_variables_with_block > 0) { if (num_workgroup_variables != num_workgroup_variables_with_block) { return vstate.diag(SPV_ERROR_INVALID_BINARY, vstate.FindDef(entry_point)) @@ -945,6 +945,13 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { "Entry point id " << entry_point << " does not meet this requirement."; } + } else if (!workgroup_blocks_allowed && + num_workgroup_variables_with_block > 0) { + return vstate.diag(SPV_ERROR_INVALID_BINARY, + vstate.FindDef(entry_point)) + << "Workgroup Storage Class variables can't be decorated with " + "Block unless declaring the WorkgroupMemoryExplicitLayoutKHR " + "capability."; } } } diff --git a/source/val/validate_extensions.cpp b/source/val/validate_extensions.cpp index 0ac62bfc8d..0334b60640 100644 --- a/source/val/validate_extensions.cpp +++ b/source/val/validate_extensions.cpp @@ -482,8 +482,8 @@ spv_result_t ValidateClspvReflectionArgumentBuffer(ValidationState_t& _, return SPV_SUCCESS; } -spv_result_t ValidateClspvReflectionArgumentOffsetBuffer(ValidationState_t& _, - const Instruction* inst) { +spv_result_t ValidateClspvReflectionArgumentOffsetBuffer( + ValidationState_t& _, const Instruction* inst) { const auto num_operands = inst->operands().size(); if (auto error = ValidateKernelDecl(_, inst)) { return error; @@ -802,7 +802,7 @@ spv_result_t ValidateClspvReflectionPushConstantData(ValidationState_t& _, } spv_result_t ValidateClspvReflectionPrintfInfo(ValidationState_t& _, - const Instruction* inst) { + const Instruction* inst) { if (!IsUint32Constant(_, inst->GetOperandAs(4))) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "PrintfID must be a 32-bit unsigned integer OpConstant"; @@ -823,8 +823,8 @@ spv_result_t ValidateClspvReflectionPrintfInfo(ValidationState_t& _, return SPV_SUCCESS; } -spv_result_t ValidateClspvReflectionPrintfStorageBuffer(ValidationState_t& _, - const Instruction* inst) { +spv_result_t ValidateClspvReflectionPrintfStorageBuffer( + ValidationState_t& _, const Instruction* inst) { if (!IsUint32Constant(_, inst->GetOperandAs(4))) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "DescriptorSet must be a 32-bit unsigned integer OpConstant"; @@ -843,8 +843,8 @@ spv_result_t ValidateClspvReflectionPrintfStorageBuffer(ValidationState_t& _, return SPV_SUCCESS; } -spv_result_t ValidateClspvReflectionPrintfPushConstant(ValidationState_t& _, - const Instruction* inst) { +spv_result_t ValidateClspvReflectionPrintfPushConstant( + ValidationState_t& _, const Instruction* inst) { if (!IsUint32Constant(_, inst->GetOperandAs(4))) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Offset must be a 32-bit unsigned integer OpConstant"; @@ -3168,16 +3168,16 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { break; } case CommonDebugInfoDebugTypePointer: { - auto validate_base_type = - ValidateOperandBaseType(_, inst, 5, ext_inst_name); + auto validate_base_type = ValidateOperandDebugType( + _, "Base Type", inst, 5, ext_inst_name, false); if (validate_base_type != SPV_SUCCESS) return validate_base_type; CHECK_CONST_UINT_OPERAND("Storage Class", 6); CHECK_CONST_UINT_OPERAND("Flags", 7); break; } case CommonDebugInfoDebugTypeQualifier: { - auto validate_base_type = - ValidateOperandBaseType(_, inst, 5, ext_inst_name); + auto validate_base_type = ValidateOperandDebugType( + _, "Base Type", inst, 5, ext_inst_name, false); if (validate_base_type != SPV_SUCCESS) return validate_base_type; CHECK_CONST_UINT_OPERAND("Type Qualifier", 6); break; diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 8062d962c3..39eeb4bd7e 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Google Inc. +// Copyright (c) 2017 Google Inc. // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights // reserved. // @@ -693,16 +693,11 @@ spv_result_t ValidateImageReadWrite(ValidationState_t& _, << "storage image"; } - if (info.multisampled == 1 && + if (info.multisampled == 1 && info.arrayed == 1 && info.sampled == 2 && !_.HasCapability(spv::Capability::ImageMSArray)) { -#if 0 - // TODO(atgoo@github.com) The description of this rule in the spec - // is unclear and Glslang doesn't declare ImageMSArray. Need to clarify - // and reenable. return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Capability ImageMSArray is required to access storage " - << "image"; -#endif + << "Capability ImageMSArray is required to access storage " + << "image"; } } else if (info.sampled != 0) { return _.diag(SPV_ERROR_INVALID_DATA, inst) @@ -983,6 +978,10 @@ bool IsAllowedSampledImageOperand(spv::Op opcode, ValidationState_t& _) { case spv::Op::OpImageSparseGather: case spv::Op::OpImageSparseDrefGather: case spv::Op::OpCopyObject: + case spv::Op::OpImageSampleWeightedQCOM: + case spv::Op::OpImageBoxFilterQCOM: + case spv::Op::OpImageBlockMatchSSDQCOM: + case spv::Op::OpImageBlockMatchSADQCOM: return true; case spv::Op::OpStore: if (_.HasCapability(spv::Capability::BindlessTextureNV)) return true; @@ -1086,6 +1085,18 @@ spv_result_t ValidateSampledImage(ValidationState_t& _, } } } + + const Instruction* ld_inst; + { + int t_idx = inst->GetOperandAs(2); + ld_inst = _.FindDef(t_idx); + } + + if (ld_inst->opcode() == spv::Op::OpLoad) { + int texture_id = ld_inst->GetOperandAs(2); // variable to load + _.RegisterQCOMImageProcessingTextureConsumer(texture_id, ld_inst, inst); + } + return SPV_SUCCESS; } @@ -2129,6 +2140,56 @@ spv_result_t ValidateImageSparseTexelsResident(ValidationState_t& _, return SPV_SUCCESS; } +spv_result_t ValidateImageProcessingQCOMDecoration(ValidationState_t& _, int id, + spv::Decoration decor) { + const Instruction* si_inst = nullptr; + const Instruction* ld_inst = _.FindDef(id); + if (ld_inst->opcode() == spv::Op::OpSampledImage) { + si_inst = ld_inst; + int t_idx = si_inst->GetOperandAs(2); // texture + ld_inst = _.FindDef(t_idx); + } + if (ld_inst->opcode() != spv::Op::OpLoad) { + return _.diag(SPV_ERROR_INVALID_DATA, ld_inst) << "Expect to see OpLoad"; + } + int texture_id = ld_inst->GetOperandAs(2); // variable to load + if (!_.HasDecoration(texture_id, decor)) { + return _.diag(SPV_ERROR_INVALID_DATA, ld_inst) + << "Missing decoration WeightTextureQCOM/BlockMatchTextureQCOM"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateImageProcessingQCOM(ValidationState_t& _, + const Instruction* inst) { + spv_result_t res = SPV_SUCCESS; + const spv::Op opcode = inst->opcode(); + switch (opcode) { + case spv::Op::OpImageSampleWeightedQCOM: { + int wi_idx = inst->GetOperandAs(4); // weight + res = ValidateImageProcessingQCOMDecoration( + _, wi_idx, spv::Decoration::WeightTextureQCOM); + break; + } + case spv::Op::OpImageBlockMatchSSDQCOM: + case spv::Op::OpImageBlockMatchSADQCOM: { + int tgt_idx = inst->GetOperandAs(2); // target + res = ValidateImageProcessingQCOMDecoration( + _, tgt_idx, spv::Decoration::BlockMatchTextureQCOM); + if (res != SPV_SUCCESS) break; + int ref_idx = inst->GetOperandAs(4); // reference + res = ValidateImageProcessingQCOMDecoration( + _, ref_idx, spv::Decoration::BlockMatchTextureQCOM); + break; + } + default: + break; + } + + return res; +} + } // namespace // Validates correctness of image instructions. @@ -2248,6 +2309,12 @@ spv_result_t ImagePass(ValidationState_t& _, const Instruction* inst) { case spv::Op::OpImageSparseTexelsResident: return ValidateImageSparseTexelsResident(_, inst); + case spv::Op::OpImageSampleWeightedQCOM: + case spv::Op::OpImageBoxFilterQCOM: + case spv::Op::OpImageBlockMatchSSDQCOM: + case spv::Op::OpImageBlockMatchSADQCOM: + return ValidateImageProcessingQCOM(_, inst); + default: break; } @@ -2255,5 +2322,89 @@ spv_result_t ImagePass(ValidationState_t& _, const Instruction* inst) { return SPV_SUCCESS; } +bool IsImageInstruction(const spv::Op opcode) { + switch (opcode) { + case spv::Op::OpImageSampleImplicitLod: + case spv::Op::OpImageSampleDrefImplicitLod: + case spv::Op::OpImageSampleProjImplicitLod: + case spv::Op::OpImageSampleProjDrefImplicitLod: + case spv::Op::OpImageSparseSampleImplicitLod: + case spv::Op::OpImageSparseSampleDrefImplicitLod: + case spv::Op::OpImageSparseSampleProjImplicitLod: + case spv::Op::OpImageSparseSampleProjDrefImplicitLod: + + case spv::Op::OpImageSampleExplicitLod: + case spv::Op::OpImageSampleDrefExplicitLod: + case spv::Op::OpImageSampleProjExplicitLod: + case spv::Op::OpImageSampleProjDrefExplicitLod: + case spv::Op::OpImageSparseSampleExplicitLod: + case spv::Op::OpImageSparseSampleDrefExplicitLod: + case spv::Op::OpImageSparseSampleProjExplicitLod: + case spv::Op::OpImageSparseSampleProjDrefExplicitLod: + + case spv::Op::OpImage: + case spv::Op::OpImageFetch: + case spv::Op::OpImageSparseFetch: + case spv::Op::OpImageGather: + case spv::Op::OpImageDrefGather: + case spv::Op::OpImageSparseGather: + case spv::Op::OpImageSparseDrefGather: + case spv::Op::OpImageRead: + case spv::Op::OpImageSparseRead: + case spv::Op::OpImageWrite: + + case spv::Op::OpImageQueryFormat: + case spv::Op::OpImageQueryOrder: + case spv::Op::OpImageQuerySizeLod: + case spv::Op::OpImageQuerySize: + case spv::Op::OpImageQueryLod: + case spv::Op::OpImageQueryLevels: + case spv::Op::OpImageQuerySamples: + + case spv::Op::OpImageSampleWeightedQCOM: + case spv::Op::OpImageBoxFilterQCOM: + case spv::Op::OpImageBlockMatchSSDQCOM: + case spv::Op::OpImageBlockMatchSADQCOM: + return true; + default: + break; + } + return false; +} + +spv_result_t ValidateQCOMImageProcessingTextureUsages(ValidationState_t& _, + const Instruction* inst) { + const spv::Op opcode = inst->opcode(); + if (!IsImageInstruction(opcode)) return SPV_SUCCESS; + + switch (opcode) { + case spv::Op::OpImageSampleWeightedQCOM: + case spv::Op::OpImageBoxFilterQCOM: + case spv::Op::OpImageBlockMatchSSDQCOM: + case spv::Op::OpImageBlockMatchSADQCOM: + break; + default: + for (size_t i = 0; i < inst->operands().size(); ++i) { + int id = inst->GetOperandAs(i); + const Instruction* operand_inst = _.FindDef(id); + if (operand_inst == nullptr) continue; + if (operand_inst->opcode() == spv::Op::OpLoad) { + if (_.IsQCOMImageProcessingTextureConsumer(id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Illegal use of QCOM image processing decorated texture"; + } + } + if (operand_inst->opcode() == spv::Op::OpSampledImage) { + if (_.IsQCOMImageProcessingTextureConsumer(id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Illegal use of QCOM image processing decorated texture"; + } + } + } + break; + } + return SPV_SUCCESS; +} + } // namespace val } // namespace spvtools diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index ea6d084233..5b25eeb3c7 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -966,6 +966,8 @@ spv_result_t ValidateLoad(ValidationState_t& _, const Instruction* inst) { } } + _.RegisterQCOMImageProcessingTextureConsumer(pointer_id, inst, nullptr); + return SPV_SUCCESS; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 974a3c31b8..6685985b6e 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -611,6 +611,18 @@ void ValidationState_t::RegisterSampledImageConsumer(uint32_t sampled_image_id, sampled_image_consumers_[sampled_image_id].push_back(consumer); } +void ValidationState_t::RegisterQCOMImageProcessingTextureConsumer( + uint32_t texture_id, const Instruction* consumer0, + const Instruction* consumer1) { + if (HasDecoration(texture_id, spv::Decoration::WeightTextureQCOM) || + HasDecoration(texture_id, spv::Decoration::BlockMatchTextureQCOM)) { + qcom_image_processing_consumers_.insert(consumer0->id()); + if (consumer1) { + qcom_image_processing_consumers_.insert(consumer1->id()); + } + } +} + void ValidationState_t::RegisterStorageClassConsumer( spv::StorageClass storage_class, Instruction* consumer) { if (spvIsVulkanEnv(context()->target_env)) { @@ -668,39 +680,39 @@ void ValidationState_t::RegisterStorageClassConsumer( if (storage_class == spv::StorageClass::CallableDataKHR) { std::string errorVUID = VkErrorID(4704); function(consumer->function()->id()) - ->RegisterExecutionModelLimitation([errorVUID]( - spv::ExecutionModel model, - std::string* message) { - if (model != spv::ExecutionModel::RayGenerationKHR && - model != spv::ExecutionModel::ClosestHitKHR && - model != spv::ExecutionModel::CallableKHR && - model != spv::ExecutionModel::MissKHR) { - if (message) { - *message = errorVUID + - "CallableDataKHR Storage Class is limited to " - "RayGenerationKHR, ClosestHitKHR, CallableKHR, and " - "MissKHR execution model"; - } - return false; - } - return true; - }); + ->RegisterExecutionModelLimitation( + [errorVUID](spv::ExecutionModel model, std::string* message) { + if (model != spv::ExecutionModel::RayGenerationKHR && + model != spv::ExecutionModel::ClosestHitKHR && + model != spv::ExecutionModel::CallableKHR && + model != spv::ExecutionModel::MissKHR) { + if (message) { + *message = + errorVUID + + "CallableDataKHR Storage Class is limited to " + "RayGenerationKHR, ClosestHitKHR, CallableKHR, and " + "MissKHR execution model"; + } + return false; + } + return true; + }); } else if (storage_class == spv::StorageClass::IncomingCallableDataKHR) { std::string errorVUID = VkErrorID(4705); function(consumer->function()->id()) - ->RegisterExecutionModelLimitation([errorVUID]( - spv::ExecutionModel model, - std::string* message) { - if (model != spv::ExecutionModel::CallableKHR) { - if (message) { - *message = errorVUID + - "IncomingCallableDataKHR Storage Class is limited to " - "CallableKHR execution model"; - } - return false; - } - return true; - }); + ->RegisterExecutionModelLimitation( + [errorVUID](spv::ExecutionModel model, std::string* message) { + if (model != spv::ExecutionModel::CallableKHR) { + if (message) { + *message = + errorVUID + + "IncomingCallableDataKHR Storage Class is limited to " + "CallableKHR execution model"; + } + return false; + } + return true; + }); } else if (storage_class == spv::StorageClass::RayPayloadKHR) { std::string errorVUID = VkErrorID(4698); function(consumer->function()->id()) diff --git a/source/val/validation_state.h b/source/val/validation_state.h index 5ab6ac6021..0cd6c789bb 100644 --- a/source/val/validation_state.h +++ b/source/val/validation_state.h @@ -485,6 +485,13 @@ class ValidationState_t { void RegisterSampledImageConsumer(uint32_t sampled_image_id, Instruction* consumer); + // Record a cons_id as a consumer of texture_id + // if texture 'texture_id' has a QCOM image processing decoration + // and consumer is a load or a sampled image instruction + void RegisterQCOMImageProcessingTextureConsumer(uint32_t texture_id, + const Instruction* consumer0, + const Instruction* consumer1); + // Record a function's storage class consumer instruction void RegisterStorageClassConsumer(spv::StorageClass storage_class, Instruction* consumer); @@ -792,6 +799,13 @@ class ValidationState_t { current_layout_section_ = section; } + // Check if instruction 'id' is a consumer of a texture decorated + // with a QCOM image processing decoration + bool IsQCOMImageProcessingTextureConsumer(uint32_t id) { + return qcom_image_processing_consumers_.find(id) != + qcom_image_processing_consumers_.end(); + } + private: ValidationState_t(const ValidationState_t&); @@ -826,6 +840,10 @@ class ValidationState_t { std::unordered_map> sampled_image_consumers_; + /// Stores load instructions that load textures used + // in QCOM image processing functions + std::unordered_set qcom_image_processing_consumers_; + /// A map of operand IDs and their names defined by the OpName instruction std::unordered_map operand_names_; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 37c5e1d514..662c0bf4cb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -111,7 +111,6 @@ set(TEST_SOURCES hex_float_test.cpp immediate_int_test.cpp libspirv_macros_test.cpp - log_test.cpp named_id_test.cpp name_mapper_test.cpp opcode_make_test.cpp diff --git a/test/enum_set_test.cpp b/test/enum_set_test.cpp index 7a6e4caba1..11105f9918 100644 --- a/test/enum_set_test.cpp +++ b/test/enum_set_test.cpp @@ -277,7 +277,7 @@ constexpr std::array kCapabilities{ spv::Capability::GroupNonUniformRotateKHR, spv::Capability::AtomicFloat32AddEXT, spv::Capability::AtomicFloat64AddEXT, - spv::Capability::LongConstantCompositeINTEL, + spv::Capability::LongCompositesINTEL, spv::Capability::OptNoneINTEL, spv::Capability::AtomicFloat16AddEXT, spv::Capability::DebugInfoModuleINTEL, diff --git a/test/link/binary_version_test.cpp b/test/link/binary_version_test.cpp index 78da1aeced..384255a468 100644 --- a/test/link/binary_version_test.cpp +++ b/test/link/binary_version_test.cpp @@ -73,5 +73,21 @@ TEST_F(BinaryVersion, Mismatch) { "through 1) vs 1.5 (input module 2).")); } +TEST_F(BinaryVersion, UseHighest) { + // clang-format off + spvtest::Binaries binaries = { + CreateBinary(SPV_SPIRV_VERSION_WORD(1, 3)), + CreateBinary(SPV_SPIRV_VERSION_WORD(1, 5)), + }; + // clang-format on + LinkerOptions options; + options.SetUseHighestVersion(true); + spvtest::Binary linked_binary; + ASSERT_EQ(SPV_SUCCESS, Link(binaries, &linked_binary, options)) + << GetErrorMessage(); + EXPECT_THAT(GetErrorMessage(), std::string()); + EXPECT_EQ(SPV_SPIRV_VERSION_WORD(1, 5), linked_binary[1]); +} + } // namespace } // namespace spvtools diff --git a/test/log_test.cpp b/test/log_test.cpp deleted file mode 100644 index ec66aa1ece..0000000000 --- a/test/log_test.cpp +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2016 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. - -#include "source/opt/log.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace spvtools { -namespace { - -using ::testing::MatchesRegex; - -TEST(Log, Unimplemented) { - int invocation = 0; - auto consumer = [&invocation](spv_message_level_t level, const char* source, - const spv_position_t&, const char* message) { - ++invocation; - EXPECT_EQ(SPV_MSG_INTERNAL_ERROR, level); - EXPECT_THAT(source, MatchesRegex(".*log_test.cpp$")); - EXPECT_STREQ("unimplemented: the-ultimite-feature", message); - }; - - SPIRV_UNIMPLEMENTED(consumer, "the-ultimite-feature"); - EXPECT_EQ(1, invocation); -} - -TEST(Log, Unreachable) { - int invocation = 0; - auto consumer = [&invocation](spv_message_level_t level, const char* source, - const spv_position_t&, const char* message) { - ++invocation; - EXPECT_EQ(SPV_MSG_INTERNAL_ERROR, level); - EXPECT_THAT(source, MatchesRegex(".*log_test.cpp$")); - EXPECT_STREQ("unreachable", message); - }; - - SPIRV_UNREACHABLE(consumer); - EXPECT_EQ(1, invocation); -} - -} // namespace -} // namespace spvtools diff --git a/test/operand_capabilities_test.cpp b/test/operand_capabilities_test.cpp index 01b98a63ef..4872228170 100644 --- a/test/operand_capabilities_test.cpp +++ b/test/operand_capabilities_test.cpp @@ -18,7 +18,9 @@ #include #include "gmock/gmock.h" +#include "source/assembly_grammar.h" #include "source/enum_set.h" +#include "source/operand.h" #include "test/unit_spirv.h" namespace spvtools { @@ -31,12 +33,39 @@ using ::testing::TestWithParam; using ::testing::Values; using ::testing::ValuesIn; +// Emits a CapabilitySet to the given ostream, returning the ostream. +inline std::ostream& operator<<(std::ostream& out, const CapabilitySet& cs) { + out << "CapabilitySet{"; + auto ctx = spvContextCreate(SPV_ENV_UNIVERSAL_1_0); + spvtools::AssemblyGrammar grammar(ctx); + bool first = true; + for (auto c : cs) { + if (!first) { + out << " "; + first = false; + } + out << grammar.lookupOperandName(SPV_OPERAND_TYPE_CAPABILITY, uint32_t(c)) + << "(" << uint32_t(c) << ")"; + } + spvContextDestroy(ctx); + out << "}"; + return out; +} + // A test case for mapping an enum to a capability mask. struct EnumCapabilityCase { spv_operand_type_t type; uint32_t value; CapabilitySet expected_capabilities; }; +// Emits an EnumCapabilityCase to the ostream, returning the ostream. +inline std::ostream& operator<<(std::ostream& out, + const EnumCapabilityCase& ecc) { + out << "EnumCapabilityCase{ " << spvOperandTypeStr(ecc.type) << "(" + << unsigned(ecc.type) << "), " << ecc.value << ", " + << ecc.expected_capabilities << "}"; + return out; +} // Test fixture for testing EnumCapabilityCases. using EnumCapabilityTest = @@ -56,7 +85,7 @@ TEST_P(EnumCapabilityTest, Sample) { EXPECT_THAT(ElementsIn(cap_set), Eq(ElementsIn(std::get<1>(GetParam()).expected_capabilities))) - << " capability value " << std::get<1>(GetParam()).value; + << " enum value " << std::get<1>(GetParam()).value; spvContextDestroy(context); } @@ -237,25 +266,21 @@ INSTANTIATE_TEST_SUITE_P( SamplerAddressingMode, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ - CASE1(SAMPLER_ADDRESSING_MODE, SamplerAddressingMode::None, - Kernel), - CASE1(SAMPLER_ADDRESSING_MODE, - SamplerAddressingMode::ClampToEdge, Kernel), - CASE1(SAMPLER_ADDRESSING_MODE, SamplerAddressingMode::Clamp, - Kernel), - CASE1(SAMPLER_ADDRESSING_MODE, SamplerAddressingMode::Repeat, - Kernel), - CASE1(SAMPLER_ADDRESSING_MODE, - SamplerAddressingMode::RepeatMirrored, Kernel), - }))); + CASE0(SAMPLER_ADDRESSING_MODE, SamplerAddressingMode::None), + CASE0(SAMPLER_ADDRESSING_MODE, + SamplerAddressingMode::ClampToEdge), + CASE0(SAMPLER_ADDRESSING_MODE, SamplerAddressingMode::Clamp), + CASE0(SAMPLER_ADDRESSING_MODE, SamplerAddressingMode::Repeat), + CASE0(SAMPLER_ADDRESSING_MODE, + SamplerAddressingMode::RepeatMirrored)}))); // See SPIR-V Section 3.10 Sampler Filter Mode INSTANTIATE_TEST_SUITE_P( SamplerFilterMode, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ - CASE1(SAMPLER_FILTER_MODE, SamplerFilterMode::Nearest, Kernel), - CASE1(SAMPLER_FILTER_MODE, SamplerFilterMode::Linear, Kernel), + CASE0(SAMPLER_FILTER_MODE, SamplerFilterMode::Nearest), + CASE0(SAMPLER_FILTER_MODE, SamplerFilterMode::Linear), }))); // See SPIR-V Section 3.11 Image Format @@ -417,7 +442,7 @@ INSTANTIATE_TEST_SUITE_P( // See SPIR-V Section 3.20 Decoration INSTANTIATE_TEST_SUITE_P( - Decoration, EnumCapabilityTest, + Decoration_1_1, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ CASE1(DECORATION, Decoration::RelaxedPrecision, Shader), @@ -469,6 +494,13 @@ INSTANTIATE_TEST_SUITE_P( CASE1(DECORATION, Decoration::Alignment, Kernel), }))); +// See SPIR-V Section 3.20 Decoration +INSTANTIATE_TEST_SUITE_P(Decoration_1_6, EnumCapabilityTest, + Combine(Values(SPV_ENV_UNIVERSAL_1_6), + ValuesIn(std::vector{ + CASE2(DECORATION, Decoration::Uniform, + Shader, UniformDecoration)}))); + #if 0 // SpecId has different requirements in v1.0 and v1.1: INSTANTIATE_TEST_SUITE_P(DecorationSpecIdV10, EnumCapabilityTest, diff --git a/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt index 432a17d092..ceada132b3 100644 --- a/test/opt/CMakeLists.txt +++ b/test/opt/CMakeLists.txt @@ -66,6 +66,7 @@ add_spvtools_unittest(TARGET opt instruction_list_test.cpp instruction_test.cpp interface_var_sroa_test.cpp + invocation_interlock_placement_test.cpp interp_fixup_test.cpp ir_builder.cpp ir_context_test.cpp @@ -103,6 +104,7 @@ add_spvtools_unittest(TARGET opt strip_debug_info_test.cpp strip_nonsemantic_info_test.cpp struct_cfg_analysis_test.cpp + switch_descriptorset_test.cpp trim_capabilities_pass_test.cpp type_manager_test.cpp types_test.cpp diff --git a/test/opt/aggressive_dead_code_elim_test.cpp b/test/opt/aggressive_dead_code_elim_test.cpp index f8f15b6cc4..845c6a5886 100644 --- a/test/opt/aggressive_dead_code_elim_test.cpp +++ b/test/opt/aggressive_dead_code_elim_test.cpp @@ -6764,7 +6764,7 @@ TEST_F(AggressiveDCETest, ShaderDebugInfoKeepInFunctionElimStoreVar) { %60 = OpExtInst %void %1 DebugTypeVector %59 %uint_4 %58 = OpExtInst %void %1 DebugTypeMember %10 %60 %55 %uint_12 %uint_5 %uint_0 %uint_128 %uint_3 %57 = OpExtInst %void %1 DebugTypeComposite %8 %uint_1 %55 %uint_10 %uint_1 %56 %8 %uint_128 %uint_3 %58 - %63 = OpExtInst %void %1 DebugTypeVector %59 %uint_2 + %63 = OpExtInst %void %1 DebugTypeVector %59 %uint_2 %62 = OpExtInst %void %1 DebugTypeMember %12 %63 %55 %uint_7 %uint_5 %uint_0 %uint_64 %uint_3 %61 = OpExtInst %void %1 DebugTypeComposite %11 %uint_1 %55 %uint_5 %uint_1 %56 %11 %uint_64 %uint_3 %62 %64 = OpExtInst %void %1 DebugTypeComposite %13 %uint_0 %55 %uint_0 %uint_0 %56 %14 %51 %uint_3 @@ -7949,6 +7949,49 @@ TEST_F(AggressiveDCETest, FunctionReturnPointer) { SinglePassRunAndMatch(text, true); } +TEST_F(AggressiveDCETest, KeepBeginEndInvocationInterlock) { + // OpBeginInvocationInterlockEXT and OpEndInvocationInterlockEXT delimit a + // critical section. As such, they should be treated as if they have side + // effects and should not be removed. + const std::string test = + R"(OpCapability Shader +OpCapability FragmentShaderSampleInterlockEXT +OpExtension "SPV_EXT_fragment_shader_interlock" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "main" %gl_FragCoord +OpExecutionMode %1 OriginUpperLeft +OpExecutionMode %1 SampleInterlockOrderedEXT +OpDecorate %gl_FragCoord BuiltIn FragCoord +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%void = OpTypeVoid +%8 = OpTypeFunction %void +%bool = OpTypeBool +%gl_FragCoord = OpVariable %_ptr_Input_v4float Input +%1 = OpFunction %void None %8 +%10 = OpLabel +%11 = OpLoad %v4float %gl_FragCoord +%12 = OpCompositeExtract %float %11 0 +%13 = OpFOrdGreaterThan %bool %12 %float_0 +OpSelectionMerge %14 None +OpBranchConditional %13 %15 %16 +%15 = OpLabel +OpBeginInvocationInterlockEXT +OpBranch %14 +%16 = OpLabel +OpBeginInvocationInterlockEXT +OpBranch %14 +%14 = OpLabel +OpEndInvocationInterlockEXT +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(test, test, true, true); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/test/opt/dead_insert_elim_test.cpp b/test/opt/dead_insert_elim_test.cpp index 268e659063..fcc3dde48d 100644 --- a/test/opt/dead_insert_elim_test.cpp +++ b/test/opt/dead_insert_elim_test.cpp @@ -736,6 +736,113 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } +TEST_F(DeadInsertElimTest, PhiOverEmptyStruct) { + // Reproducer for nullptr access error in MarkInsertChain + // that occurs when processing a phi operation with an + // empty struct result type. + // + // Note: Disassembly created from HLSL source with + // dxc -T cs_6_6 -spirv -Oconfig= + // --eliminate-dead-branches,--merge-return,--ssa-rewrite + // + // RWBuffer buf; + // + // struct S { }; + // + // S fn() { + // S s = (S)0; + // if (buf[0] > 0) { + // return s; + // } + // return s; + // } + // + // [numthreads(1,1,1)] + // void main() { + // fn(); + // } + + const std::string disassembly = + R"(OpCapability Shader + OpCapability SampledBuffer + OpCapability ImageBuffer + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource HLSL 660 + OpName %S "S" + OpName %type_buffer_image "type.buffer.image" + OpName %buf "buf" + OpName %main "main" + OpName %src_main "src.main" + OpName %bb_entry "bb.entry" + OpName %fn "fn" + OpName %bb_entry_0 "bb.entry" + OpName %s "s" + OpName %if_true "if.true" + OpName %if_merge "if.merge" + OpDecorate %buf DescriptorSet 0 + OpDecorate %buf Binding 0 + %S = OpTypeStruct + %4 = OpConstantNull %S + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %float = OpTypeFloat 32 + %float_0 = OpConstant %float 0 +%type_buffer_image = OpTypeImage %float Buffer 2 0 0 2 R32f +%_ptr_UniformConstant_type_buffer_image = OpTypePointer UniformConstant %type_buffer_image + %void = OpTypeVoid + %12 = OpTypeFunction %void + %19 = OpTypeFunction %S +%_ptr_Function_S = OpTypePointer Function %S + %v4float = OpTypeVector %float 4 + %bool = OpTypeBool + %buf = OpVariable %_ptr_UniformConstant_type_buffer_image UniformConstant + %false = OpConstantFalse %bool +%_ptr_Function_bool = OpTypePointer Function %bool + %true = OpConstantTrue %bool + %main = OpFunction %void None %12 + %13 = OpLabel + %14 = OpFunctionCall %void %src_main + OpReturn + OpFunctionEnd + %src_main = OpFunction %void None %12 + %bb_entry = OpLabel + %17 = OpFunctionCall %S %fn + OpReturn + OpFunctionEnd + %fn = OpFunction %S None %19 + %bb_entry_0 = OpLabel + %39 = OpVariable %_ptr_Function_bool Function %false + %34 = OpVariable %_ptr_Function_S Function + %s = OpVariable %_ptr_Function_S Function + OpSelectionMerge %33 None + OpSwitch %uint_0 %36 + %36 = OpLabel + OpStore %s %4 + %23 = OpLoad %type_buffer_image %buf + %25 = OpImageRead %v4float %23 %uint_0 None + %26 = OpCompositeExtract %float %25 0 + %28 = OpFOrdGreaterThan %bool %26 %float_0 + OpSelectionMerge %if_merge None + OpBranchConditional %28 %if_true %if_merge + %if_true = OpLabel + OpStore %39 %true + OpStore %34 %4 + OpBranch %33 + %if_merge = OpLabel + OpStore %39 %true + OpStore %34 %4 + OpBranch %33 + %33 = OpLabel + %41 = OpPhi %S %4 %if_true %4 %if_merge + OpReturnValue %41 + OpFunctionEnd +)"; + // Used to crash with a nullptr access violation when processing %41 + SinglePassRunToBinary(disassembly, true); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // diff --git a/test/opt/fix_storage_class_test.cpp b/test/opt/fix_storage_class_test.cpp index 93ce873605..684e006eca 100644 --- a/test/opt/fix_storage_class_test.cpp +++ b/test/opt/fix_storage_class_test.cpp @@ -874,6 +874,47 @@ TEST_F(FixTypeTest, FixPhiInLoop) { SinglePassRunAndMatch(text, false); } +TEST_F(FixStorageClassTest, SupportsU64Index) { + const std::string text = R"( +; CHECK: OpAccessChain %_ptr_Uniform_float + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "testMain" %gl_LocalInvocationID + OpExecutionMode %1 LocalSize 8 8 1 + OpDecorate %gl_LocalInvocationID BuiltIn LocalInvocationId + OpDecorate %8 DescriptorSet 0 + OpDecorate %8 Binding 0 + OpDecorate %_runtimearr_float ArrayStride 4 + OpMemberDecorate %_struct_7 0 Offset 0 + OpDecorate %_struct_7 BufferBlock + %ulong = OpTypeInt 64 0 + %ulong_0 = OpConstant %ulong 0 + %float = OpTypeFloat 32 + %float_123 = OpConstant %float 123 + %uint = OpTypeInt 32 0 + %uint_10 = OpConstant %uint 10 +%_runtimearr_float = OpTypeRuntimeArray %float + %_struct_7 = OpTypeStruct %_runtimearr_float +%_ptr_Uniform__struct_7 = OpTypePointer Uniform %_struct_7 + %v3uint = OpTypeVector %uint 3 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint + %void = OpTypeVoid + %30 = OpTypeFunction %void +%_ptr_Uniform_float = OpTypePointer Uniform %float + %8 = OpVariable %_ptr_Uniform__struct_7 Uniform +%gl_LocalInvocationID = OpVariable %_ptr_Input_v3uint Input + %1 = OpFunction %void None %30 + %38 = OpLabel + %44 = OpLoad %v3uint %gl_LocalInvocationID + %59 = OpCompositeExtract %uint %44 0 + %60 = OpAccessChain %_ptr_Uniform_float %8 %ulong_0 %59 + OpStore %60 %float_123 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} } // namespace } // namespace opt diff --git a/test/opt/fold_spec_const_op_composite_test.cpp b/test/opt/fold_spec_const_op_composite_test.cpp index f83e86e961..70ba362056 100644 --- a/test/opt/fold_spec_const_op_composite_test.cpp +++ b/test/opt/fold_spec_const_op_composite_test.cpp @@ -674,6 +674,31 @@ TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, CompositeInsertMatrixNull) { SinglePassRunAndMatch(test, false); } +// Silently ignore spec constants that cannot be folded +TEST_F(FoldSpecConstantOpAndCompositePassBasicTest, UnfoldableOp) { + const std::string test = R"( + OpCapability Shader + OpCapability SignedZeroInfNanPreserve + OpExtension "SPV_KHR_float_controls" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpSource GLSL 450 + OpDecorate %v SpecId 1 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v = OpConstant %float 0x1p-1 +%c = OpSpecConstantOp %float QuantizeToF16 %v +;CHECK: {{%\w+}} = OpSpecConstantOp {{%\w+}} QuantizeToF16 {{%\w+}} + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(test, false); +} + // All types and some common constants that are potentially required in // FoldSpecConstantOpAndCompositeTest. std::vector CommonTypesAndConstants() { diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index c5adf6dd1c..a837597a55 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -176,6 +176,8 @@ OpName %main "main" %_ptr_struct_v2int_int_int = OpTypePointer Function %struct_v2int_int_int %_ptr_v2float = OpTypePointer Function %v2float %_ptr_v2double = OpTypePointer Function %v2double +%int_2 = OpConstant %int 2 +%int_arr_2 = OpTypeArray %int %int_2 %short_0 = OpConstant %short 0 %short_2 = OpConstant %short 2 %short_3 = OpConstant %short 3 @@ -185,7 +187,6 @@ OpName %main "main" %103 = OpConstant %int 7 ; Need a def with an numerical id to define id maps. %int_0 = OpConstant %int 0 %int_1 = OpConstant %int 1 -%int_2 = OpConstant %int 2 %int_3 = OpConstant %int 3 %int_4 = OpConstant %int 4 %int_10 = OpConstant %int 10 @@ -323,6 +324,7 @@ OpName %main "main" %short_0x4400 = OpConstant %short 0x4400 %ushort_0xBC00 = OpConstant %ushort 0xBC00 %short_0xBC00 = OpConstant %short 0xBC00 +%int_arr_2_undef = OpUndef %int_arr_2 )"; return header; @@ -7648,7 +7650,24 @@ ::testing::Values( "%4 = OpCompositeExtract %int %struct_v2int_int_int 3\n" + "OpReturn\n" + "OpFunctionEnd", - 4, false) + 4, false), + // Test case 18: Fold when every element of an array is inserted. + InstructionFoldingCase( + Header() + + "; CHECK: [[int:%\\w+]] = OpTypeInt 32 1\n" + + "; CHECK: [[int2:%\\w+]] = OpConstant [[int]] 2\n" + + "; CHECK-DAG: [[arr_type:%\\w+]] = OpTypeArray [[int]] [[int2]]\n" + + "; CHECK-DAG: [[int10:%\\w+]] = OpConstant [[int]] 10\n" + + "; CHECK-DAG: [[int1:%\\w+]] = OpConstant [[int]] 1\n" + + "; CHECK: [[construct:%\\w+]] = OpCompositeConstruct [[arr_type]] [[int10]] [[int1]]\n" + + "; CHECK: %5 = OpCopyObject [[arr_type]] [[construct]]\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%4 = OpCompositeInsert %int_arr_2 %int_10 %int_arr_2_undef 0\n" + + "%5 = OpCompositeInsert %int_arr_2 %int_1 %4 1\n" + + "OpReturn\n" + + "OpFunctionEnd", + 5, true) )); INSTANTIATE_TEST_SUITE_P(DotProductMatchingTest, MatchingInstructionFoldingTest, diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp index 1c192c4366..08da367fd5 100644 --- a/test/opt/inst_bindless_check_test.cpp +++ b/test/opt/inst_bindless_check_test.cpp @@ -27,243 +27,16 @@ namespace { using InstBindlessTest = PassTest<::testing::Test>; -static const std::string kOutputDecorations = R"( -; CHECK: OpDecorate [[output_buffer_type:%inst_bindless_OutputBuffer]] Block -; CHECK: OpMemberDecorate [[output_buffer_type]] 0 Offset 0 -; CHECK: OpMemberDecorate [[output_buffer_type]] 1 Offset 4 -; CHECK: OpDecorate [[output_buffer_var:%\w+]] DescriptorSet 7 -; CHECK: OpDecorate [[output_buffer_var]] Binding 0 -)"; - -static const std::string kOutputGlobals = R"( -; CHECK: [[output_buffer_type]] = OpTypeStruct %uint %uint %_runtimearr_uint -; CHECK: [[output_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[output_buffer_type]] -; CHECK: [[output_buffer_var]] = OpVariable [[output_ptr_type]] StorageBuffer -)"; - -static const std::string kStreamWrite6 = R"( -; CHECK: %inst_bindless_stream_write_6 = OpFunction %void None {{%\w+}} -; CHECK: [[sw_shader_id:%\w+]] = OpFunctionParameter %uint -; CHECK: [[sw_inst_idx:%\w+]] = OpFunctionParameter %uint -; CHECK: [[sw_stage_info:%\w+]] = OpFunctionParameter %v4uint -; CHECK: [[sw_param_1:%\w+]] = OpFunctionParameter %uint -; CHECK: [[sw_param_2:%\w+]] = OpFunctionParameter %uint -; CHECK: [[sw_param_3:%\w+]] = OpFunctionParameter %uint -; CHECK: [[sw_param_4:%\w+]] = OpFunctionParameter %uint -; CHECK: [[sw_param_5:%\w+]] = OpFunctionParameter %uint -; CHECK: [[sw_param_6:%\w+]] = OpFunctionParameter %uint -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 -; CHECK: {{%\w+}} = OpAtomicIAdd %uint {{%\w+}} %uint_4 %uint_0 %uint_13 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_13 -; CHECK: {{%\w+}} = OpArrayLength %uint [[output_buffer_var]] 2 -; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} %uint_13 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[sw_shader_id]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_2 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[sw_inst_idx]] -; CHECK: {{%\w+}} = OpCompositeExtract %uint [[sw_stage_info]] 0 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint [[sw_stage_info]] 1 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint [[sw_stage_info]] 2 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint [[sw_stage_info]] 3 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[sw_param_1]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[sw_param_2]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_9 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[sw_param_3]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[sw_param_4]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_11 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[sw_param_5]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_12 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[sw_param_6]] -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpReturn -; CHECK: OpFunctionEnd -)"; -// clang-format on - -static const std::string kInputDecorations = R"( -; CHECK: OpDecorate [[desc_set_struct:%inst_bindless_DescriptorSetData]] Block -; CHECK: OpMemberDecorate [[desc_set_struct]] 0 Offset 0 -; CHECK: OpMemberDecorate [[desc_set_struct]] 1 Offset 4 -; CHECK: OpDecorate [[input_buffer_type:%inst_bindless_InputBuffer]] Block -; CHECK: OpMemberDecorate [[input_buffer_type]] 0 Offset 0 -; CHECK: OpDecorate [[input_buffer_var:%\w+]] DescriptorSet 7 -; CHECK: OpDecorate [[input_buffer_var]] Binding 1 -)"; +static const std::string kFuncName = "inst_bindless_check_desc"; -static const std::string kInputGlobals = R"( -; CHECK: [[desc_set_struct]] = OpTypeStruct %uint %_runtimearr_uint -; CHECK: [[desc_set_ptr:%\w+]] = OpTypePointer PhysicalStorageBuffer [[desc_set_struct]] -; CHECK: [[desc_set_ptr_array:%\w+]] = OpTypeArray [[desc_set_ptr]] %uint_32 -; CHECK: [[input_buffer_type]] = OpTypeStruct [[desc_set_ptr_array]] -; CHECK: [[input_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[input_buffer_type]] -; CHECK: [[input_buffer_var]] = OpVariable [[input_ptr_type]] StorageBuffer +static const std::string kImportDeco = R"( +;CHECK: OpDecorate %)" + kFuncName + R"( LinkageAttributes ")" + + kFuncName + R"(" Import )"; -static const std::string kCheckDesc = R"( -; CHECK: %inst_bindless_desc_check = OpFunction %bool None {{%\w+}} -; CHECK: [[di_shader_id:%\w+]] = OpFunctionParameter %uint -; CHECK: [[di_line:%\w+]] = OpFunctionParameter %uint -; CHECK: [[di_stage_info:%\w+]] = OpFunctionParameter %v4uint -; CHECK: [[di_desc_set:%\w+]] = OpFunctionParameter %uint -; CHECK: [[di_binding:%\w+]] = OpFunctionParameter %uint -; CHECK: [[di_desc_idx:%\w+]] = OpFunctionParameter %uint -; CHECK: [[di_byte_offset:%\w+]] = OpFunctionParameter %uint -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[di_error:%\w+]] = OpVariable %_ptr_Function_uint Function %uint_0 -; CHECK: [[di_param5:%\w+]] = OpVariable %_ptr_Function_uint Function %uint_0 -; CHECK: [[di_param6:%\w+]] = OpVariable %_ptr_Function_uint Function %uint_0 -; CHECK: [[di_num_bindings:%\w+]] = OpVariable %_ptr_Function_uint Function %uint_0 -; CHECK: [[di_init_status:%\w+]] = OpVariable %_ptr_Function_uint Function %uint_0 -; CHECK: [[di_desc_set_ptr:%\w+]] = OpVariable %_ptr_Function__ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData Function -; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_desc_set]] %uint_32 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpStore [[di_error]] %uint_1 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint [[di_error]] -; CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData %inst_bindless_input_buffer %uint_0 [[di_desc_set]] -; CHECK: {{%\w+}} = OpLoad %_ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData {{%\w+}} -; CHECK: OpStore [[di_desc_set_ptr]] {{%\w+}} -; CHECK: {{%\w+}} = OpBitcast %v2uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpLogicalAnd %bool {{%\w+}} {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpStore [[di_error]] %uint_1 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint [[di_error]] -; CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %_ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData [[di_desc_set_ptr]] -; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 8 -; CHECK: OpStore [[di_num_bindings]] {{%\w+}} -; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_binding]] {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpStore [[di_error]] %uint_1 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint [[di_error]] -; CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %_ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData [[di_desc_set_ptr]] -; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 [[di_binding]] -; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 4 -; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_desc_idx]] {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpStore [[di_error]] %uint_1 -; CHECK: OpStore [[di_param5]] {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint [[di_error]] -; CHECK: {{%\w+}} = OpLoad %uint [[di_error]] -; CHECK: {{%\w+}} = OpIEqual %bool %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %_ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData [[di_desc_set_ptr]] -; CHECK: {{%\w+}} = OpLoad %uint [[di_num_bindings]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} [[di_binding]] -; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 4 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} [[di_desc_idx]] -; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 4 -; CHECK: OpStore [[di_init_status]] {{%\w+}} -; CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpStore [[di_error]] %uint_2 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint [[di_error]] -; CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint [[di_init_status]] -; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_byte_offset]] {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpStore [[di_error]] %uint_4 -; CHECK: OpStore [[di_param5]] [[di_byte_offset]] -; CHECK: OpStore [[di_param6]] {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint [[di_error]] -; CHECK: {{%\w+}} = OpINotEqual %bool %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint [[di_param5]] -; CHECK: {{%\w+}} = OpLoad %uint [[di_param6]] -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 [[di_shader_id]] [[di_line]] [[di_stage_info]] {{%\w+}} [[di_desc_set]] [[di_binding]] [[di_desc_idx]] {{%\w+}} {{%\w+}} -; CHECK: OpReturnValue %false -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpReturnValue %true -; CHECK: OpFunctionEnd +static const std::string kImportStub = R"( +;CHECK: %)" + kFuncName + R"( = OpFunction %bool None {{%\w+}} +;CHECK: OpFunctionEnd )"; TEST_F(InstBindlessTest, Simple) { @@ -296,11 +69,11 @@ TEST_F(InstBindlessTest, Simple) { const std::string entry = R"( OpCapability Shader -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" +;CHECK: OpCapability Linkage %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor -; CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord OpExecutionMode %MainPs OriginUpperLeft OpSource HLSL 500 )"; @@ -321,10 +94,10 @@ OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 OpDecorate %PerViewConstantBuffer_t Block OpDecorate %g_sAniso DescriptorSet 0 OpDecorate %i_vTextureCoords Location 0 -OpDecorate %_entryPointOutput_vColor Location 0 -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +OpDecorate %_entryPointOutput_vColor Location 0)" ++ kImportDeco + +R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord )"; const std::string consts_types_vars = R"( @@ -354,14 +127,10 @@ OpDecorate %_entryPointOutput_vColor Location 0 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kOutputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; - // clang-format on const std::string main_func = R"( %MainPs = OpFunction %void None %10 @@ -375,31 +144,30 @@ OpDecorate %_entryPointOutput_vColor Location 0 %36 = OpSampledImage %26 %34 %35 %37 = OpImageSampleImplicitLod %v4float %36 %30 OpStore %_entryPointOutput_vColor %37 -; CHECK-NOT: %37 = OpImageSampleImplicitLod %v4float %36 %30 -; CHECK-NOT: OpStore %_entryPointOutput_vColor %37 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_57 {{%\w+}} %uint_3 %uint_0 %32 %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %16 %33 -; CHECK: {{%\w+}} = OpSampledImage %26 {{%\w+}} %35 -; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %30 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: OpStore %_entryPointOutput_vColor [[phi_result]] +;CHECK-NOT: %37 = OpImageSampleImplicitLod %v4float %36 %30 +;CHECK-NOT: OpStore %_entryPointOutput_vColor %37 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_57 {{%\w+}} %uint_3 %uint_0 %32 %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %16 %33 +;CHECK: {{%\w+}} = OpSampledImage %26 {{%\w+}} %35 +;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %30 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK: OpStore %_entryPointOutput_vColor [[phi_result]] OpReturn OpFunctionEnd )"; - - const std::string output_func = kStreamWrite6 + kCheckDesc; + // clang-format on SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch( - entry + names_annots + consts_types_vars + main_func + output_func, true, - 7u, 23u); + SinglePassRunAndMatch( + entry + names_annots + consts_types_vars + kImportStub + main_func, true, + 23u); } TEST_F(InstBindlessTest, InstrumentMultipleInstructions) { @@ -436,11 +204,11 @@ TEST_F(InstBindlessTest, InstrumentMultipleInstructions) { // clang-format off const std::string defs = R"( OpCapability Shader -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" +OpCapability Linkage %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor -; CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord OpExecutionMode %MainPs OriginUpperLeft OpSource HLSL 500 OpName %MainPs "MainPs" @@ -459,9 +227,8 @@ OpDecorate %PerViewConstantBuffer_t Block OpDecorate %g_sAniso DescriptorSet 3 OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %10 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -489,18 +256,14 @@ OpDecorate %_entryPointOutput_vColor Location 0 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -; CHECK: %v4uint = OpTypeVector %uint 4 -)" + kOutputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: %v4uint = OpTypeVector %uint 4 +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; - // clang-format on - const std::string main_func = - R"(%MainPs = OpFunction %void None %10 + const std::string main_func = R"( +%MainPs = OpFunction %void None %10 %30 = OpLabel %31 = OpLoad %v2float %i_vTextureCoords %32 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 @@ -510,24 +273,24 @@ OpDecorate %_entryPointOutput_vColor Location 0 %36 = OpLoad %25 %g_sAniso %37 = OpSampledImage %27 %35 %36 %38 = OpImageSampleImplicitLod %v4float %37 %31 -; CHECK-NOT: %38 = OpImageSampleImplicitLod %v4float %37 %31 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_59 {{%\w+}} %uint_3 %uint_4 %33 %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %17 %34 -; CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %36 -; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %31 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK-NOT: %38 = OpImageSampleImplicitLod %v4float %37 %31 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_60 {{%\w+}} %uint_3 %uint_4 %33 %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %17 %34 +;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %36 +;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %31 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} %39 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1 %40 = OpLoad %uint %39 %41 = OpAccessChain %_ptr_UniformConstant_17 %g_tColor %40 @@ -535,36 +298,35 @@ OpDecorate %_entryPointOutput_vColor Location 0 %43 = OpSampledImage %27 %42 %36 %44 = OpImageSampleImplicitLod %v4float %43 %31 %45 = OpFAdd %v4float %38 %44 -; CHECK-NOT: %44 = OpImageSampleImplicitLod %v4float %43 %31 -; CHECK-NOT: %45 = OpFAdd %v4float %38 %44 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_65 {{%\w+}} %uint_3 %uint_4 %40 %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %17 %41 -; CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %36 -; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %31 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: %45 = OpFAdd %v4float {{%\w+}} {{%\w+}} +;CHECK-NOT: %44 = OpImageSampleImplicitLod %v4float %43 %31 +;CHECK-NOT: %45 = OpFAdd %v4float %38 %44 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_66 {{%\w+}} %uint_3 %uint_4 %40 %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %17 %41 +;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %36 +;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %31 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK: %45 = OpFAdd %v4float {{%\w+}} {{%\w+}} OpStore %_entryPointOutput_vColor %45 OpReturn OpFunctionEnd )"; - - const std::string output_func = kStreamWrite6 + kCheckDesc; + // clang-format on SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + output_func, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, InstrumentOpImage) { @@ -576,11 +338,11 @@ TEST_F(InstBindlessTest, InstrumentOpImage) { const std::string defs = R"( OpCapability Shader OpCapability StorageImageReadWithoutFormat -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" +;CHECK: OpCapability Linkage %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor -; CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord OpExecutionMode %MainPs OriginUpperLeft OpSource HLSL 500 OpName %MainPs "MainPs" @@ -596,9 +358,8 @@ OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 OpDecorate %PerViewConstantBuffer_t Block OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -622,14 +383,10 @@ OpDecorate %_entryPointOutput_vColor Location 0 %i_vTextureCoords = OpVariable %_ptr_Input_v2int Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; - // clang-format on const std::string main_func = R"( %MainPs = OpFunction %void None %3 @@ -642,35 +399,34 @@ OpDecorate %_entryPointOutput_vColor Location 0 %75 = OpImage %20 %66 %71 = OpImageRead %v4float %75 %53 OpStore %_entryPointOutput_vColor %71 -; CHECK-NOT: %71 = OpImageRead %v4float %75 %53 -; CHECK-NOT: OpStore %_entryPointOutput_vColor %71 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_52 {{%\w+}} %uint_3 %uint_9 %64 %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %39 %65 -; CHECK: {{%\w+}} = OpImage %20 {{%\w+}} -; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %53 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: OpStore %_entryPointOutput_vColor {{%\w+}} +;CHECK-NOT: %71 = OpImageRead %v4float %75 %53 +;CHECK-NOT: OpStore %_entryPointOutput_vColor %71 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_3 %uint_9 %64 %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %39 %65 +;CHECK: {{%\w+}} = OpImage %20 {{%\w+}} +;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %53 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK: OpStore %_entryPointOutput_vColor {{%\w+}} OpReturn OpFunctionEnd )"; - - const std::string output_func = kStreamWrite6 + kCheckDesc; + // clang-format on SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + output_func, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, InstrumentSampledImage) { @@ -681,11 +437,11 @@ TEST_F(InstBindlessTest, InstrumentSampledImage) { // clang-format off const std::string defs = R"( OpCapability Shader -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" +;CHECK: OpCapability Linkage %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor -; CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord OpExecutionMode %MainPs OriginUpperLeft OpSource HLSL 500 OpName %MainPs "MainPs" @@ -701,8 +457,8 @@ OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 OpDecorate %PerViewConstantBuffer_t Block OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -726,14 +482,10 @@ OpDecorate %_entryPointOutput_vColor Location 0 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; - // clang-format on const std::string main_func = R"( %MainPs = OpFunction %void None %3 @@ -745,34 +497,33 @@ OpDecorate %_entryPointOutput_vColor Location 0 %66 = OpLoad %39 %65 %71 = OpImageSampleImplicitLod %v4float %66 %53 OpStore %_entryPointOutput_vColor %71 -; CHECK-NOT: %71 = OpImageSampleImplicitLod %v4float %66 %53 -; CHECK-NOT: OpStore %_entryPointOutput_vColor %71 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_50 {{%\w+}} %uint_4 %uint_11 %64 %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %39 %65 -; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %53 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: OpStore %_entryPointOutput_vColor {{%\w+}} +;CHECK-NOT: %71 = OpImageSampleImplicitLod %v4float %66 %53 +;CHECK-NOT: OpStore %_entryPointOutput_vColor %71 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_50 {{%\w+}} %uint_4 %uint_11 %64 %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %39 %65 +;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %53 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK: OpStore %_entryPointOutput_vColor {{%\w+}} OpReturn OpFunctionEnd )"; - - const std::string output_func = kStreamWrite6 + kCheckDesc; + // clang-format on SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + output_func, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, InstrumentImageWrite) { @@ -784,11 +535,11 @@ TEST_F(InstBindlessTest, InstrumentImageWrite) { const std::string defs = R"( OpCapability Shader OpCapability StorageImageWriteWithoutFormat -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" +;CHECK: OpCapability Linkage %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor -; CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord OpExecutionMode %MainPs OriginUpperLeft OpSource HLSL 500 OpName %MainPs "MainPs" @@ -804,9 +555,8 @@ OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 OpDecorate %PerViewConstantBuffer_t Block OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -831,14 +581,10 @@ OpDecorate %_entryPointOutput_vColor Location 0 %i_vTextureCoords = OpVariable %_ptr_Input_v2int Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -)" + kInputGlobals + R"( -; CHECK: %v4uint = OpTypeVector %uint 4 -)" + kOutputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: %v4uint = OpTypeVector %uint 4 +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input )"; - // clang-format on const std::string main_func = R"( %MainPs = OpFunction %void None %3 @@ -850,34 +596,33 @@ OpDecorate %_entryPointOutput_vColor Location 0 %66 = OpLoad %20 %65 OpImageWrite %66 %53 %80 OpStore %_entryPointOutput_vColor %80 -; CHECK-NOT: OpImageWrite %66 %53 %80 -; CHECK-NOT: OpStore %_entryPointOutput_vColor %80 -; CHECK: %32 = OpLoad %16 %31 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_52 {{%\w+}} %uint_30 %uint_2 %30 %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %16 %31 -; CHECK: OpImageWrite {{%\w+}} %28 %19 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpStore %_entryPointOutput_vColor %19 +;CHECK-NOT: OpImageWrite %66 %53 %80 +;CHECK-NOT: OpStore %_entryPointOutput_vColor %80 +;CHECK: %32 = OpLoad %16 %31 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_30 %uint_2 %30 %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %16 %31 +;CHECK: OpImageWrite {{%\w+}} %28 %19 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpStore %_entryPointOutput_vColor %19 OpReturn OpFunctionEnd )"; - - const std::string output_func = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + output_func, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, InstrumentVertexSimple) { @@ -889,7 +634,7 @@ TEST_F(InstBindlessTest, InstrumentVertexSimple) { const std::string defs = R"( OpCapability Shader OpCapability Sampled1D -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" +;CHECK: OpCapability Linkage %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Vertex %main "main" %_ %coords2D @@ -908,10 +653,9 @@ OpName %foo "foo" OpMemberName %foo 0 "g_idx" OpName %__0 "" OpName %coords2D "coords2D" -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex -; CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex +;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex OpMemberDecorate %gl_PerVertex 0 BuiltIn Position OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance @@ -954,15 +698,11 @@ OpDecorate %coords2D Location 0 %v2float = OpTypeVector %float 2 %_ptr_Input_v2float = OpTypePointer Input %v2float %coords2D = OpVariable %_ptr_Input_v2float Input -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %_ptr_Input_uint = OpTypePointer Input %uint -; CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_uint Input -; CHECK: %gl_InstanceIndex = OpVariable %_ptr_Input_uint Input -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: %_ptr_Input_uint = OpTypePointer Input %uint +;CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_uint Input +;CHECK: %gl_InstanceIndex = OpVariable %_ptr_Input_uint Input +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; - // clang-format on const std::string main_func = R"( %main = OpFunction %void None %3 @@ -980,52 +720,51 @@ OpStore %coords1D %float_1_78900003 %38 = OpImageSampleExplicitLod %v4float %35 %36 Lod %37 %40 = OpAccessChain %_ptr_Output_v4float %_ %int_0 OpStore %40 %38 -; CHECK-NOT: %38 = OpImageSampleExplicitLod %v4float %35 %36 Lod %37 -; CHECK-NOT: %40 = OpAccessChain %_ptr_Output_v4float %_ %int_0 -; CHECK-NOT: OpStore %40 %38 -; CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex -; CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_70 {{%\w+}} %uint_7 %uint_5 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %int {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %int {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpAccessChain %_ptr_UniformConstant_25 %texSampler1D {{%\w+}} -; CHECK: {{%\w+}} = OpLoad {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %float %coords1D -; CHECK: {{%\w+}} = OpLoad %float %lod -; CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex -; CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_75 {{%\w+}} %uint_2 %uint_13 {{%\w+}} %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %25 %38 -; CHECK: {{%\w+}} = OpImageSampleExplicitLod %v4float {{%\w+}} %40 Lod %41 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: %43 = OpAccessChain %_ptr_Output_v4float %_ %int_0 -; CHECK: OpStore %43 {{%\w+}} +;CHECK-NOT: %38 = OpImageSampleExplicitLod %v4float %35 %36 Lod %37 +;CHECK-NOT: %40 = OpAccessChain %_ptr_Output_v4float %_ %int_0 +;CHECK-NOT: OpStore %40 %38 +;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex +;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_70 {{%\w+}} %uint_7 %uint_5 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %int {{%\w+}} +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %int {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpAccessChain %_ptr_UniformConstant_25 %texSampler1D {{%\w+}} +;CHECK: {{%\w+}} = OpLoad {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLoad %float %coords1D +;CHECK: {{%\w+}} = OpLoad %float %lod +;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex +;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_75 {{%\w+}} %uint_2 %uint_13 {{%\w+}} %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %25 %38 +;CHECK: {{%\w+}} = OpImageSampleExplicitLod %v4float {{%\w+}} %40 Lod %41 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: %43 = OpAccessChain %_ptr_Output_v4float %_ %int_0 +;CHECK: OpStore %43 {{%\w+}} OpReturn OpFunctionEnd )"; - - const std::string output_func = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + output_func, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, InstrumentTeseSimple) { @@ -1050,10 +789,11 @@ TEST_F(InstBindlessTest, InstrumentTeseSimple) { const std::string defs = R"( OpCapability Tessellation +;CHECK: OpCapability Linkage %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint TessellationEvaluation %main "main" %_ -; CHECK: OpEntryPoint TessellationEvaluation %main "main" %_ %gl_PrimitiveID %gl_TessCoord +;CHECK: OpEntryPoint TessellationEvaluation %main "main" %_ %gl_PrimitiveID %gl_TessCoord OpExecutionMode %main Triangles OpExecutionMode %main SpacingEqual OpExecutionMode %main VertexOrderCw @@ -1085,10 +825,9 @@ OpMemberDecorate %ufoo 0 Offset 0 OpDecorate %ufoo Block OpDecorate %uniform_index_buffer DescriptorSet 9 OpDecorate %uniform_index_buffer Binding 2 -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId -; CHECK: OpDecorate %gl_TessCoord BuiltIn TessCoord +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId +;CHECK: OpDecorate %gl_TessCoord BuiltIn TessCoord %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -1112,73 +851,322 @@ OpDecorate %uniform_index_buffer Binding 2 %_ptr_Uniform_uint = OpTypePointer Uniform %uint %_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float %_ptr_Output_v4float = OpTypePointer Output %v4float -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %_ptr_Input_uint = OpTypePointer Input %uint -; CHECK: %gl_PrimitiveID = OpVariable %_ptr_Input_uint Input -; CHECK: %v3float = OpTypeVector %float 3 -; CHECK: %_ptr_Input_v3float = OpTypePointer Input %v3float -; CHECK: %gl_TessCoord = OpVariable %_ptr_Input_v3float Input -; CHECK: %v3uint = OpTypeVector %uint 3 -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: %_ptr_Input_uint = OpTypePointer Input %uint +;CHECK: %gl_PrimitiveID = OpVariable %_ptr_Input_uint Input +;CHECK: %v3float = OpTypeVector %float 3 +;CHECK: %_ptr_Input_v3float = OpTypePointer Input %v3float +;CHECK: %gl_TessCoord = OpVariable %_ptr_Input_v3float Input +;CHECK: %v3uint = OpTypeVector %uint 3 +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; - // clang-format on - const std::string main_func = R"( + const std::string main_func = + R"( %main = OpFunction %void None %3 %5 = OpLabel %25 = OpAccessChain %_ptr_Uniform_uint %uniform_index_buffer %int_0 %26 = OpLoad %uint %25 %28 = OpAccessChain %_ptr_StorageBuffer_v4float %adds %26 %int_0 %29 = OpLoad %v4float %28 -; CHECK-NOT: %29 = OpLoad %v4float %28 -; CHECK: {{%\w+}} = OpLoad %uint %gl_PrimitiveID -; CHECK: {{%\w+}} = OpLoad %v3float %gl_TessCoord -; CHECK: {{%\w+}} = OpBitcast %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_2 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_62 {{%\w+}} %uint_9 %uint_2 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint %27 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK-NOT: %29 = OpLoad %v4float %28 +;CHECK: {{%\w+}} = OpLoad %uint %gl_PrimitiveID +;CHECK: {{%\w+}} = OpLoad %v3float %gl_TessCoord +;CHECK: {{%\w+}} = OpBitcast %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_2 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_62 {{%\w+}} %uint_9 %uint_2 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %uint %27 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} %31 = OpAccessChain %_ptr_Output_v4float %_ %int_0 OpStore %31 %29 -; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpLoad %uint %gl_PrimitiveID -; CHECK: {{%\w+}} = OpLoad %v3float %gl_TessCoord -; CHECK: {{%\w+}} = OpBitcast %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_2 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_64 {{%\w+}} %uint_9 %uint_1 {{%\w+}} {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %v4float %29 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: %31 = OpAccessChain %_ptr_Output_v4float %_ %int_0 -; CHECK: OpStore %31 [[phi_result]] +;CHECK-NOT: OpStore %31 %29 +;CHECK: {{%\w+}} = OpLoad %uint %gl_PrimitiveID +;CHECK: {{%\w+}} = OpLoad %v3float %gl_TessCoord +;CHECK: {{%\w+}} = OpBitcast %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_2 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_64 {{%\w+}} %uint_9 %uint_1 {{%\w+}} {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %v4float %29 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result:%\w+]] = OpPhi {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: %31 = OpAccessChain %_ptr_Output_v4float %_ %int_0 +;CHECK: OpStore %31 [[phi_result]] OpReturn OpFunctionEnd )"; - - const std::string output_func = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + output_func, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); +} + +TEST_F(InstBindlessTest, InstrumentTesc) { + // This test verifies that the pass will correctly instrument tessellation + // control shader + // + // clang-format off + // + // #version 450 + // layout(vertices = 3) out; + // layout(set = 0, binding = 0) uniform texture1D _77; + // layout(set = 0, binding = 1) uniform sampler _78; + + // layout(location = 1) flat in int _3[]; + // layout(location = 0) out vec4 _5[3]; + + // void main() + // { + // float param; + // if (_3[gl_InvocationID] == 0) + // { + // param = 0.0234375; + // } + // else + // { + // param = 1.0156199932098388671875; + // } + // _5[gl_InvocationID] = textureLod(sampler1D(_77, _78), param, 0.0); + // vec4 _203; + // if (gl_InvocationID == 0) + // { + // _203 = gl_in[0].gl_Position; + // } + // else + // { + // _203 = gl_in[2].gl_Position; + // } + // gl_out[gl_InvocationID].gl_Position = _203; + // gl_TessLevelInner[0] = 2.7999999523162841796875; + // gl_TessLevelInner[1] = 2.7999999523162841796875; + // gl_TessLevelOuter[0] = 2.7999999523162841796875; + // gl_TessLevelOuter[1] = 2.7999999523162841796875; + // gl_TessLevelOuter[2] = 2.7999999523162841796875; + // gl_TessLevelOuter[3] = 2.7999999523162841796875; + // } + // + // clang-format on + // + // + + // clang-format off + const std::string defs = R"( +OpCapability Tessellation +OpCapability Sampled1D +;CHECK: OpCapability Linkage +;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" +;CHECK: OpExtension "SPV_KHR_physical_storage_buffer" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +;CHECK: OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint TessellationControl %main "main" %_3 %gl_InvocationID %_5 %gl_in %gl_out %gl_TessLevelInner %gl_TessLevelOuter +;CHECK: OpEntryPoint TessellationControl %main "main" %_3 %gl_InvocationID %_5 %gl_in %gl_out %gl_TessLevelInner %gl_TessLevelOuter %gl_PrimitiveID +OpExecutionMode %main OutputVertices 3 +OpSource GLSL 450 +OpName %main "main" +OpName %_3 "_3" +OpName %gl_InvocationID "gl_InvocationID" +OpName %param "param" +OpName %_5 "_5" +OpName %_77 "_77" +OpName %_78 "_78" +OpName %_203 "_203" +OpName %gl_PerVertex "gl_PerVertex" +OpMemberName %gl_PerVertex 0 "gl_Position" +OpMemberName %gl_PerVertex 1 "gl_PointSize" +OpMemberName %gl_PerVertex 2 "gl_ClipDistance" +OpMemberName %gl_PerVertex 3 "gl_CullDistance" +OpName %gl_in "gl_in" +OpName %gl_PerVertex_0 "gl_PerVertex" +OpMemberName %gl_PerVertex_0 0 "gl_Position" +OpMemberName %gl_PerVertex_0 1 "gl_PointSize" +OpMemberName %gl_PerVertex_0 2 "gl_ClipDistance" +OpMemberName %gl_PerVertex_0 3 "gl_CullDistance" +OpName %gl_out "gl_out" +OpName %gl_TessLevelInner "gl_TessLevelInner" +OpName %gl_TessLevelOuter "gl_TessLevelOuter" +OpDecorate %_3 Flat +OpDecorate %_3 Location 1 +OpDecorate %gl_InvocationID BuiltIn InvocationId +OpDecorate %_5 Location 0 +OpDecorate %_77 DescriptorSet 0 +OpDecorate %_77 Binding 0 +OpDecorate %_78 DescriptorSet 0 +OpDecorate %_78 Binding 1 +OpMemberDecorate %gl_PerVertex 0 BuiltIn Position +OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize +OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance +OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance +OpDecorate %gl_PerVertex Block +OpMemberDecorate %gl_PerVertex_0 0 BuiltIn Position +OpMemberDecorate %gl_PerVertex_0 1 BuiltIn PointSize +OpMemberDecorate %gl_PerVertex_0 2 BuiltIn ClipDistance +OpMemberDecorate %gl_PerVertex_0 3 BuiltIn CullDistance +OpDecorate %gl_PerVertex_0 Block +OpDecorate %gl_TessLevelInner Patch +OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner +OpDecorate %gl_TessLevelOuter Patch +OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter +%void = OpTypeVoid +%3 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%uint = OpTypeInt 32 0 +%uint_32 = OpConstant %uint 32 +%_arr_int_uint_32 = OpTypeArray %int %uint_32 +%_ptr_Input__arr_int_uint_32 = OpTypePointer Input %_arr_int_uint_32 +%_3 = OpVariable %_ptr_Input__arr_int_uint_32 Input +%_ptr_Input_int = OpTypePointer Input %int +%gl_InvocationID = OpVariable %_ptr_Input_int Input +%int_0 = OpConstant %int 0 +%bool = OpTypeBool +%float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float +%float_0_0234375 = OpConstant %float 0.0234375 +%float_1_01561999 = OpConstant %float 1.01561999 +%v4float = OpTypeVector %float 4 +%uint_3 = OpConstant %uint 3 +%_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3 +%_ptr_Output__arr_v4float_uint_3 = OpTypePointer Output %_arr_v4float_uint_3 +%_5 = OpVariable %_ptr_Output__arr_v4float_uint_3 Output +%34 = OpTypeImage %float 1D 0 0 0 1 Unknown +%_ptr_UniformConstant_34 = OpTypePointer UniformConstant %34 +%_77 = OpVariable %_ptr_UniformConstant_34 UniformConstant +%38 = OpTypeSampler +%_ptr_UniformConstant_38 = OpTypePointer UniformConstant %38 +%_78 = OpVariable %_ptr_UniformConstant_38 UniformConstant +%42 = OpTypeSampledImage %34 +%float_0 = OpConstant %float 0 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_ptr_Function_v4float = OpTypePointer Function %v4float +%uint_1 = OpConstant %uint 1 +%_arr_float_uint_1 = OpTypeArray %float %uint_1 +%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1 +%_arr_gl_PerVertex_uint_32 = OpTypeArray %gl_PerVertex %uint_32 +%_ptr_Input__arr_gl_PerVertex_uint_32 = OpTypePointer Input %_arr_gl_PerVertex_uint_32 +%gl_in = OpVariable %_ptr_Input__arr_gl_PerVertex_uint_32 Input +%_ptr_Input_v4float = OpTypePointer Input %v4float +%int_2 = OpConstant %int 2 +%gl_PerVertex_0 = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1 +%_arr_gl_PerVertex_0_uint_3 = OpTypeArray %gl_PerVertex_0 %uint_3 +%_ptr_Output__arr_gl_PerVertex_0_uint_3 = OpTypePointer Output %_arr_gl_PerVertex_0_uint_3 +%gl_out = OpVariable %_ptr_Output__arr_gl_PerVertex_0_uint_3 Output +%uint_2 = OpConstant %uint 2 +%_arr_float_uint_2 = OpTypeArray %float %uint_2 +%_ptr_Output__arr_float_uint_2 = OpTypePointer Output %_arr_float_uint_2 +%gl_TessLevelInner = OpVariable %_ptr_Output__arr_float_uint_2 Output +%float_2_79999995 = OpConstant %float 2.79999995 +%_ptr_Output_float = OpTypePointer Output %float +%int_1 = OpConstant %int 1 +%uint_4 = OpConstant %uint 4 +%_arr_float_uint_4 = OpTypeArray %float %uint_4 +%_ptr_Output__arr_float_uint_4 = OpTypePointer Output %_arr_float_uint_4 +%gl_TessLevelOuter = OpVariable %_ptr_Output__arr_float_uint_4 Output +%int_3 = OpConstant %int 3 +)"; + + const std::string main_func = + R"( +%main = OpFunction %void None %3 +%5 = OpLabel +%param = OpVariable %_ptr_Function_float Function +%_203 = OpVariable %_ptr_Function_v4float Function +%14 = OpLoad %int %gl_InvocationID +%15 = OpAccessChain %_ptr_Input_int %_3 %14 +%16 = OpLoad %int %15 +%19 = OpIEqual %bool %16 %int_0 +OpSelectionMerge %21 None +OpBranchConditional %19 %20 %26 +%20 = OpLabel +;CHECK-NOT: %15 = OpAccessChain %_ptr_Input_int %_3 %14 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %int %gl_InvocationID +;CHECK: {{%\w+}} = OpAccessChain %_ptr_Input_int %_3 {{%\w+}} +;CHECK: {{%\w+}} = OpLoad %int {{%\w+}} +;CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %int_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +OpStore %param %float_0_0234375 +OpBranch %21 +%26 = OpLabel +OpStore %param %float_1_01561999 +OpBranch %21 +%21 = OpLabel +%33 = OpLoad %int %gl_InvocationID +%37 = OpLoad %34 %_77 +%41 = OpLoad %38 %_78 +%43 = OpSampledImage %42 %37 %41 +%44 = OpLoad %float %param +;CHECK: {{%\w+}} = OpLoad %int %gl_InvocationID +;CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}} +;CHECK: {{%\w+}} = OpLoad %uint %gl_PrimitiveID +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_1 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_check_desc %uint_23 %uint_129 {{%\w+}} %uint_0 %uint_0 %uint_0 %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +%46 = OpImageSampleExplicitLod %v4float %43 %44 Lod %float_0 +%48 = OpAccessChain %_ptr_Output_v4float %_5 %33 +OpStore %48 %46 +;CHECK-NOT: %48 = OpAccessChain %_ptr_Output_v4float %_5 %33 +;CHECK-NOT: OpStore %48 %46 +;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: [[access_chain:%\w+]] = OpAccessChain %_ptr_Output_v4float %_5 {{%\w+}} +;CHECK: OpStore [[access_chain]] [[phi_result]] +%49 = OpLoad %int %gl_InvocationID +%50 = OpIEqual %bool %49 %int_0 +OpSelectionMerge %52 None +OpBranchConditional %50 %51 %64 +%51 = OpLabel +%62 = OpAccessChain %_ptr_Input_v4float %gl_in %int_0 %int_0 +%63 = OpLoad %v4float %62 +OpStore %_203 %63 +OpBranch %52 +%64 = OpLabel +%66 = OpAccessChain %_ptr_Input_v4float %gl_in %int_2 %int_0 +%67 = OpLoad %v4float %66 +OpStore %_203 %67 +OpBranch %52 +%52 = OpLabel +%72 = OpLoad %int %gl_InvocationID +%73 = OpLoad %v4float %_203 +%74 = OpAccessChain %_ptr_Output_v4float %gl_out %72 %int_0 +OpStore %74 %73 +%81 = OpAccessChain %_ptr_Output_float %gl_TessLevelInner %int_0 +OpStore %81 %float_2_79999995 +%83 = OpAccessChain %_ptr_Output_float %gl_TessLevelInner %int_1 +OpStore %83 %float_2_79999995 +%88 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_0 +OpStore %88 %float_2_79999995 +%89 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_1 +OpStore %89 %float_2_79999995 +%90 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_2 +OpStore %90 %float_2_79999995 +%92 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_3 +OpStore %92 %float_2_79999995 +OpReturn +OpFunctionEnd +)"; + // clang-format on + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, MultipleDebugFunctions) { @@ -1188,11 +1176,11 @@ TEST_F(InstBindlessTest, MultipleDebugFunctions) { // clang-format off const std::string defs = R"( OpCapability Shader -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" +;CHECK: OpCapability Linkage %2 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor -; CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord OpExecutionMode %MainPs OriginUpperLeft %1 = OpString "foo5.frag" OpSource HLSL 500 %1 @@ -1221,9 +1209,8 @@ OpDecorate %g_sAniso DescriptorSet 1 OpDecorate %g_sAniso Binding 3 OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %4 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -1257,14 +1244,10 @@ OpDecorate %_entryPointOutput_vColor Location 0 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; - // clang-format on const std::string func1 = R"( %MainPs = OpFunction %void None %4 @@ -1299,44 +1282,43 @@ OpLine %1 24 0 %43 = OpAccessChain %_ptr_Function_v2float %i %int_0 %44 = OpLoad %v2float %43 %45 = OpImageSampleImplicitLod %v4float %41 %44 -; CHECK-NOT: %45 = OpImageSampleImplicitLod %v4float %41 %44 -; CHECK: {{%\w+}} = OpLoad %v2float {{%\w+}} -; CHECK: OpNoLine -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_128 {{%\w+}} %uint_1 %uint_2 {{%\w+}} %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %27 {{%\w+}} -; CHECK: {{%\w+}} = OpSampledImage %37 {{%\w+}} {{%\w+}} -; CHECK: OpLine %5 24 0 -; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} {{%\w+}} -; CHECK: OpNoLine -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK-NOT: %45 = OpImageSampleImplicitLod %v4float %41 %44 +;CHECK: {{%\w+}} = OpLoad %v2float {{%\w+}} +;CHECK: OpNoLine +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_128 {{%\w+}} %uint_1 %uint_2 {{%\w+}} %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %27 {{%\w+}} +;CHECK: {{%\w+}} = OpSampledImage %37 {{%\w+}} {{%\w+}} +;CHECK: OpLine %5 24 0 +;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} {{%\w+}} +;CHECK: OpNoLine +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} %47 = OpAccessChain %_ptr_Function_v4float %ps_output %int_0 OpStore %47 %45 -; CHECK-NOT: OpStore %47 %45 -; CHECK: [[store_loc:%\w+]] = OpAccessChain %_ptr_Function_v4float %ps_output %int_0 -; CHECK: OpStore [[store_loc]] [[phi_result]] +;CHECK-NOT: OpStore %47 %45 +;CHECK: [[store_loc:%\w+]] = OpAccessChain %_ptr_Function_v4float %ps_output %int_0 +;CHECK: OpStore [[store_loc]] [[phi_result]] OpLine %1 25 0 %48 = OpLoad %PS_OUTPUT %ps_output OpReturnValue %48 OpFunctionEnd )"; - - const std::string output_func = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch( - defs + func1 + func2 + output_func, true, 7u, 23u); + defs + kImportStub + func1 + func2, true, 23u); } TEST_F(InstBindlessTest, RuntimeArray) { @@ -1348,12 +1330,12 @@ TEST_F(InstBindlessTest, RuntimeArray) { const std::string defs = R"( OpCapability Shader OpCapability RuntimeDescriptorArray +;CHECK: OpCapability Linkage OpExtension "SPV_EXT_descriptor_indexing" -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor -; CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord OpExecutionMode %MainPs OriginUpperLeft OpSource HLSL 500 OpName %MainPs "MainPs" @@ -1372,9 +1354,8 @@ OpDecorate %g_sAniso DescriptorSet 1 OpDecorate %g_sAniso Binding 3 OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -1401,12 +1382,10 @@ OpDecorate %_entryPointOutput_vColor Location 0 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; - // clang-format on const std::string main_func = R"( %MainPs = OpFunction %void None %3 @@ -1420,35 +1399,34 @@ OpDecorate %_entryPointOutput_vColor Location 0 %68 = OpSampledImage %39 %66 %67 %71 = OpImageSampleImplicitLod %v4float %68 %53 OpStore %_entryPointOutput_vColor %71 -; CHECK-NOT: %71 = OpImageSampleImplicitLod %v4float %68 %53 -; CHECK-NOT: OpStore %_entryPointOutput_vColor %71 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: [[check_result:%\w+]] = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_60 {{%\w+}} %uint_1 %uint_2 %32 %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %16 %33 -; CHECK: {{%\w+}} = OpSampledImage %26 {{%\w+}} %35 -; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %30 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: OpStore %_entryPointOutput_vColor [[phi_result_1]] +;CHECK-NOT: %71 = OpImageSampleImplicitLod %v4float %68 %53 +;CHECK-NOT: OpStore %_entryPointOutput_vColor %71 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: [[check_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_60 {{%\w+}} %uint_1 %uint_2 %32 %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %16 %33 +;CHECK: {{%\w+}} = OpSampledImage %26 {{%\w+}} %35 +;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %30 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK: OpStore %_entryPointOutput_vColor [[phi_result_1]] OpReturn OpFunctionEnd )"; - - const std::string new_funcs = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + new_funcs, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, InstrumentInitCheckOnScalarDescriptor) { @@ -1462,11 +1440,11 @@ TEST_F(InstBindlessTest, InstrumentInitCheckOnScalarDescriptor) { // clang-format off const std::string defs = R"( OpCapability Shader -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" +;CHECK: OpCapability Linkage %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor -; CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord OpExecutionMode %MainPs OriginUpperLeft OpSource HLSL 500 OpName %MainPs "MainPs" @@ -1480,9 +1458,8 @@ OpDecorate %g_sAniso DescriptorSet 1 OpDecorate %g_sAniso Binding 2 OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 -; check: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; check: OpDecorate %gl_FragCoord BuiltIn FragCoord +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %8 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -1499,10 +1476,8 @@ OpDecorate %_entryPointOutput_vColor Location 0 %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; - // clang-format on const std::string main_func = R"( %MainPs = OpFunction %void None %8 @@ -1513,43 +1488,38 @@ OpDecorate %_entryPointOutput_vColor Location 0 %23 = OpSampledImage %16 %21 %22 %24 = OpImageSampleImplicitLod %v4float %23 %20 OpStore %_entryPointOutput_vColor %24 -; CHECK-NOT: %24 = OpImageSampleImplicitLod %v4float %23 %20 -; CHECK-NOT: OpStore %_entryPointOutput_vColor %24 -; CHECK: [[check_result:%\w+]] = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_40 {{%\w+}} %uint_1 %uint_2 %uint_0 %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional [[check_result]] {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %12 %g_tColor -; CHECK: {{%\w+}} = OpSampledImage %16 {{%\w+}} %22 -; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %20 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: OpStore %_entryPointOutput_vColor [[phi_result]] +;CHECK-NOT: %24 = OpImageSampleImplicitLod %v4float %23 %20 +;CHECK-NOT: OpStore %_entryPointOutput_vColor %24 +;CHECK: [[check_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_40 {{%\w+}} %uint_1 %uint_2 %uint_0 %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional [[check_result]] {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %12 %g_tColor +;CHECK: {{%\w+}} = OpSampledImage %16 {{%\w+}} %22 +;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %20 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK: OpStore %_entryPointOutput_vColor [[phi_result]] OpReturn OpFunctionEnd )"; - - const std::string new_funcs = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + new_funcs, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, SPV14AddToEntryPoint) { const std::string text = R"( -; CHECK: OpEntryPoint Fragment {{%\w+}} "foo" {{%\w+}} {{%\w+}} {{%\w+}} [[v1:%\w+]] [[v2:%\w+]] -; CHECK: OpDecorate [[v1]] DescriptorSet 7 -; CHECK: OpDecorate [[v2]] DescriptorSet 7 -; CHECK: [[v1]] = OpVariable {{%\w+}} StorageBuffer -; CHECK: [[v2]] = OpVariable {{%\w+}} StorageBuffer OpCapability Shader OpExtension "SPV_EXT_descriptor_indexing" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %foo "foo" %gid %image_var %sampler_var +;CHECK: OpEntryPoint Fragment {{%\w+}} "foo" {{%\w+}} {{%\w+}} {{%\w+}} %gl_FragCoord OpExecutionMode %foo OriginUpperLeft OpDecorate %image_var DescriptorSet 4 OpDecorate %image_var Binding 1 @@ -1592,22 +1562,19 @@ OpFunctionEnd )"; SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } TEST_F(InstBindlessTest, SPV14AddToEntryPoints) { const std::string text = R"( -; CHECK: OpEntryPoint Fragment {{%\w+}} "foo" {{%\w+}} {{%\w+}} {{%\w+}} [[v1:%\w+]] [[v2:%\w+]] -; CHECK: OpEntryPoint Fragment {{%\w+}} "bar" {{%\w+}} {{%\w+}} {{%\w+}} [[v1:%\w+]] [[v2:%\w+]] -; CHECK: OpDecorate [[v1]] DescriptorSet 7 -; CHECK: OpDecorate [[v2]] DescriptorSet 7 -; CHECK: [[v1]] = OpVariable {{%\w+}} StorageBuffer -; CHECK: [[v2]] = OpVariable {{%\w+}} StorageBuffer OpCapability Shader +;CHECK: OpCapability Linkage OpExtension "SPV_EXT_descriptor_indexing" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %foo "foo" %gid %image_var %sampler_var +;CHECK: OpEntryPoint Fragment {{%\w+}} "foo" {{%\w+}} {{%\w+}} {{%\w+}} %gl_FragCoord OpEntryPoint Fragment %foo "bar" %gid %image_var %sampler_var +;CHECK: OpEntryPoint Fragment {{%\w+}} "bar" {{%\w+}} {{%\w+}} {{%\w+}} %gl_FragCoord OpExecutionMode %foo OriginUpperLeft OpDecorate %image_var DescriptorSet 3 OpDecorate %image_var Binding 2 @@ -1650,7 +1617,7 @@ OpFunctionEnd )"; SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedUBOArray) { @@ -1673,12 +1640,12 @@ OpCapability Shader OpCapability ShaderNonUniform OpCapability RuntimeDescriptorArray OpCapability UniformBufferArrayNonUniformIndexing +;CHECK: OpCapability Linkage OpExtension "SPV_EXT_descriptor_indexing" -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %b %nu_ii -; CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord +;CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord OpExecutionMode %main OriginUpperLeft OpSource GLSL 450 OpSourceExtension "GL_EXT_nonuniform_qualifier" @@ -1698,11 +1665,10 @@ OpDecorate %nu_ii Location 0 OpDecorate %nu_ii NonUniform OpDecorate %16 NonUniform OpDecorate %20 NonUniform -; CHECK: OpDecorate {{%\w+}} NonUniform -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -; CHECK: OpDecorate {{%\w+}} NonUniform +;CHECK: OpDecorate {{%\w+}} NonUniform +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +;CHECK: OpDecorate {{%\w+}} NonUniform %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -1717,15 +1683,12 @@ OpDecorate %20 NonUniform %nu_ii = OpVariable %_ptr_Input_int Input %int_0 = OpConstant %int 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -)" + kInputGlobals + R"( -; CHECK: %v4uint = OpTypeVector %uint 4 -)" + kOutputGlobals + R"( -; CHECK: %v4float = OpTypeVector %float 4 -; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -; CHECK: [[null_float:%\w+]] = OpConstantNull %float +;CHECK: %v4uint = OpTypeVector %uint 4 +;CHECK: %v4float = OpTypeVector %float 4 +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: [[null_float:%\w+]] = OpConstantNull %float )"; - // clang-format on const std::string main_func = R"( %main = OpFunction %void None %3 @@ -1734,34 +1697,33 @@ OpDecorate %20 NonUniform %19 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %16 %int_0 %20 = OpLoad %float %19 OpStore %b %20 -; CHECK-NOT: %20 = OpLoad %float %19 -; CHECK-NOT: OpStore %b %20 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_46 {{%\w+}} %uint_6 %uint_3 {{%\w+}} {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %float %20 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: OpStore %b [[phi_result]] +;CHECK-NOT: %20 = OpLoad %float %19 +;CHECK-NOT: OpStore %b %20 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpBitcast %uint %7 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_6 %uint_3 {{%\w+}} {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %float %20 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: OpStore %b [[phi_result]] OpReturn OpFunctionEnd )"; - - const std::string new_funcs = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + new_funcs, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArrayDeprecated) { @@ -1784,12 +1746,12 @@ OpCapability Shader OpCapability ShaderNonUniform OpCapability RuntimeDescriptorArray OpCapability StorageBufferArrayNonUniformIndexing +;CHECK: OpCapability Linkage OpExtension "SPV_EXT_descriptor_indexing" -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %b %nu_ii -; CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord +;CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord OpExecutionMode %main OriginUpperLeft OpSource GLSL 450 OpSourceExtension "GL_EXT_nonuniform_qualifier" @@ -1809,9 +1771,8 @@ OpDecorate %nu_ii Location 0 OpDecorate %nu_ii NonUniform OpDecorate %16 NonUniform OpDecorate %20 NonUniform -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -1826,17 +1787,13 @@ OpDecorate %20 NonUniform %nu_ii = OpVariable %_ptr_Input_int Input %int_0 = OpConstant %int 0 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float -; CHECK: %uint = OpTypeInt 32 0 -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -; CHECK: %v4uint = OpTypeVector %uint 4 -)" + kOutputGlobals + R"( -; CHECK: %v4float = OpTypeVector %float 4 -; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -; CHECK: [[null_float:%\w+]] = OpConstantNull %float +;CHECK: %uint = OpTypeInt 32 0 +;CHECK: %v4uint = OpTypeVector %uint 4 +;CHECK: %v4float = OpTypeVector %float 4 +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: [[null_float:%\w+]] = OpConstantNull %float )"; - // clang-format on const std::string main_func = R"( %main = OpFunction %void None %3 @@ -1845,34 +1802,33 @@ OpDecorate %20 NonUniform %19 = OpAccessChain %_ptr_StorageBuffer_float %storageBuffer %16 %int_0 %20 = OpLoad %float %19 OpStore %b %20 -; CHECK-NOT: %20 = OpLoad %float %19 -; CHECK-NOT: OpStore %b %20 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_46 {{%\w+}} %uint_7 %uint_3 {{%\w+}} {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %float %20 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: OpStore %b [[phi_result]] +;CHECK-NOT: %20 = OpLoad %float %19 +;CHECK-NOT: OpStore %b %20 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpBitcast %uint %7 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_7 %uint_3 {{%\w+}} {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %float %20 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: OpStore %b [[phi_result]] OpReturn OpFunctionEnd )"; - - const std::string new_funcs = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + new_funcs, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArray) { @@ -1884,12 +1840,12 @@ OpCapability Shader OpCapability ShaderNonUniform OpCapability RuntimeDescriptorArray OpCapability StorageBufferArrayNonUniformIndexing +;CHECK: OpCapability Linkage OpExtension "SPV_EXT_descriptor_indexing" -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %b %nu_ii -; CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord +;CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord OpExecutionMode %main OriginUpperLeft OpSource GLSL 450 OpSourceExtension "GL_EXT_nonuniform_qualifier" @@ -1909,11 +1865,10 @@ OpDecorate %nu_ii Location 0 OpDecorate %nu_ii NonUniform OpDecorate %16 NonUniform OpDecorate %20 NonUniform -; CHECK: OpDecorate {{%\w+}} NonUniform -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -; CHECK: OpDecorate {{%\w+}} NonUniform +;CHECK: OpDecorate {{%\w+}} NonUniform +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +;CHECK: OpDecorate {{%\w+}} NonUniform %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -1928,15 +1883,12 @@ OpDecorate %20 NonUniform %nu_ii = OpVariable %_ptr_Input_int Input %int_0 = OpConstant %int 0 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float -)" + kInputGlobals + R"( -; CHECK: %v4uint = OpTypeVector %uint 4 -)" + kOutputGlobals + R"( -; CHECK: %v4float = OpTypeVector %float 4 -; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -; CHECK: [[null_float:%\w+]] = OpConstantNull %float +;CHECK: %v4uint = OpTypeVector %uint 4 +;CHECK: %v4float = OpTypeVector %float 4 +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: [[null_float:%\w+]] = OpConstantNull %float )"; - // clang-format on const std::string main_func = R"( %main = OpFunction %void None %3 @@ -1945,34 +1897,33 @@ OpDecorate %20 NonUniform %19 = OpAccessChain %_ptr_StorageBuffer_float %storageBuffer %16 %int_0 %20 = OpLoad %float %19 OpStore %b %20 -; CHECK-NOT: %20 = OpLoad %float %19 -; CHECK-NOT: OpStore %b %20 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_46 {{%\w+}} %uint_0 %uint_3 {{%\w+}} {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %float %20 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: OpStore %b {{%\w+}} +;CHECK-NOT: %20 = OpLoad %float %19 +;CHECK-NOT: OpStore %b %20 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpBitcast %uint %7 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_0 %uint_3 {{%\w+}} {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %float %20 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: OpStore %b {{%\w+}} OpReturn OpFunctionEnd )"; - - const std::string new_funcs = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + new_funcs, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, InstInitLoadUBOScalar) { @@ -1990,12 +1941,12 @@ TEST_F(InstBindlessTest, InstInitLoadUBOScalar) { // clang-format off const std::string defs = R"( OpCapability Shader +;CHECK: OpCapability Linkage OpExtension "SPV_EXT_descriptor_indexing" -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %b -; CHECK: OpEntryPoint Fragment %main "main" %b %gl_FragCoord +;CHECK: OpEntryPoint Fragment %main "main" %b %gl_FragCoord OpExecutionMode %main OriginUpperLeft OpSource GLSL 450 OpSourceExtension "GL_EXT_nonuniform_qualifier" @@ -2009,9 +1960,8 @@ OpMemberDecorate %uname 0 Offset 0 OpDecorate %uname Block OpDecorate %uniformBuffer DescriptorSet 7 OpDecorate %uniformBuffer Binding 3 -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -2023,19 +1973,15 @@ OpDecorate %uniformBuffer Binding 3 %int = OpTypeInt 32 1 %int_0 = OpConstant %int 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -; CHECK: %int = OpTypeInt 32 1 -; CHECK: %_ptr_Uniform_float = OpTypePointer Uniform %float -; CHECK: %uint = OpTypeInt 32 0 -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -; CHECK: %v4uint = OpTypeVector %uint 4 -)" + kOutputGlobals + R"( -; CHECK: %v4float = OpTypeVector %float 4 -; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -; CHECK: [[null_float:%\w+]] = OpConstantNull %float +;CHECK: %int = OpTypeInt 32 1 +;CHECK: %_ptr_Uniform_float = OpTypePointer Uniform %float +;CHECK: %uint = OpTypeInt 32 0 +;CHECK: %v4uint = OpTypeVector %uint 4 +;CHECK: %v4float = OpTypeVector %float 4 +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: [[null_float:%\w+]] = OpConstantNull %float )"; - // clang-format on const std::string main_func = R"( %main = OpFunction %void None %3 @@ -2043,33 +1989,32 @@ OpDecorate %uniformBuffer Binding 3 %15 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %int_0 %16 = OpLoad %float %15 OpStore %b %16 -; CHECK-NOT: %16 = OpLoad %float %15 -; CHECK-NOT: OpStore %b %16 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: [[check_result:%\w+]] = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_33 {{%\w+}} %uint_7 %uint_3 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional [[check_result]] {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %float %15 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: OpStore %b [[phi_result]] +;CHECK-NOT: %16 = OpLoad %float %15 +;CHECK-NOT: OpStore %b %16 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: [[check_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_33 {{%\w+}} %uint_7 %uint_3 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional [[check_result]] {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %float %15 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: OpStore %b [[phi_result]] OpReturn OpFunctionEnd )"; - - const std::string new_funcs = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + new_funcs, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, InstBoundsInitStoreUnsizedSSBOArray) { @@ -2091,12 +2036,12 @@ TEST_F(InstBindlessTest, InstBoundsInitStoreUnsizedSSBOArray) { OpCapability ShaderNonUniform OpCapability RuntimeDescriptorArray OpCapability StorageBufferArrayNonUniformIndexing +;CHECK: OpCapability Linkage OpExtension "SPV_EXT_descriptor_indexing" -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %nu_ii %b -; CHECK: OpEntryPoint Fragment %main "main" %nu_ii %b %gl_FragCoord +;CHECK: OpEntryPoint Fragment %main "main" %nu_ii %b %gl_FragCoord OpExecutionMode %main OriginUpperLeft OpSource GLSL 450 OpSourceExtension "GL_EXT_nonuniform_qualifier" @@ -2115,9 +2060,8 @@ OpDecorate %nu_ii Location 0 OpDecorate %nu_ii NonUniform OpDecorate %14 NonUniform OpDecorate %b Location 1 -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -2132,12 +2076,9 @@ OpDecorate %b Location 1 %_ptr_Input_float = OpTypePointer Input %float %b = OpVariable %_ptr_Input_float Input %_ptr_Uniform_float = OpTypePointer Uniform %float -)" + kInputGlobals + R"( -; CHECK: %v4uint = OpTypeVector %uint 4 -)" + kOutputGlobals + R"( -; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: %v4uint = OpTypeVector %uint 4 +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input )"; - // clang-format on const std::string main_func = R"( %main = OpFunction %void None %3 @@ -2146,31 +2087,30 @@ OpDecorate %b Location 1 %18 = OpLoad %float %b %20 = OpAccessChain %_ptr_Uniform_float %storageBuffer %14 %int_0 OpStore %20 %18 -; CHECK-NOT: OpStore %20 %18 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: [[check_result:%\w+]] = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_46 {{%\w+}} %uint_5 %uint_4 {{%\w+}} {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional [[check_result]] {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpStore %20 %19 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel +;CHECK-NOT: OpStore %20 %18 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpBitcast %uint %7 +;CHECK: [[check_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_5 %uint_4 {{%\w+}} {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional [[check_result]] {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpStore %20 %19 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - - const std::string new_funcs = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + new_funcs, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, InstBoundsInitLoadSizedUBOArray) { @@ -2192,12 +2132,12 @@ TEST_F(InstBindlessTest, InstBoundsInitLoadSizedUBOArray) { OpCapability Shader OpCapability ShaderNonUniform OpCapability UniformBufferArrayNonUniformIndexing +;CHECK: OpCapability Linkage OpExtension "SPV_EXT_descriptor_indexing" -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %b %nu_ii -; CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord +;CHECK: OpEntryPoint Fragment %main "main" %b %nu_ii %gl_FragCoord OpExecutionMode %main OriginUpperLeft OpSource GLSL 450 OpSourceExtension "GL_EXT_nonuniform_qualifier" @@ -2217,10 +2157,9 @@ OpDecorate %nu_ii Location 0 OpDecorate %nu_ii NonUniform OpDecorate %18 NonUniform OpDecorate %22 NonUniform -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -; CHECK: OpDecorate [[load_result:%\w+]] NonUniform +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +;CHECK: OpDecorate [[load_result:%\w+]] NonUniform %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -2237,12 +2176,10 @@ OpDecorate %22 NonUniform %nu_ii = OpVariable %_ptr_Input_int Input %int_0 = OpConstant %int 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -; CHECK: [[null_float:%\w+]] = OpConstantNull %float +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: [[null_float:%\w+]] = OpConstantNull %float )"; - // clang-format on const std::string main_func = R"( %main = OpFunction %void None %3 @@ -2251,34 +2188,33 @@ OpDecorate %22 NonUniform %21 = OpAccessChain %_ptr_Uniform_float %uniformBuffer %18 %int_0 %22 = OpLoad %float %21 OpStore %b %22 -; CHECK-NOT: %22 = OpLoad %float %21 -; CHECK-NOT: OpStore %b %22 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_47 {{%\w+}} %uint_1 %uint_3 {{%\w+}} {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %float %22 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: OpStore %b {{%\w+}} +;CHECK-NOT: %22 = OpLoad %float %21 +;CHECK-NOT: OpStore %b %22 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpBitcast %uint %7 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_47 {{%\w+}} %uint_1 %uint_3 {{%\w+}} {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %float %22 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: OpStore %b {{%\w+}} OpReturn OpFunctionEnd )"; - - const std::string new_funcs = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + new_funcs, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, @@ -2304,12 +2240,12 @@ TEST_F(InstBindlessTest, const std::string defs = R"( OpCapability Shader OpCapability RuntimeDescriptorArray +;CHECK: OpCapability Linkage OpExtension "SPV_EXT_descriptor_indexing" -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint GLCompute %main "main" -; CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID +;CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID OpExecutionMode %main LocalSize 1 1 1 OpSource GLSL 450 OpSourceExtension "GL_EXT_nonuniform_qualifier" @@ -2327,9 +2263,8 @@ OpDecorate %sbo Binding 0 OpDecorate %images DescriptorSet 2 OpDecorate %images Binding 1 OpDecorate %images NonWritable -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 @@ -2351,14 +2286,12 @@ OpDecorate %images NonWritable %v4float = OpTypeVector %float 4 %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: %v3uint = OpTypeVector %uint 3 -; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint -; CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input -; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: %v3uint = OpTypeVector %uint 3 +;CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint +;CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input +;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; - // clang-format on const std::string main_func = R"( %main = OpFunction %void None %3 @@ -2371,65 +2304,64 @@ OpDecorate %images NonWritable %29 = OpCompositeExtract %float %27 0 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 -; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_48 {{%\w+}} %uint_2 %uint_0 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint %25 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %13 {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_51 {{%\w+}} %uint_2 %uint_1 {{%\w+}} %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %13 {{%\w+}} -; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1 -; CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_54 {{%\w+}} %uint_2 %uint_0 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpStore %31 {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel +;CHECK-NOT: OpStore %31 %29 +;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_48 {{%\w+}} %uint_2 %uint_0 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %uint %25 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} +;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}} +;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_51 {{%\w+}} %uint_2 %uint_1 {{%\w+}} %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}} +;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0 +;CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_54 {{%\w+}} %uint_2 %uint_0 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpStore %31 {{%\w+}} +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - - const std::string new_funcs = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + new_funcs, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, @@ -2454,13 +2386,13 @@ TEST_F(InstBindlessTest, const std::string defs = R"( OpCapability RuntimeDescriptorArray OpCapability RayTracingNV +;CHECK: OpCapability Linkage OpExtension "SPV_EXT_descriptor_indexing" OpExtension "SPV_NV_ray_tracing" -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint RayGenerationNV %main "main" -; CHECK: OpEntryPoint RayGenerationNV %main "main" [[launch_id:%\w+]] +;CHECK: OpEntryPoint RayGenerationNV %main "main" [[launch_id:%\w+]] OpSource GLSL 460 OpSourceExtension "GL_EXT_nonuniform_qualifier" OpSourceExtension "GL_NV_ray_tracing" @@ -2478,9 +2410,8 @@ OpDecorate %sbo Binding 1 OpDecorate %images DescriptorSet 3 OpDecorate %images Binding 5 OpDecorate %images NonWritable -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV +)" + kImportDeco + R"( +;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 @@ -2502,11 +2433,9 @@ OpDecorate %images NonWritable %v4float = OpTypeVector %float 4 %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; - // clang-format on const std::string main_func = R"( %main = OpFunction %void None %3 @@ -2519,65 +2448,64 @@ OpDecorate %images NonWritable %29 = OpCompositeExtract %float %27 0 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 -; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5313 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_49 {{%\w+}} %uint_3 %uint_1 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint %25 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} -; CHECK: {{%\w+}} = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %13 {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5313 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_52 {{%\w+}} %uint_3 %uint_5 {{%\w+}} %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %13 {{%\w+}} -; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1 -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5313 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_55 {{%\w+}} %uint_3 %uint_1 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpStore {{%\w+}} {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel +;CHECK-NOT: OpStore %31 %29 +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5313 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_3 %uint_1 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %uint %25 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} +;CHECK: {{%\w+}} = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} +;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}} +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5313 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_3 %uint_5 {{%\w+}} %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}} +;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0 +;CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5313 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_3 %uint_1 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpStore {{%\w+}} {{%\w+}} +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - - const std::string new_funcs = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + new_funcs, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, @@ -2602,13 +2530,13 @@ TEST_F(InstBindlessTest, const std::string defs = R"( OpCapability RuntimeDescriptorArray OpCapability RayTracingNV +;CHECK: OpCapability Linkage OpExtension "SPV_EXT_descriptor_indexing" OpExtension "SPV_NV_ray_tracing" -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint IntersectionNV %main "main" -; CHECK: OpEntryPoint IntersectionNV %main "main" [[launch_id:%\w+]] +;CHECK: OpEntryPoint IntersectionNV %main "main" [[launch_id:%\w+]] OpSource GLSL 460 OpSourceExtension "GL_EXT_nonuniform_qualifier" OpSourceExtension "GL_NV_ray_tracing" @@ -2626,9 +2554,8 @@ OpDecorate %sbo Binding 1 OpDecorate %images DescriptorSet 5 OpDecorate %images Binding 3 OpDecorate %images NonWritable -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV +)" + kImportDeco + R"( +;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 @@ -2650,12 +2577,10 @@ OpDecorate %images NonWritable %v4float = OpTypeVector %float 4 %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input -; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input +;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; - // clang-format on const std::string main_func = R"( %main = OpFunction %void None %3 @@ -2668,64 +2593,63 @@ OpDecorate %images NonWritable %29 = OpCompositeExtract %float %27 0 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 -; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5314 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_49 {{%\w+}} %uint_5 %uint_1 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint %25 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} -; CHECK: {{%\w+}} = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %13 {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5314 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_52 {{%\w+}} %uint_5 %uint_3 {{%\w+}} %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %13 {{%\w+}} -; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1 -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5314 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_55 {{%\w+}} %uint_5 %uint_1 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpStore %31 {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} +;CHECK-NOT: OpStore %31 %29 +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5314 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_5 %uint_1 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %uint %25 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} +;CHECK: {{%\w+}} = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} +;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}} +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5314 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_5 %uint_3 {{%\w+}} %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %13 {{%\w+}} +;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0 +;CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5314 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_5 %uint_1 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpStore %31 {{%\w+}} +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} OpReturn OpFunctionEnd )"; - - const std::string new_funcs = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + new_funcs, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, @@ -2750,13 +2674,13 @@ TEST_F(InstBindlessTest, const std::string defs = R"( OpCapability RuntimeDescriptorArray OpCapability RayTracingNV +;CHECK: OpCapability Linkage OpExtension "SPV_EXT_descriptor_indexing" OpExtension "SPV_NV_ray_tracing" -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint AnyHitNV %main "main" -; CHECK: OpEntryPoint AnyHitNV %main "main" [[launch_id:%\w+]] +;CHECK: OpEntryPoint AnyHitNV %main "main" [[launch_id:%\w+]] OpSource GLSL 460 OpSourceExtension "GL_EXT_nonuniform_qualifier" OpSourceExtension "GL_NV_ray_tracing" @@ -2774,9 +2698,8 @@ OpDecorate %sbo Binding 1 OpDecorate %images DescriptorSet 2 OpDecorate %images Binding 3 OpDecorate %images NonWritable -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV +)" + kImportDeco + R"( +;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 @@ -2798,12 +2721,10 @@ OpDecorate %images NonWritable %v4float = OpTypeVector %float 4 %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input -; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input +;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; - // clang-format on const std::string main_func = R"( %main = OpFunction %void None %3 @@ -2816,71 +2737,70 @@ OpDecorate %images NonWritable %29 = OpCompositeExtract %float %27 0 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 -; CHECK-NOT: %20 = OpLoad %uint %19 -; CHECK-NOT: %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 -; CHECK-NOT: %23 = OpLoad %13 %22 -; CHECK-NOT: %27 = OpImageRead %v4float %23 %25 -; CHECK-NOT: %29 = OpCompositeExtract %float %27 0 -; CHECK-NOT: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 -; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5315 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_49 {{%\w+}} %uint_2 %uint_1 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint %25 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} -; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]] -; CHECK: %28 = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5315 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_52 {{%\w+}} %uint_2 %uint_3 {{%\w+}} %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0 -; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5315 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_55 {{%\w+}} %uint_2 %uint_1 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpStore %31 %30 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -OpReturn -OpFunctionEnd -)"; - - const std::string new_funcs = kStreamWrite6 + kCheckDesc; - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + new_funcs, - true, 7u, 23u); +;CHECK-NOT: %20 = OpLoad %uint %19 +;CHECK-NOT: %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +;CHECK-NOT: %23 = OpLoad %13 %22 +;CHECK-NOT: %27 = OpImageRead %v4float %23 %25 +;CHECK-NOT: %29 = OpCompositeExtract %float %27 0 +;CHECK-NOT: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +;CHECK-NOT: OpStore %31 %29 +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5315 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_2 %uint_1 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %uint %25 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} +;CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]] +;CHECK: %28 = OpLoad %13 %27 +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5315 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_2 %uint_3 {{%\w+}} %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %13 %27 +;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0 +;CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5315 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_2 %uint_1 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpStore %31 %30 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +OpReturn +OpFunctionEnd +)"; + // clang-format on + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, @@ -2905,13 +2825,13 @@ TEST_F(InstBindlessTest, const std::string defs = R"( OpCapability RuntimeDescriptorArray OpCapability RayTracingNV +;CHECK: OpCapability Linkage OpExtension "SPV_EXT_descriptor_indexing" OpExtension "SPV_NV_ray_tracing" -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint ClosestHitNV %main "main" -; CHECK: OpEntryPoint ClosestHitNV %main "main" [[launch_id:%\w+]] +;CHECK: OpEntryPoint ClosestHitNV %main "main" [[launch_id:%\w+]] OpSource GLSL 460 OpSourceExtension "GL_EXT_nonuniform_qualifier" OpSourceExtension "GL_NV_ray_tracing" @@ -2929,9 +2849,8 @@ OpDecorate %sbo Binding 2 OpDecorate %images DescriptorSet 1 OpDecorate %images Binding 3 OpDecorate %images NonWritable -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV +)" + kImportDeco + R"( +;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 @@ -2953,12 +2872,10 @@ OpDecorate %images NonWritable %v4float = OpTypeVector %float 4 %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input -; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input +;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; - // clang-format on const std::string main_func = R"( %main = OpFunction %void None %3 @@ -2971,71 +2888,70 @@ OpDecorate %images NonWritable %29 = OpCompositeExtract %float %27 0 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 -; CHECK-NOT: %20 = OpLoad %uint %19 -; CHECK-NOT: %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 -; CHECK-NOT: %23 = OpLoad %13 %22 -; CHECK-NOT: %27 = OpImageRead %v4float %23 %25 -; CHECK-NOT: %29 = OpCompositeExtract %float %27 0 -; CHECK-NOT: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 -; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5316 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_49 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint %25 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} -; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]] -; CHECK: %28 = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5316 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_52 {{%\w+}} %uint_1 %uint_3 {{%\w+}} %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0 -; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5316 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_55 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpStore %31 %30 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel +;CHECK-NOT: %20 = OpLoad %uint %19 +;CHECK-NOT: %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +;CHECK-NOT: %23 = OpLoad %13 %22 +;CHECK-NOT: %27 = OpImageRead %v4float %23 %25 +;CHECK-NOT: %29 = OpCompositeExtract %float %27 0 +;CHECK-NOT: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +;CHECK-NOT: OpStore %31 %29 +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5316 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %uint %25 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} +;CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]] +;CHECK: %28 = OpLoad %13 %27 +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5316 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_1 %uint_3 {{%\w+}} %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %13 %27 +;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0 +;CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5316 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpStore %31 %30 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - - const std::string new_funcs = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + new_funcs, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, @@ -3060,13 +2976,13 @@ TEST_F(InstBindlessTest, const std::string defs = R"( OpCapability RuntimeDescriptorArray OpCapability RayTracingNV +;CHECK: OpCapability Linkage OpExtension "SPV_EXT_descriptor_indexing" OpExtension "SPV_NV_ray_tracing" -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint MissNV %main "main" -; CHECK: OpEntryPoint MissNV %main "main" [[launch_id:%\w+]] +;CHECK: OpEntryPoint MissNV %main "main" [[launch_id:%\w+]] OpSource GLSL 460 OpSourceExtension "GL_EXT_nonuniform_qualifier" OpSourceExtension "GL_NV_ray_tracing" @@ -3084,9 +3000,8 @@ OpDecorate %sbo Binding 2 OpDecorate %images DescriptorSet 1 OpDecorate %images Binding 3 OpDecorate %images NonWritable -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV +)" + kImportDeco + R"( +;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 @@ -3108,12 +3023,10 @@ OpDecorate %images NonWritable %v4float = OpTypeVector %float 4 %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input -; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input +;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; - // clang-format on const std::string main_func = R"( %main = OpFunction %void None %3 @@ -3126,68 +3039,67 @@ OpDecorate %images NonWritable %29 = OpCompositeExtract %float %27 0 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 -; CHECK-NOT: %20 = OpLoad %uint %19 -; CHECK-NOT: %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 -; CHECK-NOT: %27 = OpImageRead %v4float %23 %25 -; CHECK-NOT: %29 = OpCompositeExtract %float %27 0 -; CHECK-NOT OpStore %31 %29 -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5317 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_49 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint %25 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} -; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]] -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5317 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_52 {{%\w+}} %uint_1 %uint_3 {{%\w+}} %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0 -; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5317 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_55 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpStore %31 %30 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel +;CHECK-NOT: %20 = OpLoad %uint %19 +;CHECK-NOT: %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +;CHECK-NOT: %27 = OpImageRead %v4float %23 %25 +;CHECK-NOT: %29 = OpCompositeExtract %float %27 0 +;CHECK-NOT OpStore %31 %29 +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5317 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %uint %25 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} +;CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]] +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5317 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_1 %uint_3 {{%\w+}} %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %13 %27 +;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0 +;CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5317 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpStore %31 %30 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - - const std::string new_funcs = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + new_funcs, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, @@ -3212,13 +3124,13 @@ TEST_F(InstBindlessTest, const std::string defs = R"( OpCapability RuntimeDescriptorArray OpCapability RayTracingNV +;CHECK: OpCapability Linkage OpExtension "SPV_EXT_descriptor_indexing" OpExtension "SPV_NV_ray_tracing" -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint CallableNV %main "main" -; CHECK: OpEntryPoint CallableNV %main "main" [[launch_id:%\w+]] +;CHECK: OpEntryPoint CallableNV %main "main" [[launch_id:%\w+]] OpSource GLSL 460 OpSourceExtension "GL_EXT_nonuniform_qualifier" OpSourceExtension "GL_NV_ray_tracing" @@ -3236,9 +3148,8 @@ OpDecorate %sbo Binding 2 OpDecorate %images DescriptorSet 1 OpDecorate %images Binding 3 OpDecorate %images NonWritable -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV +)" + kImportDeco + R"( +;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 @@ -3260,11 +3171,9 @@ OpDecorate %images NonWritable %v4float = OpTypeVector %float 4 %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; - // clang-format on const std::string main_func = R"( %main = OpFunction %void None %3 @@ -3275,72 +3184,71 @@ OpDecorate %images NonWritable %23 = OpLoad %13 %22 %27 = OpImageRead %v4float %23 %25 %29 = OpCompositeExtract %float %27 0 -; CHECK-NOT: %20 = OpLoad %uint %19 -; CHECK-NOT: %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5318 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_49 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint %25 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} -; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} -; CHECK-NOT: %23 = OpLoad %13 %22 -; CHECK-NOT: %27 = OpImageRead %v4float %23 %25 -; CHECK-NOT: %29 = OpCompositeExtract %float %27 0 -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5318 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_52 {{%\w+}} %uint_1 %uint_3 {{%\w+}} %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0 -; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +;CHECK-NOT: %20 = OpLoad %uint %19 +;CHECK-NOT: %22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5318 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %uint %25 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} +;CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} +;CHECK-NOT: %23 = OpLoad %13 %22 +;CHECK-NOT: %27 = OpImageRead %v4float %23 %25 +;CHECK-NOT: %29 = OpCompositeExtract %float %27 0 +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5318 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_1 %uint_3 {{%\w+}} %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %13 %27 +;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0 +;CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 -; CHECK-NOT: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 -; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5318 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_55 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpStore %31 %30 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel +;CHECK-NOT: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +;CHECK-NOT: OpStore %31 %29 +;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5318 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_1 %uint_2 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpStore %31 %30 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - - const std::string new_funcs = kStreamWrite6 + kCheckDesc; + // clang-format on // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + new_funcs, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, InstBoundsInitSameBlockOpReplication) { @@ -3375,12 +3283,12 @@ TEST_F(InstBindlessTest, InstBoundsInitSameBlockOpReplication) { OpCapability Shader OpCapability ShaderNonUniformEXT OpCapability SampledImageArrayNonUniformIndexingEXT +;CHECK: OpCapability Linkage OpExtension "SPV_EXT_descriptor_indexing" -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %inTexcoord %outColor -; CHECK: OpEntryPoint Fragment %main "main" %inTexcoord %outColor %gl_FragCoord +;CHECK: OpEntryPoint Fragment %main "main" %inTexcoord %outColor %gl_FragCoord OpExecutionMode %main OriginUpperLeft OpSource GLSL 450 OpSourceExtension "GL_EXT_nonuniform_qualifier" @@ -3410,12 +3318,11 @@ OpDecorate %Uniforms Block OpDecorate %uniforms DescriptorSet 1 OpDecorate %uniforms Binding 0 OpDecorate %outColor Location 0 -; CHECK: OpDecorate {{%\w+}} NonUniform -; CHECK: OpDecorate {{%\w+}} NonUniform -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -; CHECK: OpDecorate [[desc_state_result:%\w+]] NonUniform +;CHECK: OpDecorate {{%\w+}} NonUniform +;CHECK: OpDecorate {{%\w+}} NonUniform +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +;CHECK: OpDecorate [[desc_state_result:%\w+]] NonUniform %void = OpTypeVoid %3 = OpTypeFunction %void %int = OpTypeInt 32 1 @@ -3447,11 +3354,9 @@ OpDecorate %outColor Location 0 %_ptr_Output_v4float = OpTypePointer Output %v4float %outColor = OpVariable %_ptr_Output_v4float Output %float_0 = OpConstant %float 0 -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -; CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float )"; - // clang-format on const std::string main_func = R"( %main = OpFunction %void None %3 @@ -3468,26 +3373,26 @@ OpStore %index %int_0 %32 = OpLoad %v2float %inTexcoord %34 = OpImageSampleImplicitLod %v4float %28 %32 %36 = OpCompositeExtract %float %34 0 -; CHECK-NOT: %34 = OpImageSampleImplicitLod %v4float %28 %32 -; CHECK-NOT: %36 = OpCompositeExtract %float %34 0 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpBitcast %uint %19 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_80 {{%\w+}} %uint_1 %uint_3 {{%\w+}} %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %13 %21 -; CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %26 -; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %32 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK-NOT: %34 = OpImageSampleImplicitLod %v4float %28 %32 +;CHECK-NOT: %36 = OpCompositeExtract %float %34 0 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpBitcast %uint %19 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_80 {{%\w+}} %uint_1 %uint_3 {{%\w+}} %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %13 %21 +;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %26 +;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %32 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} OpStore %x %36 %39 = OpLoad %13 %uniformTex %40 = OpLoad %23 %uniformSampler @@ -3496,48 +3401,48 @@ OpStore %x %36 %47 = OpAccessChain %_ptr_Uniform_v2float %uniforms %int_0 %48 = OpLoad %v2float %47 %49 = OpFMul %v2float %42 %48 -; CHECK-NOT: %48 = OpLoad %v2float %47 -; CHECK-NOT: %49 = OpFMul %v2float %42 %48 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_88 {{%\w+}} %uint_1 %uint_0 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %v2float %47 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} -; CHECK: %49 = OpFMul %v2float %42 [[phi_result]] +;CHECK-NOT: %48 = OpLoad %v2float %47 +;CHECK-NOT: %49 = OpFMul %v2float %42 %48 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_88 {{%\w+}} %uint_1 %uint_0 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %v2float %47 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result:%\w+]] = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} +;CHECK: %49 = OpFMul %v2float %42 [[phi_result]] %50 = OpImageSampleImplicitLod %v4float %41 %49 %51 = OpCompositeExtract %float %50 0 OpStore %y %51 -; CHECK-NOT: %50 = OpImageSampleImplicitLod %v4float %41 %49 -; CHECK-NOT: %51 = OpCompositeExtract %float %50 0 -; CHECK: {{%\w+}} = OpSampledImage %27 %39 %40 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_90 {{%\w+}} %uint_1 %uint_2 %uint_0 %uint_0 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %13 %uniformTex -; CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %40 -; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %49 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: %51 = OpCompositeExtract %float {{%\w+}} 0 +;CHECK-NOT: %50 = OpImageSampleImplicitLod %v4float %41 %49 +;CHECK-NOT: %51 = OpCompositeExtract %float %50 0 +;CHECK: {{%\w+}} = OpSampledImage %27 %39 %40 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_90 {{%\w+}} %uint_1 %uint_2 %uint_0 %uint_0 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %13 %uniformTex +;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %40 +;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %49 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK: %51 = OpCompositeExtract %float {{%\w+}} 0 OpStore %y %51 %54 = OpLoad %float %x %55 = OpLoad %float %y @@ -3546,12 +3451,11 @@ OpStore %outColor %57 OpReturn OpFunctionEnd )"; - - const std::string new_funcs = kStreamWrite6 + kCheckDesc; + // clang-format on SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + main_func + new_funcs, - true, 7u, 23u); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); } TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { @@ -3593,147 +3497,145 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { // clang-format off const std::string text = R"( - OpCapability Shader -;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor -;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_FragCoord - OpExecutionMode %MainPs OriginUpperLeft - OpSource HLSL 500 - OpName %MainPs "MainPs" - OpName %PerViewPushConst_t "PerViewPushConst_t" - OpMemberName %PerViewPushConst_t 0 "g_B" - OpName %_ "" - OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" - OpMemberName %PerViewConstantBuffer_t 0 "g_TexOff0" - OpMemberName %PerViewConstantBuffer_t 1 "g_TexOff1" - OpName %__0 "" - OpName %g_tColor "g_tColor" - OpName %g_sAniso "g_sAniso" - OpName %i_vTextureCoords "i.vTextureCoords" - OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" - OpMemberDecorate %PerViewPushConst_t 0 Offset 0 - OpDecorate %PerViewPushConst_t Block - OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 - OpMemberDecorate %PerViewConstantBuffer_t 1 Offset 8 - OpDecorate %PerViewConstantBuffer_t Block - OpDecorate %__0 DescriptorSet 0 - OpDecorate %__0 Binding 1 - OpDecorate %g_tColor DescriptorSet 0 - OpDecorate %g_tColor Binding 0 - OpDecorate %g_sAniso DescriptorSet 0 - OpDecorate %g_sAniso Binding 2 - OpDecorate %i_vTextureCoords Location 0 - OpDecorate %_entryPointOutput_vColor Location 0 - ;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( - ;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 - %v2float = OpTypeVector %float 2 - %v4float = OpTypeVector %float 4 - %uint = OpTypeInt 32 0 +OpCapability Shader +;CHECK: OpCapability Linkage +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor +;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %PerViewPushConst_t "PerViewPushConst_t" +OpMemberName %PerViewPushConst_t 0 "g_B" +OpName %_ "" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_TexOff0" +OpMemberName %PerViewConstantBuffer_t 1 "g_TexOff1" +OpName %__0 "" +OpName %g_tColor "g_tColor" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpMemberDecorate %PerViewPushConst_t 0 Offset 0 +OpDecorate %PerViewPushConst_t Block +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpMemberDecorate %PerViewConstantBuffer_t 1 Offset 8 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %__0 DescriptorSet 0 +OpDecorate %__0 Binding 1 +OpDecorate %g_tColor DescriptorSet 0 +OpDecorate %g_tColor Binding 0 +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %g_sAniso Binding 2 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%uint = OpTypeInt 32 0 %PerViewPushConst_t = OpTypeStruct %uint %_ptr_PushConstant_PerViewPushConst_t = OpTypePointer PushConstant %PerViewPushConst_t - %_ = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant - %int = OpTypeInt 32 1 - %int_0 = OpConstant %int 0 +%_ = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 %_ptr_PushConstant_uint = OpTypePointer PushConstant %uint - %bool = OpTypeBool - %uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%uint_0 = OpConstant %uint 0 %PerViewConstantBuffer_t = OpTypeStruct %v2float %v2float %_ptr_Uniform_PerViewConstantBuffer_t = OpTypePointer Uniform %PerViewConstantBuffer_t - %__0 = OpVariable %_ptr_Uniform_PerViewConstantBuffer_t Uniform +%__0 = OpVariable %_ptr_Uniform_PerViewConstantBuffer_t Uniform %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float - %int_1 = OpConstant %int 1 - %49 = OpTypeImage %float 2D 0 0 0 1 Unknown +%int_1 = OpConstant %int 1 +%49 = OpTypeImage %float 2D 0 0 0 1 Unknown %_ptr_UniformConstant_49 = OpTypePointer UniformConstant %49 - %g_tColor = OpVariable %_ptr_UniformConstant_49 UniformConstant - %53 = OpTypeSampler +%g_tColor = OpVariable %_ptr_UniformConstant_49 UniformConstant +%53 = OpTypeSampler %_ptr_UniformConstant_53 = OpTypePointer UniformConstant %53 - %g_sAniso = OpVariable %_ptr_UniformConstant_53 UniformConstant - %57 = OpTypeSampledImage %49 +%g_sAniso = OpVariable %_ptr_UniformConstant_53 UniformConstant +%57 = OpTypeSampledImage %49 %_ptr_Input_v2float = OpTypePointer Input %v2float %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output - )" + kInputGlobals + R"( - ;CHECK: %v4uint = OpTypeVector %uint 4 - )" + kOutputGlobals + R"( - ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float - ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input - ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float - %MainPs = OpFunction %void None %3 - %5 = OpLabel - %69 = OpLoad %v2float %i_vTextureCoords - %82 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 - %83 = OpLoad %uint %82 - %84 = OpINotEqual %bool %83 %uint_0 - OpSelectionMerge %91 None - OpBranchConditional %84 %85 %88 - %85 = OpLabel - %86 = OpAccessChain %_ptr_Uniform_v2float %__0 %int_0 - %87 = OpLoad %v2float %86 - ;CHECK-NOT: %87 = OpLoad %v2float %86 - ;CHECK: {{%\w+}} = OpLabel - ;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 %uint_7 - ;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord - ;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} - ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 - ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 - ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 - ;CHECK: [[desc_state_result:%\w+]] = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_72 {{%\w+}} %uint_0 %uint_1 %uint_0 {{%\w+}} - ;CHECK: OpSelectionMerge {{%\w+}} None - ;CHECK: OpBranchConditional [[desc_state_result]] {{%\w+}} {{%\w+}} - ;CHECK: {{%\w+}} = OpLabel - ;CHECK: {{%\w+}} = OpLoad %v2float %86 - ;CHECK: OpBranch {{%\w+}} - ;CHECK: {{%\w+}} = OpLabel - ;CHECK: OpBranch {{%\w+}} - ;CHECK: {{%\w+}} = OpLabel - ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} - OpBranch %91 - %88 = OpLabel - %89 = OpAccessChain %_ptr_Uniform_v2float %__0 %int_1 - %90 = OpLoad %v2float %89 - ;CHECK-NOT: %90 = OpLoad %v2float %89 - ;CHECK: {{%\w+}} = OpIAdd %uint %uint_8 %uint_7 - ;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord - ;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} - ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 - ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 - ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 - ;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_76 {{%\w+}} %uint_0 %uint_1 %uint_0 {{%\w+}} - ;CHECK: OpSelectionMerge {{%\w+}} None - ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} - ;CHECK: {{%\w+}} = OpLabel - ;CHECK: {{%\w+}} = OpLoad %v2float %89 - ;CHECK: OpBranch {{%\w+}} - ;CHECK: {{%\w+}} = OpLabel - ;CHECK: OpBranch {{%\w+}} - ;CHECK: {{%\w+}} = OpLabel +;CHECK: %v4uint = OpTypeVector %uint 4 +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float + )" + kImportStub + R"( +%MainPs = OpFunction %void None %3 +%5 = OpLabel +%69 = OpLoad %v2float %i_vTextureCoords +%82 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 +%83 = OpLoad %uint %82 +%84 = OpINotEqual %bool %83 %uint_0 +OpSelectionMerge %91 None +OpBranchConditional %84 %85 %88 +%85 = OpLabel +%86 = OpAccessChain %_ptr_Uniform_v2float %__0 %int_0 +%87 = OpLoad %v2float %86 +;CHECK-NOT: %87 = OpLoad %v2float %86 +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 %uint_7 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: [[desc_state_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_72 {{%\w+}} %uint_0 %uint_1 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional [[desc_state_result]] {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %v2float %86 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} - OpBranch %91 - %91 = OpLabel - %115 = OpPhi %v2float %87 %85 %90 %88 - ;CHECK-NOT: %115 = OpPhi %v2float %87 %85 %90 %88 - ;CHECK: %115 = OpPhi %v2float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} - %95 = OpFAdd %v2float %69 %115 - %96 = OpLoad %49 %g_tColor - %97 = OpLoad %53 %g_sAniso - %98 = OpSampledImage %57 %96 %97 - %100 = OpImageSampleImplicitLod %v4float %98 %95 - OpStore %_entryPointOutput_vColor %100 - OpReturn - OpFunctionEnd -)" + kStreamWrite6 + kCheckDesc; +OpBranch %91 +%88 = OpLabel +%89 = OpAccessChain %_ptr_Uniform_v2float %__0 %int_1 +%90 = OpLoad %v2float %89 +;CHECK-NOT: %90 = OpLoad %v2float %89 +;CHECK: {{%\w+}} = OpIAdd %uint %uint_8 %uint_7 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_76 {{%\w+}} %uint_0 %uint_1 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %v2float %89 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} +OpBranch %91 +%91 = OpLabel +%115 = OpPhi %v2float %87 %85 %90 %88 +;CHECK-NOT: %115 = OpPhi %v2float %87 %85 %90 %88 +;CHECK: %115 = OpPhi %v2float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +%95 = OpFAdd %v2float %69 %115 +%96 = OpLoad %49 %g_tColor +%97 = OpLoad %53 %g_sAniso +%98 = OpSampledImage %57 %96 %97 +%100 = OpImageSampleImplicitLod %v4float %98 %95 +OpStore %_entryPointOutput_vColor %100 +OpReturn +OpFunctionEnd +)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { @@ -3774,96 +3676,94 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { // clang-format off const std::string text = R"( - OpCapability Shader -;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor - OpExecutionMode %MainPs OriginUpperLeft - OpSource HLSL 500 - OpName %MainPs "MainPs" - OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t" - OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal" - OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins" - OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff" - OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t" - OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants" - OpName %_ "" - OpName %PerViewPushConst_t "PerViewPushConst_t" - OpMemberName %PerViewPushConst_t 0 "g_c" - OpName %__0 "" - OpName %g_tColor "g_tColor" - OpName %g_sAniso "g_sAniso" - OpName %i_vTextureCoords "i.vTextureCoords" - OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" - OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 RowMajor - OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 Offset 0 - OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 MatrixStride 16 - OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 1 Offset 48 - OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 2 Offset 64 - OpDecorate %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 ArrayStride 80 - OpMemberDecorate %_BindlessFastEnvMapCB_PS_t 0 Offset 0 - OpDecorate %_BindlessFastEnvMapCB_PS_t Block - OpDecorate %_ DescriptorSet 0 - OpDecorate %_ Binding 2 - OpMemberDecorate %PerViewPushConst_t 0 Offset 0 - OpDecorate %PerViewPushConst_t Block - OpDecorate %g_tColor DescriptorSet 0 - OpDecorate %g_tColor Binding 0 - OpDecorate %g_sAniso DescriptorSet 0 - OpDecorate %g_sAniso Binding 1 - OpDecorate %i_vTextureCoords Location 0 - OpDecorate %_entryPointOutput_vColor Location 0 -;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 - %v2float = OpTypeVector %float 2 - %v4float = OpTypeVector %float 4 - %v3float = OpTypeVector %float 3 +OpCapability Shader +;CHECK: OpCapability Linkage +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t" +OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal" +OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins" +OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff" +OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t" +OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants" +OpName %_ "" +OpName %PerViewPushConst_t "PerViewPushConst_t" +OpMemberName %PerViewPushConst_t 0 "g_c" +OpName %__0 "" +OpName %g_tColor "g_tColor" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 RowMajor +OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 Offset 0 +OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 MatrixStride 16 +OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 1 Offset 48 +OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 2 Offset 64 +OpDecorate %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 ArrayStride 80 +OpMemberDecorate %_BindlessFastEnvMapCB_PS_t 0 Offset 0 +OpDecorate %_BindlessFastEnvMapCB_PS_t Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 2 +OpMemberDecorate %PerViewPushConst_t 0 Offset 0 +OpDecorate %PerViewPushConst_t Block +OpDecorate %g_tColor DescriptorSet 0 +OpDecorate %g_tColor Binding 0 +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %g_sAniso Binding 1 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%v3float = OpTypeVector %float 3 %mat4v3float = OpTypeMatrix %v3float 4 %PerBatchEnvMapConstantBuffer_t = OpTypeStruct %mat4v3float %v4float %v2float - %uint = OpTypeInt 32 0 - %uint_128 = OpConstant %uint 128 +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 = OpTypeArray %PerBatchEnvMapConstantBuffer_t %uint_128 %_BindlessFastEnvMapCB_PS_t = OpTypeStruct %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 %_ptr_Uniform__BindlessFastEnvMapCB_PS_t = OpTypePointer Uniform %_BindlessFastEnvMapCB_PS_t - %_ = OpVariable %_ptr_Uniform__BindlessFastEnvMapCB_PS_t Uniform - %int = OpTypeInt 32 1 - %int_0 = OpConstant %int 0 +%_ = OpVariable %_ptr_Uniform__BindlessFastEnvMapCB_PS_t Uniform +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 %PerViewPushConst_t = OpTypeStruct %uint %_ptr_PushConstant_PerViewPushConst_t = OpTypePointer PushConstant %PerViewPushConst_t - %__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant +%__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant %_ptr_PushConstant_uint = OpTypePointer PushConstant %uint - %int_2 = OpConstant %int 2 +%int_2 = OpConstant %int 2 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float - %46 = OpTypeImage %float 2D 0 0 0 1 Unknown +%46 = OpTypeImage %float 2D 0 0 0 1 Unknown %_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46 - %g_tColor = OpVariable %_ptr_UniformConstant_46 UniformConstant - %50 = OpTypeSampler +%g_tColor = OpVariable %_ptr_UniformConstant_46 UniformConstant +%50 = OpTypeSampler %_ptr_UniformConstant_50 = OpTypePointer UniformConstant %50 - %g_sAniso = OpVariable %_ptr_UniformConstant_50 UniformConstant - %54 = OpTypeSampledImage %46 +%g_sAniso = OpVariable %_ptr_UniformConstant_50 UniformConstant +%54 = OpTypeSampledImage %46 %_ptr_Input_v2float = OpTypePointer Input %v2float %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -)" + kInputGlobals + R"( -;CHECK: %v4uint = OpTypeVector %uint 4 -)" + kOutputGlobals + R"( -;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float -;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input -;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float - %MainPs = OpFunction %void None %3 - %5 = OpLabel - %66 = OpLoad %v2float %i_vTextureCoords - %79 = OpAccessChain %_ptr_PushConstant_uint %__0 %int_0 - %80 = OpLoad %uint %79 - %81 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %80 %int_2 - %82 = OpLoad %v2float %81 -;CHECK-NOT: %82 = OpLoad %v2float %81 +;CHECK: %v4uint = OpTypeVector %uint 4 +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float +)" + kImportStub + R"( +%MainPs = OpFunction %void None %3 +%5 = OpLabel +%66 = OpLoad %v2float %i_vTextureCoords +%79 = OpAccessChain %_ptr_PushConstant_uint %__0 %int_0 +%80 = OpLoad %uint %79 +%81 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %80 %int_2 +%82 = OpLoad %v2float %81 +;CHECK-NOT: %82 = OpLoad %v2float %81 ;CHECK: {{%\w+}} = OpIMul %uint %uint_80 %80 ;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64 @@ -3873,7 +3773,7 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_79 {{%\w+}} %uint_0 %uint_2 %uint_0 {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_79 {{%\w+}} %uint_0 %uint_2 %uint_0 {{%\w+}} ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -3883,22 +3783,22 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} - %86 = OpFAdd %v2float %66 %82 -;CHECK-NOT: %86 = OpFAdd %v2float %66 %82 -;CHECK: %86 = OpFAdd %v2float %66 {{%\w+}} - %87 = OpLoad %46 %g_tColor - %88 = OpLoad %50 %g_sAniso - %89 = OpSampledImage %54 %87 %88 - %91 = OpImageSampleImplicitLod %v4float %89 %86 - OpStore %_entryPointOutput_vColor %91 - OpReturn - OpFunctionEnd -)" + kStreamWrite6 + kCheckDesc; +%86 = OpFAdd %v2float %66 %82 +;CHECK-NOT: %86 = OpFAdd %v2float %66 %82 +;CHECK: %86 = OpFAdd %v2float %66 {{%\w+}} +%87 = OpLoad %46 %g_tColor +%88 = OpLoad %50 %g_sAniso +%89 = OpSampledImage %54 %87 %88 +%91 = OpImageSampleImplicitLod %v4float %89 %86 +OpStore %_entryPointOutput_vColor %91 +OpReturn +OpFunctionEnd +)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { @@ -3909,98 +3809,96 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { // clang-format off const std::string text = R"( - OpCapability Shader -;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor -;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_FragCoord - OpExecutionMode %MainPs OriginUpperLeft - OpSource HLSL 500 - OpName %MainPs "MainPs" - OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t" - OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal" - OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins" - OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff" - OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t" - OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants" - OpName %_ "" - OpName %PerViewPushConst_t "PerViewPushConst_t" - OpMemberName %PerViewPushConst_t 0 "g_c" - OpName %__0 "" - OpName %g_tColor "g_tColor" - OpName %g_sAniso "g_sAniso" - OpName %i_vTextureCoords "i.vTextureCoords" - OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" - OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 RowMajor - OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 Offset 0 - OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 MatrixStride 16 - OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 1 Offset 48 - OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 2 Offset 64 - OpDecorate %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 ArrayStride 80 - OpMemberDecorate %_BindlessFastEnvMapCB_PS_t 0 Offset 0 - OpDecorate %_BindlessFastEnvMapCB_PS_t Block - OpDecorate %_ DescriptorSet 0 - OpDecorate %_ Binding 2 - OpMemberDecorate %PerViewPushConst_t 0 Offset 0 - OpDecorate %PerViewPushConst_t Block - OpDecorate %g_tColor DescriptorSet 0 - OpDecorate %g_tColor Binding 0 - OpDecorate %g_sAniso DescriptorSet 0 - OpDecorate %g_sAniso Binding 1 - OpDecorate %i_vTextureCoords Location 0 - OpDecorate %_entryPointOutput_vColor Location 0 -;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 - %v2float = OpTypeVector %float 2 - %v4float = OpTypeVector %float 4 - %v3float = OpTypeVector %float 3 +OpCapability Shader +;CHECK: OpCapability Linkage +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor +;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t" +OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal" +OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins" +OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff" +OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t" +OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants" +OpName %_ "" +OpName %PerViewPushConst_t "PerViewPushConst_t" +OpMemberName %PerViewPushConst_t 0 "g_c" +OpName %__0 "" +OpName %g_tColor "g_tColor" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 RowMajor +OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 Offset 0 +OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 MatrixStride 16 +OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 1 Offset 48 +OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 2 Offset 64 +OpDecorate %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 ArrayStride 80 +OpMemberDecorate %_BindlessFastEnvMapCB_PS_t 0 Offset 0 +OpDecorate %_BindlessFastEnvMapCB_PS_t Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 2 +OpMemberDecorate %PerViewPushConst_t 0 Offset 0 +OpDecorate %PerViewPushConst_t Block +OpDecorate %g_tColor DescriptorSet 0 +OpDecorate %g_tColor Binding 0 +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %g_sAniso Binding 1 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%v3float = OpTypeVector %float 3 %mat4v3float = OpTypeMatrix %v3float 4 %PerBatchEnvMapConstantBuffer_t = OpTypeStruct %mat4v3float %v4float %v2float - %uint = OpTypeInt 32 0 - %uint_128 = OpConstant %uint 128 +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 = OpTypeArray %PerBatchEnvMapConstantBuffer_t %uint_128 %_BindlessFastEnvMapCB_PS_t = OpTypeStruct %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 %_ptr_Uniform__BindlessFastEnvMapCB_PS_t = OpTypePointer Uniform %_BindlessFastEnvMapCB_PS_t - %_ = OpVariable %_ptr_Uniform__BindlessFastEnvMapCB_PS_t Uniform - %int = OpTypeInt 32 1 - %int_0 = OpConstant %int 0 +%_ = OpVariable %_ptr_Uniform__BindlessFastEnvMapCB_PS_t Uniform +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 %PerViewPushConst_t = OpTypeStruct %uint %_ptr_PushConstant_PerViewPushConst_t = OpTypePointer PushConstant %PerViewPushConst_t - %__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant +%__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant %_ptr_PushConstant_uint = OpTypePointer PushConstant %uint - %int_2 = OpConstant %int 2 +%int_2 = OpConstant %int 2 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float - %46 = OpTypeImage %float 2D 0 0 0 1 Unknown +%46 = OpTypeImage %float 2D 0 0 0 1 Unknown %_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46 - %g_tColor = OpVariable %_ptr_UniformConstant_46 UniformConstant - %50 = OpTypeSampler +%g_tColor = OpVariable %_ptr_UniformConstant_46 UniformConstant +%50 = OpTypeSampler %_ptr_UniformConstant_50 = OpTypePointer UniformConstant %50 - %g_sAniso = OpVariable %_ptr_UniformConstant_50 UniformConstant - %54 = OpTypeSampledImage %46 +%g_sAniso = OpVariable %_ptr_UniformConstant_50 UniformConstant +%54 = OpTypeSampledImage %46 %_ptr_Input_v2float = OpTypePointer Input %v2float %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -)" + kInputGlobals + R"( ;CHECK: %v4uint = OpTypeVector %uint 4 -)" + kOutputGlobals + R"( ;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float ;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float - %MainPs = OpFunction %void None %3 - %5 = OpLabel - %66 = OpLoad %v2float %i_vTextureCoords - %79 = OpAccessChain %_ptr_PushConstant_uint %__0 %int_0 - %80 = OpLoad %uint %79 - %81 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %80 %int_2 - %82 = OpLoad %v2float %81 - %86 = OpFAdd %v2float %66 %82 +)" + kImportStub + R"( +%MainPs = OpFunction %void None %3 +%5 = OpLabel +%66 = OpLoad %v2float %i_vTextureCoords +%79 = OpAccessChain %_ptr_PushConstant_uint %__0 %int_0 +%80 = OpLoad %uint %79 +%81 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %80 %int_2 +%82 = OpLoad %v2float %81 +%86 = OpFAdd %v2float %66 %82 ;CHECK-NOT: %82 = OpLoad %v2float %81 ;CHECK-NOT: %86 = OpFAdd %v2float %66 %82 ;CHECK: {{%\w+}} = OpIMul %uint %uint_80 %80 @@ -4012,7 +3910,7 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_79 {{%\w+}} %uint_0 %uint_2 %uint_0 {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_79 {{%\w+}} %uint_0 %uint_2 %uint_0 {{%\w+}} ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -4023,11 +3921,11 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} ;CHECK: %86 = OpFAdd %v2float %66 {{%\w+}} - %87 = OpLoad %46 %g_tColor - %88 = OpLoad %50 %g_sAniso - %89 = OpSampledImage %54 %87 %88 - %91 = OpImageSampleImplicitLod %v4float %89 %86 - OpStore %_entryPointOutput_vColor %91 +%87 = OpLoad %46 %g_tColor +%88 = OpLoad %50 %g_sAniso +%89 = OpSampledImage %54 %87 %88 +%91 = OpImageSampleImplicitLod %v4float %89 %86 +OpStore %_entryPointOutput_vColor %91 ;CHECK-NOT: %91 = OpImageSampleImplicitLod %v4float %89 %86 ;CHECK-NOT: OpStore %_entryPointOutput_vColor %91 ;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord @@ -4035,7 +3933,7 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_84 {{%\w+}} %uint_0 %uint_0 %uint_0 %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_84 {{%\w+}} %uint_0 %uint_0 %uint_0 %uint_0 ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -4048,14 +3946,14 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} ;CHECK: OpStore %_entryPointOutput_vColor {{%\w+}} - OpReturn - OpFunctionEnd -)" + kStreamWrite6 + kCheckDesc; +OpReturn +OpFunctionEnd +)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { @@ -4066,88 +3964,87 @@ TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { // clang-format off const std::string text = R"( - OpCapability Shader - OpCapability Int16 - OpCapability StoragePushConstant16 -;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %MainPs "MainPs" %g_tColor %_ %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor -;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %g_tColor %_ %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_FragCoord - OpExecutionMode %MainPs OriginUpperLeft - OpSource HLSL 500 - OpName %MainPs "MainPs" - OpName %g_tColor "g_tColor" - OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" - OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" - OpName %_ "" - OpName %g_sAniso "g_sAniso" - OpName %i_vTextureCoords "i.vTextureCoords" - OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" - OpDecorate %g_tColor DescriptorSet 1 - OpDecorate %g_tColor Binding 2 - OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 - OpDecorate %PerViewConstantBuffer_t Block - OpDecorate %g_sAniso DescriptorSet 1 - OpDecorate %g_sAniso Binding 2 - OpDecorate %i_vTextureCoords Location 0 - OpDecorate %_entryPointOutput_vColor Location 0 -;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord - %void = OpTypeVoid - %10 = OpTypeFunction %void - %float = OpTypeFloat 32 - %v2float = OpTypeVector %float 2 - %v4float = OpTypeVector %float 4 - %int = OpTypeInt 32 1 - %int_0 = OpConstant %int 0 - %16 = OpTypeImage %float 2D 0 0 0 1 Unknown - %uint = OpTypeInt 32 0 - %uint_128 = OpConstant %uint 128 +OpCapability Shader +OpCapability Int16 +OpCapability StoragePushConstant16 +;CHECK: OpCapability Linkage +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %g_tColor %_ %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor +;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %g_tColor %_ %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %g_tColor "g_tColor" +OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" +OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" +OpName %_ "" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpDecorate %g_tColor DescriptorSet 1 +OpDecorate %g_tColor Binding 2 +OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 +OpDecorate %PerViewConstantBuffer_t Block +OpDecorate %g_sAniso DescriptorSet 1 +OpDecorate %g_sAniso Binding 2 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%10 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%16 = OpTypeImage %float 2D 0 0 0 1 Unknown +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 %_arr_16_uint_128 = OpTypeArray %16 %uint_128 %_ptr_UniformConstant__arr_16_uint_128 = OpTypePointer UniformConstant %_arr_16_uint_128 - %g_tColor = OpVariable %_ptr_UniformConstant__arr_16_uint_128 UniformConstant - %ushort = OpTypeInt 16 0 +%g_tColor = OpVariable %_ptr_UniformConstant__arr_16_uint_128 UniformConstant +%ushort = OpTypeInt 16 0 %PerViewConstantBuffer_t = OpTypeStruct %ushort %_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t - %_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant +%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant %_ptr_PushConstant_ushort = OpTypePointer PushConstant %ushort %_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16 - %25 = OpTypeSampler +%25 = OpTypeSampler %_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25 - %g_sAniso = OpVariable %_ptr_UniformConstant_25 UniformConstant - %27 = OpTypeSampledImage %16 +%g_sAniso = OpVariable %_ptr_UniformConstant_25 UniformConstant +%27 = OpTypeSampledImage %16 %_ptr_Input_v2float = OpTypePointer Input %v2float %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -)" + kInputGlobals + kOutputGlobals + R"( -;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float -;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float - %MainPs = OpFunction %void None %10 - %30 = OpLabel +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +)" + kImportStub + R"( +%MainPs = OpFunction %void None %10 +%30 = OpLabel ;CHECK: OpBranch %39 ;CHECK: %39 = OpLabel - %31 = OpLoad %v2float %i_vTextureCoords - %32 = OpAccessChain %_ptr_PushConstant_ushort %_ %int_0 - %33 = OpLoad %ushort %32 - %34 = OpAccessChain %_ptr_UniformConstant_16 %g_tColor %33 - %35 = OpLoad %16 %34 - %36 = OpLoad %25 %g_sAniso - %37 = OpSampledImage %27 %35 %36 - %38 = OpImageSampleImplicitLod %v4float %37 %31 - OpStore %_entryPointOutput_vColor %38 -;CHECK-NOT: %38 = OpImageSampleImplicitLod %v4float %37 %31 -;CHECK-NOT: OpStore %_entryPointOutput_vColor %38 +%31 = OpLoad %v2float %i_vTextureCoords +%32 = OpAccessChain %_ptr_PushConstant_ushort %_ %int_0 +%33 = OpLoad %ushort %32 +%34 = OpAccessChain %_ptr_UniformConstant_16 %g_tColor %33 +%35 = OpLoad %16 %34 +%36 = OpLoad %25 %g_sAniso +%37 = OpSampledImage %27 %35 %36 +%38 = OpImageSampleImplicitLod %v4float %37 %31 +OpStore %_entryPointOutput_vColor %38 +;CHECK-NOT: %38 = OpImageSampleImplicitLod %v4float %37 %31 +;CHECK-NOT: OpStore %_entryPointOutput_vColor %38 ;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord ;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 ;CHECK: {{%\w+}} = OpUConvert %uint %33 -;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_61 {{%\w+}} %uint_1 %uint_2 {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_61 {{%\w+}} %uint_1 %uint_2 {{%\w+}} %uint_0 ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -4160,14 +4057,14 @@ TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} ;CHECK: OpStore %_entryPointOutput_vColor [[phi_result]] - OpReturn - OpFunctionEnd -)" + kStreamWrite6 + kCheckDesc; +OpReturn +OpFunctionEnd +)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { @@ -4208,100 +4105,99 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { // clang-format off const std::string text = R"( - OpCapability Shader - OpCapability Int16 - OpCapability StoragePushConstant16 -;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor -;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_FragCoord - OpExecutionMode %MainPs OriginUpperLeft - OpSource HLSL 500 - OpName %MainPs "MainPs" - OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t" - OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal" - OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins" - OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff" - OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t" - OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants" - OpName %_ "" - OpName %PerViewPushConst_t "PerViewPushConst_t" - OpMemberName %PerViewPushConst_t 0 "g_c" - OpName %__0 "" - OpName %g_tColor "g_tColor" - OpName %g_sAniso "g_sAniso" - OpName %i_vTextureCoords "i.vTextureCoords" - OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" - OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 RowMajor - OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 Offset 0 - OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 MatrixStride 16 - OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 1 Offset 48 - OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 2 Offset 64 - OpDecorate %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 ArrayStride 80 - OpMemberDecorate %_BindlessFastEnvMapCB_PS_t 0 Offset 0 - OpDecorate %_BindlessFastEnvMapCB_PS_t Block - OpDecorate %_ DescriptorSet 0 - OpDecorate %_ Binding 0 - OpMemberDecorate %PerViewPushConst_t 0 Offset 0 - OpDecorate %PerViewPushConst_t Block - OpDecorate %g_tColor DescriptorSet 0 - OpDecorate %g_tColor Binding 0 - OpDecorate %g_sAniso DescriptorSet 0 - OpDecorate %g_sAniso Binding 0 - OpDecorate %i_vTextureCoords Location 0 - OpDecorate %_entryPointOutput_vColor Location 0 -;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord - %void = OpTypeVoid - %14 = OpTypeFunction %void - %float = OpTypeFloat 32 - %v2float = OpTypeVector %float 2 - %v4float = OpTypeVector %float 4 - %v3float = OpTypeVector %float 3 +OpCapability Shader +OpCapability Int16 +OpCapability StoragePushConstant16 +;CHECK: OpCapability Linkage +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor +;CHECK: OpEntryPoint Fragment %MainPs "MainPs" %_ %__0 %g_tColor %g_sAniso %i_vTextureCoords %_entryPointOutput_vColor %gl_FragCoord +OpExecutionMode %MainPs OriginUpperLeft +OpSource HLSL 500 +OpName %MainPs "MainPs" +OpName %PerBatchEnvMapConstantBuffer_t "PerBatchEnvMapConstantBuffer_t" +OpMemberName %PerBatchEnvMapConstantBuffer_t 0 "g_matEnvMapWorldToLocal" +OpMemberName %PerBatchEnvMapConstantBuffer_t 1 "g_vEnvironmentMapBoxMins" +OpMemberName %PerBatchEnvMapConstantBuffer_t 2 "g_TexOff" +OpName %_BindlessFastEnvMapCB_PS_t "_BindlessFastEnvMapCB_PS_t" +OpMemberName %_BindlessFastEnvMapCB_PS_t 0 "g_envMapConstants" +OpName %_ "" +OpName %PerViewPushConst_t "PerViewPushConst_t" +OpMemberName %PerViewPushConst_t 0 "g_c" +OpName %__0 "" +OpName %g_tColor "g_tColor" +OpName %g_sAniso "g_sAniso" +OpName %i_vTextureCoords "i.vTextureCoords" +OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" +OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 RowMajor +OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 Offset 0 +OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 0 MatrixStride 16 +OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 1 Offset 48 +OpMemberDecorate %PerBatchEnvMapConstantBuffer_t 2 Offset 64 +OpDecorate %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 ArrayStride 80 +OpMemberDecorate %_BindlessFastEnvMapCB_PS_t 0 Offset 0 +OpDecorate %_BindlessFastEnvMapCB_PS_t Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 0 +OpMemberDecorate %PerViewPushConst_t 0 Offset 0 +OpDecorate %PerViewPushConst_t Block +OpDecorate %g_tColor DescriptorSet 0 +OpDecorate %g_tColor Binding 0 +OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %g_sAniso Binding 0 +OpDecorate %i_vTextureCoords Location 0 +OpDecorate %_entryPointOutput_vColor Location 0 +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%14 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%v4float = OpTypeVector %float 4 +%v3float = OpTypeVector %float 3 %mat4v3float = OpTypeMatrix %v3float 4 %PerBatchEnvMapConstantBuffer_t = OpTypeStruct %mat4v3float %v4float %v2float - %uint = OpTypeInt 32 0 - %uint_128 = OpConstant %uint 128 +%uint = OpTypeInt 32 0 +%uint_128 = OpConstant %uint 128 %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 = OpTypeArray %PerBatchEnvMapConstantBuffer_t %uint_128 %_BindlessFastEnvMapCB_PS_t = OpTypeStruct %_arr_PerBatchEnvMapConstantBuffer_t_uint_128 %_ptr_Uniform__BindlessFastEnvMapCB_PS_t = OpTypePointer Uniform %_BindlessFastEnvMapCB_PS_t - %_ = OpVariable %_ptr_Uniform__BindlessFastEnvMapCB_PS_t Uniform - %int = OpTypeInt 32 1 - %int_0 = OpConstant %int 0 - %ushort = OpTypeInt 16 0 +%_ = OpVariable %_ptr_Uniform__BindlessFastEnvMapCB_PS_t Uniform +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%ushort = OpTypeInt 16 0 %PerViewPushConst_t = OpTypeStruct %ushort %_ptr_PushConstant_PerViewPushConst_t = OpTypePointer PushConstant %PerViewPushConst_t - %__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant +%__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant %_ptr_PushConstant_ushort = OpTypePointer PushConstant %ushort - %int_2 = OpConstant %int 2 +%int_2 = OpConstant %int 2 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float - %30 = OpTypeImage %float 2D 0 0 0 1 Unknown +%30 = OpTypeImage %float 2D 0 0 0 1 Unknown %_ptr_UniformConstant_30 = OpTypePointer UniformConstant %30 - %g_tColor = OpVariable %_ptr_UniformConstant_30 UniformConstant - %32 = OpTypeSampler +%g_tColor = OpVariable %_ptr_UniformConstant_30 UniformConstant +%32 = OpTypeSampler %_ptr_UniformConstant_32 = OpTypePointer UniformConstant %32 - %g_sAniso = OpVariable %_ptr_UniformConstant_32 UniformConstant - %34 = OpTypeSampledImage %30 +%g_sAniso = OpVariable %_ptr_UniformConstant_32 UniformConstant +%34 = OpTypeSampledImage %30 %_ptr_Input_v2float = OpTypePointer Input %v2float %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -)" + kInputGlobals + kOutputGlobals + R"( -;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float -;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input -;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float - %MainPs = OpFunction %void None %14 - %37 = OpLabel - %38 = OpLoad %v2float %i_vTextureCoords - %39 = OpAccessChain %_ptr_PushConstant_ushort %__0 %int_0 - %40 = OpLoad %ushort %39 - %41 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %40 %int_2 - %42 = OpLoad %v2float %41 - %43 = OpFAdd %v2float %38 %42 -;CHECK-NOT: %42 = OpLoad %v2float %41 -;CHECK-NOT: %43 = OpFAdd %v2float %38 %42 +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float +)" + kImportStub + R"( +%MainPs = OpFunction %void None %14 +%37 = OpLabel +%38 = OpLoad %v2float %i_vTextureCoords +%39 = OpAccessChain %_ptr_PushConstant_ushort %__0 %int_0 +%40 = OpLoad %ushort %39 +%41 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %40 %int_2 +%42 = OpLoad %v2float %41 +%43 = OpFAdd %v2float %38 %42 +;CHECK-NOT: %42 = OpLoad %v2float %41 +;CHECK-NOT: %43 = OpFAdd %v2float %38 %42 ;CHECK: {{%\w+}} = OpUConvert %uint %40 ;CHECK: {{%\w+}} = OpIMul %uint %uint_80 {{%\w+}} ;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} @@ -4312,7 +4208,7 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_82 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_82 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -4323,19 +4219,19 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} ;CHECK: %43 = OpFAdd %v2float %38 {{%\w+}} - %44 = OpLoad %30 %g_tColor - %45 = OpLoad %32 %g_sAniso - %46 = OpSampledImage %34 %44 %45 - %47 = OpImageSampleImplicitLod %v4float %46 %43 - OpStore %_entryPointOutput_vColor %47 - OpReturn - OpFunctionEnd - )" + kStreamWrite6 + kCheckDesc; +%44 = OpLoad %30 %g_tColor +%45 = OpLoad %32 %g_sAniso +%46 = OpSampledImage %34 %44 %45 +%47 = OpImageSampleImplicitLod %v4float %46 %43 +OpStore %_entryPointOutput_vColor %47 +OpReturn +OpFunctionEnd +)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { @@ -4359,70 +4255,69 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { // clang-format off std::string text = R"( - OpCapability Shader -;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position -;CHECK: OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_VertexIndex %gl_InstanceIndex - OpSource GLSL 450 - OpSourceExtension "GL_EXT_scalar_block_layout" - OpName %main "main" - OpName %v_vtxResult "v_vtxResult" - OpName %Block "Block" - OpMemberName %Block 0 "var" - OpName %_ "" - OpName %a_position "a_position" - OpDecorate %v_vtxResult RelaxedPrecision - OpDecorate %v_vtxResult Location 0 - OpMemberDecorate %Block 0 RowMajor - OpMemberDecorate %Block 0 RelaxedPrecision - OpMemberDecorate %Block 0 Offset 0 - OpMemberDecorate %Block 0 MatrixStride 16 - OpDecorate %Block Block - OpDecorate %_ DescriptorSet 0 - OpDecorate %_ Binding 0 - OpDecorate %21 RelaxedPrecision -;CHECK-NOT: OpDecorate %21 RelaxedPrecision +OpCapability Shader +;CHECK: OpCapability Linkage +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position +;CHECK: OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %gl_VertexIndex %gl_InstanceIndex +OpSource GLSL 450 +OpSourceExtension "GL_EXT_scalar_block_layout" +OpName %main "main" +OpName %v_vtxResult "v_vtxResult" +OpName %Block "Block" +OpMemberName %Block 0 "var" +OpName %_ "" +OpName %a_position "a_position" +OpDecorate %v_vtxResult RelaxedPrecision +OpDecorate %v_vtxResult Location 0 +OpMemberDecorate %Block 0 RowMajor +OpMemberDecorate %Block 0 RelaxedPrecision +OpMemberDecorate %Block 0 Offset 0 +OpMemberDecorate %Block 0 MatrixStride 16 +OpDecorate %Block Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 0 +OpDecorate %21 RelaxedPrecision +;CHECK-NOT: OpDecorate %21 RelaxedPrecision ;CHECK: OpDecorate %v_vtxResult RelaxedPrecision ;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision - OpDecorate %a_position Location 0 -;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( +OpDecorate %a_position Location 0 +)" + kImportDeco + R"( ;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex ;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex ;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 %_ptr_Output_float = OpTypePointer Output %float %v_vtxResult = OpVariable %_ptr_Output_float Output - %v2float = OpTypeVector %float 2 +%v2float = OpTypeVector %float 2 %mat4v2float = OpTypeMatrix %v2float 4 - %Block = OpTypeStruct %mat4v2float +%Block = OpTypeStruct %mat4v2float %_ptr_Uniform_Block = OpTypePointer Uniform %Block - %_ = OpVariable %_ptr_Uniform_Block Uniform - %int = OpTypeInt 32 1 - %int_0 = OpConstant %int 0 - %int_2 = OpConstant %int 2 - %uint = OpTypeInt 32 0 - %uint_1 = OpConstant %uint 1 +%_ = OpVariable %_ptr_Uniform_Block Uniform +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%int_2 = OpConstant %int 2 +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 %_ptr_Uniform_float = OpTypePointer Uniform %float - %v4float = OpTypeVector %float 4 +%v4float = OpTypeVector %float 4 %_ptr_Input_v4float = OpTypePointer Input %v4float - %a_position = OpVariable %_ptr_Input_v4float Input -)" + kInputGlobals + kOutputGlobals + R"( -;CHECK:%_ptr_Input_uint = OpTypePointer Input %uint -;CHECK:%gl_VertexIndex = OpVariable %_ptr_Input_uint Input -;CHECK:%gl_InstanceIndex = OpVariable %_ptr_Input_uint Input +%a_position = OpVariable %_ptr_Input_v4float Input +;CHECK: %_ptr_Input_uint = OpTypePointer Input %uint +;CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_uint Input +;CHECK: %gl_InstanceIndex = OpVariable %_ptr_Input_uint Input ;CHECK: [[null_float:%\w+]] = OpConstantNull %float - %main = OpFunction %void None %3 - %5 = OpLabel +)" + kImportStub + R"( +%main = OpFunction %void None %3 +%5 = OpLabel ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel - %20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1 - %21 = OpLoad %float %20 -;CHECK-NOT: %21 = OpLoad %float %20 +%20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1 +%21 = OpLoad %float %20 +;CHECK-NOT: %21 = OpLoad %float %20 ;CHECK: {{%\w+}} = OpIMul %uint %uint_4 %int_2 ;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} ;CHECK: {{%\w+}} = OpIMul %uint %uint_16 %uint_1 @@ -4431,7 +4326,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex ;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 -;CHECK: [[desc_state:%\w+]] = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_46 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} +;CHECK: [[desc_state:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional [[desc_state]] {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -4441,17 +4336,17 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[phi_result]] = OpPhi %float [[load_result]] {{%\w+}} [[null_float]] {{%\w+}} - OpStore %v_vtxResult %21 -;CHECK-NOT: OpStore %v_vtxResult %21$ -;CHECK: OpStore %v_vtxResult [[phi_result]] - OpReturn - OpFunctionEnd - )" + kStreamWrite6 + kCheckDesc; +OpStore %v_vtxResult %21 +;CHECK-NOT: OpStore %v_vtxResult %21$ +;CHECK: OpStore %v_vtxResult [[phi_result]] +OpReturn +OpFunctionEnd +)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { @@ -4475,67 +4370,66 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { // clang-format off const std::string text = R"( - OpCapability Shader -;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position -;CHECK: OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_VertexIndex %gl_InstanceIndex - OpSource GLSL 450 - OpSourceExtension "GL_EXT_scalar_block_layout" - OpName %main "main" - OpName %v_vtxResult "v_vtxResult" - OpName %Block "Block" - OpMemberName %Block 0 "var" - OpName %_ "" - OpName %a_position "a_position" - OpDecorate %v_vtxResult RelaxedPrecision - OpDecorate %v_vtxResult Location 0 - OpMemberDecorate %Block 0 ColMajor - OpMemberDecorate %Block 0 RelaxedPrecision - OpMemberDecorate %Block 0 Offset 0 - OpMemberDecorate %Block 0 MatrixStride 8 - OpDecorate %Block Block - OpDecorate %_ DescriptorSet 0 - OpDecorate %_ Binding 0 - OpDecorate %21 RelaxedPrecision -;CHECK-NOT: OpDecorate %21 RelaxedPrecision +OpCapability Shader +;CHECK: OpCapability Linkage +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position +;CHECK: OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %gl_VertexIndex %gl_InstanceIndex +OpSource GLSL 450 +OpSourceExtension "GL_EXT_scalar_block_layout" +OpName %main "main" +OpName %v_vtxResult "v_vtxResult" +OpName %Block "Block" +OpMemberName %Block 0 "var" +OpName %_ "" +OpName %a_position "a_position" +OpDecorate %v_vtxResult RelaxedPrecision +OpDecorate %v_vtxResult Location 0 +OpMemberDecorate %Block 0 ColMajor +OpMemberDecorate %Block 0 RelaxedPrecision +OpMemberDecorate %Block 0 Offset 0 +OpMemberDecorate %Block 0 MatrixStride 8 +OpDecorate %Block Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 0 +OpDecorate %21 RelaxedPrecision +;CHECK-NOT: OpDecorate %21 RelaxedPrecision ;CHECK: OpDecorate %v_vtxResult RelaxedPrecision ;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision - OpDecorate %a_position Location 0 -;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( +OpDecorate %a_position Location 0 +)" + kImportDeco + R"( ;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex ;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex ;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 %_ptr_Output_float = OpTypePointer Output %float %v_vtxResult = OpVariable %_ptr_Output_float Output - %v2float = OpTypeVector %float 2 +%v2float = OpTypeVector %float 2 %mat4v2float = OpTypeMatrix %v2float 4 - %Block = OpTypeStruct %mat4v2float +%Block = OpTypeStruct %mat4v2float %_ptr_Uniform_Block = OpTypePointer Uniform %Block - %_ = OpVariable %_ptr_Uniform_Block Uniform - %int = OpTypeInt 32 1 - %int_0 = OpConstant %int 0 - %int_2 = OpConstant %int 2 - %uint = OpTypeInt 32 0 - %uint_1 = OpConstant %uint 1 +%_ = OpVariable %_ptr_Uniform_Block Uniform +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%int_2 = OpConstant %int 2 +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 %_ptr_Uniform_float = OpTypePointer Uniform %float - %v4float = OpTypeVector %float 4 +%v4float = OpTypeVector %float 4 %_ptr_Input_v4float = OpTypePointer Input %v4float - %a_position = OpVariable %_ptr_Input_v4float Input -)" + kInputGlobals + kOutputGlobals + R"( -;CHECK:%_ptr_Input_uint = OpTypePointer Input %uint -;CHECK:%gl_VertexIndex = OpVariable %_ptr_Input_uint Input -;CHECK:%gl_InstanceIndex = OpVariable %_ptr_Input_uint Input +%a_position = OpVariable %_ptr_Input_v4float Input +;CHECK: %_ptr_Input_uint = OpTypePointer Input %uint +;CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_uint Input +;CHECK: %gl_InstanceIndex = OpVariable %_ptr_Input_uint Input ;CHECK: [[null_float:%\w+]] = OpConstantNull %float +)" + kImportStub + R"( %main = OpFunction %void None %3 - %5 = OpLabel - %20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1 - %21 = OpLoad %float %20 +%5 = OpLabel +%20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1 +%21 = OpLoad %float %20 ;CHECK-NOT: %21 = OpLoad %float %20 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -4547,7 +4441,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { ;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex ;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 -;CHECK: [[desc_state:%\w+]] = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_46 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} +;CHECK: [[desc_state:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_46 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional [[desc_state]] {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -4557,18 +4451,18 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[phi_result]] = OpPhi %float [[load_result]] {{%\w+}} [[null_float]] {{%\w+}} - OpStore %v_vtxResult %21 -;CHECK-NOT: OpStore %v_vtxResult %21$ +OpStore %v_vtxResult %21 +;CHECK-NOT: OpStore %v_vtxResult %21$ ;CHECK: OpStore %v_vtxResult [[phi_result]] - OpReturn - OpFunctionEnd - )" + kStreamWrite6 + kCheckDesc; +OpReturn +OpFunctionEnd +)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); ValidatorOptions()->uniform_buffer_standard_layout = true; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { @@ -4592,71 +4486,70 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { // clang-format off const std::string text = R"( - OpCapability Shader -;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position -;CHECK: OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_VertexIndex %gl_InstanceIndex - OpSource GLSL 450 - OpSourceExtension "GL_EXT_scalar_block_layout" - OpName %main "main" - OpName %v_vtxResult "v_vtxResult" - OpName %Block "Block" - OpMemberName %Block 0 "var" - OpName %_ "" - OpName %a_position "a_position" - OpDecorate %v_vtxResult Location 0 - OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 32 - OpDecorate %_arr__arr_mat2v2float_uint_4_uint_3 ArrayStride 128 - OpMemberDecorate %Block 0 RowMajor - OpMemberDecorate %Block 0 RelaxedPrecision - OpMemberDecorate %Block 0 Offset 0 - OpMemberDecorate %Block 0 MatrixStride 16 - OpDecorate %Block Block - OpDecorate %_ DescriptorSet 3 - OpDecorate %_ Binding 7 - OpDecorate %26 RelaxedPrecision -;CHECK-NOT: OpDecorate %26 RelaxedPrecision +OpCapability Shader +;CHECK: OpCapability Linkage +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position +;CHECK: OpEntryPoint Vertex %main "main" %v_vtxResult %_ %a_position %gl_VertexIndex %gl_InstanceIndex +OpSource GLSL 450 +OpSourceExtension "GL_EXT_scalar_block_layout" +OpName %main "main" +OpName %v_vtxResult "v_vtxResult" +OpName %Block "Block" +OpMemberName %Block 0 "var" +OpName %_ "" +OpName %a_position "a_position" +OpDecorate %v_vtxResult Location 0 +OpDecorate %_arr_mat2v2float_uint_4 ArrayStride 32 +OpDecorate %_arr__arr_mat2v2float_uint_4_uint_3 ArrayStride 128 +OpMemberDecorate %Block 0 RowMajor +OpMemberDecorate %Block 0 RelaxedPrecision +OpMemberDecorate %Block 0 Offset 0 +OpMemberDecorate %Block 0 MatrixStride 16 +OpDecorate %Block Block +OpDecorate %_ DescriptorSet 3 +OpDecorate %_ Binding 7 +OpDecorate %26 RelaxedPrecision +;CHECK-NOT: OpDecorate %26 RelaxedPrecision ;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision - OpDecorate %a_position Location 0 -;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( +OpDecorate %a_position Location 0 +)" + kImportDeco + R"( ;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex ;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex ;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 - %v2float = OpTypeVector %float 2 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 %_ptr_Output_v2float = OpTypePointer Output %v2float %v_vtxResult = OpVariable %_ptr_Output_v2float Output %mat2v2float = OpTypeMatrix %v2float 2 - %uint = OpTypeInt 32 0 - %uint_4 = OpConstant %uint 4 +%uint = OpTypeInt 32 0 +%uint_4 = OpConstant %uint 4 %_arr_mat2v2float_uint_4 = OpTypeArray %mat2v2float %uint_4 - %uint_3 = OpConstant %uint 3 +%uint_3 = OpConstant %uint 3 %_arr__arr_mat2v2float_uint_4_uint_3 = OpTypeArray %_arr_mat2v2float_uint_4 %uint_3 - %Block = OpTypeStruct %_arr__arr_mat2v2float_uint_4_uint_3 +%Block = OpTypeStruct %_arr__arr_mat2v2float_uint_4_uint_3 %_ptr_Uniform_Block = OpTypePointer Uniform %Block - %_ = OpVariable %_ptr_Uniform_Block Uniform - %int = OpTypeInt 32 1 - %int_0 = OpConstant %int 0 - %int_2 = OpConstant %int 2 - %int_3 = OpConstant %int 3 - %int_1 = OpConstant %int 1 +%_ = OpVariable %_ptr_Uniform_Block Uniform +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%int_2 = OpConstant %int 2 +%int_3 = OpConstant %int 3 +%int_1 = OpConstant %int 1 %_ptr_Uniform_v2float = OpTypePointer Uniform %v2float - %v4float = OpTypeVector %float 4 +%v4float = OpTypeVector %float 4 %_ptr_Input_v4float = OpTypePointer Input %v4float - %a_position = OpVariable %_ptr_Input_v4float Input -)" + kInputGlobals + kOutputGlobals + R"( -;CHECK:%_ptr_Input_uint = OpTypePointer Input %uint -;CHECK:%gl_VertexIndex = OpVariable %_ptr_Input_uint Input -;CHECK:%gl_InstanceIndex = OpVariable %_ptr_Input_uint Input +%a_position = OpVariable %_ptr_Input_v4float Input +;CHECK: %_ptr_Input_uint = OpTypePointer Input %uint +;CHECK: %gl_VertexIndex = OpVariable %_ptr_Input_uint Input +;CHECK: %gl_InstanceIndex = OpVariable %_ptr_Input_uint Input ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float - %main = OpFunction %void None %3 - %5 = OpLabel - %25 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %int_2 %int_3 %int_1 +)" + kImportStub + R"( +%main = OpFunction %void None %3 +%5 = OpLabel +%25 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %int_2 %int_3 %int_1 ;CHECK: {{%\w+}} = OpIMul %uint %uint_128 %int_2 ;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} ;CHECK: {{%\w+}} = OpIMul %uint %uint_32 %int_3 @@ -4667,11 +4560,11 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { ;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex ;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 -;CHECK: [[desc_state:%\w+]] = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_52 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}} - %26 = OpLoad %v2float %25 - OpStore %v_vtxResult %26 +;CHECK: [[desc_state:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}} +%26 = OpLoad %v2float %25 +OpStore %v_vtxResult %26 ;CHECK-NOT: %26 = OpLoad %v2float %25 -;CHECK-NOT: OpStore %v_vtxResult %26 +;CHECK-NOT: OpStore %v_vtxResult %26 ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional [[desc_state]] {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -4682,14 +4575,14 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[phi_result]] = OpPhi %v2float [[load_result]] {{%\w+}} [[null_v2float]] {{%\w+}} ;CHECK: OpStore %v_vtxResult [[phi_result]] - OpReturn - OpFunctionEnd - )" + kStreamWrite6 + kCheckDesc; +OpReturn +OpFunctionEnd +)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } TEST_F(InstBindlessTest, ImageBufferOOBRead) { @@ -4706,61 +4599,57 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { // clang-format off const std::string text = R"( - OpCapability Shader - OpCapability ImageBuffer -;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %main "main" %x %s %ii - OpExecutionMode %main OriginUpperLeft - OpSource GLSL 450 - OpName %main "main" - OpName %x "x" - OpName %s "s" - OpName %ii "ii" - OpDecorate %x Location 11 - OpDecorate %s DescriptorSet 3 - OpDecorate %s Binding 7 - OpDecorate %s NonWritable - OpDecorate %ii Flat - OpDecorate %ii Location 13 -;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 - %v4float = OpTypeVector %float 4 - %_ptr_Output_v4float = OpTypePointer Output %v4float - %x = OpVariable %_ptr_Output_v4float Output - %10 = OpTypeImage %float Buffer 0 0 0 2 R32f - %_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10 - %s = OpVariable %_ptr_UniformConstant_10 UniformConstant - %int = OpTypeInt 32 1 - %_ptr_Input_int = OpTypePointer Input %int - %ii = OpVariable %_ptr_Input_int Input -;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + kOutputGlobals + R"( -;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +OpCapability Shader +OpCapability ImageBuffer +;CHECK: OpCapability Linkage +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %x %s %ii +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpName %main "main" +OpName %x "x" +OpName %s "s" +OpName %ii "ii" +OpDecorate %x Location 11 +OpDecorate %s DescriptorSet 3 +OpDecorate %s Binding 7 +OpDecorate %s NonWritable +OpDecorate %ii Flat +OpDecorate %ii Location 13 +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%x = OpVariable %_ptr_Output_v4float Output +%10 = OpTypeImage %float Buffer 0 0 0 2 R32f +%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10 +%s = OpVariable %_ptr_UniformConstant_10 UniformConstant +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%ii = OpVariable %_ptr_Input_int Input +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float - %main = OpFunction %void None %3 - %5 = OpLabel -;CHECK: OpBranch %19 -;CHECK: %19 = OpLabel - %13 = OpLoad %10 %s - %17 = OpLoad %int %ii - %18 = OpImageRead %v4float %13 %17 - OpStore %x %18 -;CHECK-NOT: %18 = OpImageRead %v4float %13 %17 -;CHECK-NOT: OpStore %x %18 +%main = OpFunction %void None %3 +%5 = OpLabel +;CHECK: OpBranch %19 +;CHECK: %19 = OpLabel +%13 = OpLoad %10 %s +%17 = OpLoad %int %ii +%18 = OpImageRead %v4float %13 %17 +OpStore %x %18 +;CHECK-NOT: %18 = OpImageRead %v4float %13 %17 +;CHECK-NOT: OpStore %x %18 ;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord ;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_34 {{%\w+}} %uint_3 %uint_7 %uint_0 %22 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_34 {{%\w+}} %uint_3 %uint_7 %uint_0 %22 ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -4774,12 +4663,12 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { ;CHECK: OpStore %x [[phi_result]] OpReturn OpFunctionEnd - )" + kStreamWrite6 + kCheckDesc; +)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } TEST_F(InstBindlessTest, ImageBufferOOBWrite) { @@ -4796,78 +4685,75 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { // clang-format off const std::string text = R"( - OpCapability Shader - OpCapability ImageBuffer -;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %main "main" %s %ii %x -;CHECK: OpEntryPoint Fragment %main "main" %s %ii %x %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_FragCoord - OpExecutionMode %main OriginUpperLeft - OpSource GLSL 450 - OpName %main "main" - OpName %s "s" - OpName %ii "ii" - OpName %x "x" - OpDecorate %s DescriptorSet 3 - OpDecorate %s Binding 7 - OpDecorate %s NonReadable - OpDecorate %ii Flat - OpDecorate %ii Location 13 - OpDecorate %x Location 11 -;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 - %7 = OpTypeImage %float Buffer 0 0 0 2 R32f - %_ptr_UniformConstant_7 = OpTypePointer UniformConstant %7 - %s = OpVariable %_ptr_UniformConstant_7 UniformConstant - %int = OpTypeInt 32 1 - %_ptr_Input_int = OpTypePointer Input %int - %ii = OpVariable %_ptr_Input_int Input - %v4float = OpTypeVector %float 4 - %_ptr_Output_v4float = OpTypePointer Output %v4float - %x = OpVariable %_ptr_Output_v4float Output -;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + kOutputGlobals + R"( -;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input - %main = OpFunction %void None %3 - %5 = OpLabel -;CHECK: {{%\w+}} = OpLabel -;CHECK: OpBranch {{%\w+}} -;CHECK: %19 = OpLabel - %10 = OpLoad %7 %s - %14 = OpLoad %int %ii - %18 = OpLoad %v4float %x - OpImageWrite %10 %14 %18 -;CHECK-NOT: OpImageWrite %10 %14 %18 -;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_35 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}} -;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpLoad %7 %s -;CHECK: OpImageWrite {{%\w+}} %14 %18 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel +OpCapability Shader +OpCapability ImageBuffer +;CHECK: OpCapability Linkage +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %s %ii %x +;CHECK: OpEntryPoint Fragment %main "main" %s %ii %x %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpName %main "main" +OpName %s "s" +OpName %ii "ii" +OpName %x "x" +OpDecorate %s DescriptorSet 3 +OpDecorate %s Binding 7 +OpDecorate %s NonReadable +OpDecorate %ii Flat +OpDecorate %ii Location 13 +OpDecorate %x Location 11 +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%7 = OpTypeImage %float Buffer 0 0 0 2 R32f +%_ptr_UniformConstant_7 = OpTypePointer UniformConstant %7 +%s = OpVariable %_ptr_UniformConstant_7 UniformConstant +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%ii = OpVariable %_ptr_Input_int Input +%v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%x = OpVariable %_ptr_Output_v4float Output +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +)" + kImportStub + R"( +%main = OpFunction %void None %3 +%5 = OpLabel +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: %19 = OpLabel +%10 = OpLoad %7 %s +%14 = OpLoad %int %ii +%18 = OpLoad %v4float %x +OpImageWrite %10 %14 %18 +;CHECK-NOT: OpImageWrite %10 %14 %18 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_35 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %7 %s +;CHECK: OpImageWrite {{%\w+}} %14 %18 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd -)" + kStreamWrite6 + kCheckDesc; +)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } TEST_F(InstBindlessTest, TextureBufferOOBFetch) { @@ -4884,60 +4770,56 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { // clang-format off const std::string text = R"( - OpCapability Shader - OpCapability SampledBuffer -;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %main "main" %x %s %ii -;CHECK: OpEntryPoint Fragment %main "main" %x %s %ii %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_FragCoord - OpExecutionMode %main OriginUpperLeft - OpSource GLSL 450 - OpName %main "main" - OpName %x "x" - OpName %s "s" - OpName %ii "ii" - OpDecorate %x Location 11 - OpDecorate %s DescriptorSet 3 - OpDecorate %s Binding 7 - OpDecorate %ii Flat - OpDecorate %ii Location 13 -)" + kInputDecorations + kOutputDecorations + R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 - %v4float = OpTypeVector %float 4 - %_ptr_Output_v4float = OpTypePointer Output %v4float - %x = OpVariable %_ptr_Output_v4float Output - %10 = OpTypeImage %float Buffer 0 0 0 1 Unknown - %_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10 - %s = OpVariable %_ptr_UniformConstant_10 UniformConstant - %int = OpTypeInt 32 1 - %_ptr_Input_int = OpTypePointer Input %int - %ii = OpVariable %_ptr_Input_int Input -;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + kOutputGlobals + R"( -;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +OpCapability Shader +OpCapability SampledBuffer +;CHECK: OpCapability Linkage +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %x %s %ii +;CHECK: OpEntryPoint Fragment %main "main" %x %s %ii %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpName %main "main" +OpName %x "x" +OpName %s "s" +OpName %ii "ii" +OpDecorate %x Location 11 +OpDecorate %s DescriptorSet 3 +OpDecorate %s Binding 7 +OpDecorate %ii Flat +OpDecorate %ii Location 13 +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%x = OpVariable %_ptr_Output_v4float Output +%10 = OpTypeImage %float Buffer 0 0 0 1 Unknown +%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10 +%s = OpVariable %_ptr_UniformConstant_10 UniformConstant +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%ii = OpVariable %_ptr_Input_int Input +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float - %main = OpFunction %void None %3 - %5 = OpLabel -;CHECK: OpBranch %19 -;CHECK: %19 = OpLabel - %13 = OpLoad %10 %s - %17 = OpLoad %int %ii - %18 = OpImageFetch %v4float %13 %17 - OpStore %x %18 -;CHECK-NOT: %18 = OpImageFetch %v4float %13 %17 -;CHECK-NOT: OpStore %x %18 +%main = OpFunction %void None %3 +%5 = OpLabel +;CHECK: OpBranch %19 +;CHECK: %19 = OpLabel +%13 = OpLoad %10 %s +%17 = OpLoad %int %ii +%18 = OpImageFetch %v4float %13 %17 +OpStore %x %18 +;CHECK-NOT: %18 = OpImageFetch %v4float %13 %17 +;CHECK-NOT: OpStore %x %18 ;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord ;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_33 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_33 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}} ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -4951,12 +4833,12 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: OpStore %x [[phi_result]] OpReturn OpFunctionEnd - )" + kStreamWrite6 + kCheckDesc; +)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { @@ -4973,62 +4855,60 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { // clang-format off const std::string text = R"( - OpCapability Shader - OpCapability SampledBuffer -;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %main "main" %x %s %ii -;CHECK: OpEntryPoint Fragment %main "main" %x %s %ii %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_FragCoord - OpExecutionMode %main OriginUpperLeft - OpSource GLSL 450 - OpName %main "main" - OpName %x "x" - OpName %s "s" - OpName %ii "ii" - OpDecorate %x Location 11 - OpDecorate %s DescriptorSet 3 - OpDecorate %s Binding 7 - OpDecorate %ii Flat - OpDecorate %ii Location 13 -;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + kOutputDecorations + R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 - %v4float = OpTypeVector %float 4 - %_ptr_Output_v4float = OpTypePointer Output %v4float - %x = OpVariable %_ptr_Output_v4float Output - %10 = OpTypeImage %float Buffer 0 0 0 1 Unknown - %11 = OpTypeSampledImage %10 - %_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11 - %s = OpVariable %_ptr_UniformConstant_11 UniformConstant - %int = OpTypeInt 32 1 - %_ptr_Input_int = OpTypePointer Input %int - %ii = OpVariable %_ptr_Input_int Input -)" + kInputGlobals + kOutputGlobals + R"( -;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +OpCapability Shader +OpCapability SampledBuffer +;CHECK: OpCapability Linkage +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %x %s %ii +;CHECK: OpEntryPoint Fragment %main "main" %x %s %ii %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpName %main "main" +OpName %x "x" +OpName %s "s" +OpName %ii "ii" +OpDecorate %x Location 11 +OpDecorate %s DescriptorSet 3 +OpDecorate %s Binding 7 +OpDecorate %ii Flat +OpDecorate %ii Location 13 +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%x = OpVariable %_ptr_Output_v4float Output +%10 = OpTypeImage %float Buffer 0 0 0 1 Unknown +%11 = OpTypeSampledImage %10 +%_ptr_UniformConstant_11 = OpTypePointer UniformConstant %11 +%s = OpVariable %_ptr_UniformConstant_11 UniformConstant +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%ii = OpVariable %_ptr_Input_int Input +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float - %main = OpFunction %void None %3 - %5 = OpLabel -;CHECK: OpBranch %21 -;CHECK: %21 = OpLabel - %14 = OpLoad %11 %s - %18 = OpLoad %int %ii - %19 = OpImage %10 %14 - %20 = OpImageFetch %v4float %19 %18 - OpStore %x %20 -;CHECK-NOT: %20 = OpImageFetch %v4float %19 %18 -;CHECK-NOT: OpStore %x %20 +)" + kImportStub + R"( +%main = OpFunction %void None %3 +%5 = OpLabel +;CHECK: OpBranch %21 +;CHECK: %21 = OpLabel +%14 = OpLoad %11 %s +%18 = OpLoad %int %ii +%19 = OpImage %10 %14 +%20 = OpImageFetch %v4float %19 %18 +OpStore %x %20 +;CHECK-NOT: %20 = OpImageFetch %v4float %19 %18 +;CHECK-NOT: OpStore %x %20 ;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord ;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_35 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_35 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}} ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -5043,12 +4923,12 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: OpStore %x [[phi_result]] OpReturn OpFunctionEnd -)" + kStreamWrite6 + kCheckDesc; +)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { @@ -5066,68 +4946,65 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { // clang-format off const std::string text = R"( - OpCapability Shader - OpCapability SampledBuffer -;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" - %1 = OpExtInstImport "GLSL.std.450" - OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %main "main" %x %tBuf %s %ii -;CHECK: OpEntryPoint Fragment %main "main" %x %tBuf %s %ii %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_FragCoord - OpExecutionMode %main OriginUpperLeft - OpSource GLSL 450 - OpName %main "main" - OpName %x "x" - OpName %tBuf "tBuf" - OpName %s "s" - OpName %ii "ii" - OpDecorate %x Location 11 - OpDecorate %tBuf DescriptorSet 3 - OpDecorate %tBuf Binding 7 - OpDecorate %s DescriptorSet 3 - OpDecorate %s Binding 8 - OpDecorate %ii Flat - OpDecorate %ii Location 13 -)" + kInputDecorations + kOutputDecorations + R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord - %void = OpTypeVoid - %3 = OpTypeFunction %void - %float = OpTypeFloat 32 - %v4float = OpTypeVector %float 4 - %_ptr_Output_v4float = OpTypePointer Output %v4float - %x = OpVariable %_ptr_Output_v4float Output - %10 = OpTypeImage %float Buffer 0 0 0 1 Unknown - %_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10 - %tBuf = OpVariable %_ptr_UniformConstant_10 UniformConstant - %14 = OpTypeSampler - %_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14 - %s = OpVariable %_ptr_UniformConstant_14 UniformConstant - %18 = OpTypeSampledImage %10 - %int = OpTypeInt 32 1 - %_ptr_Input_int = OpTypePointer Input %int - %ii = OpVariable %_ptr_Input_int Input -;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + kOutputGlobals + R"( -;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float - %main = OpFunction %void None %3 - %5 = OpLabel - %13 = OpLoad %10 %tBuf - %17 = OpLoad %14 %s - %19 = OpSampledImage %18 %13 %17 - %23 = OpLoad %int %ii - %24 = OpImage %10 %19 - %25 = OpImageFetch %v4float %24 %23 - OpStore %x %25 -;CHECK-NOT: %25 = OpImageFetch %v4float %24 %23 -;CHECK-NOT: OpStore %x %25 +OpCapability Shader +OpCapability SampledBuffer +;CHECK: OpCapability Linkage +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %x %tBuf %s %ii +;CHECK: OpEntryPoint Fragment %main "main" %x %tBuf %s %ii %gl_FragCoord +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 450 +OpName %main "main" +OpName %x "x" +OpName %tBuf "tBuf" +OpName %s "s" +OpName %ii "ii" +OpDecorate %x Location 11 +OpDecorate %tBuf DescriptorSet 3 +OpDecorate %tBuf Binding 7 +OpDecorate %s DescriptorSet 3 +OpDecorate %s Binding 8 +OpDecorate %ii Flat +OpDecorate %ii Location 13 +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%x = OpVariable %_ptr_Output_v4float Output +%10 = OpTypeImage %float Buffer 0 0 0 1 Unknown +%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10 +%tBuf = OpVariable %_ptr_UniformConstant_10 UniformConstant +%14 = OpTypeSampler +%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14 +%s = OpVariable %_ptr_UniformConstant_14 UniformConstant +%18 = OpTypeSampledImage %10 +%int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int +%ii = OpVariable %_ptr_Input_int Input +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +%main = OpFunction %void None %3 +%5 = OpLabel +%13 = OpLoad %10 %tBuf +%17 = OpLoad %14 %s +%19 = OpSampledImage %18 %13 %17 +%23 = OpLoad %int %ii +%24 = OpImage %10 %19 +%25 = OpImageFetch %v4float %24 %23 +OpStore %x %25 +;CHECK-NOT: %25 = OpImageFetch %v4float %24 %23 +;CHECK-NOT: OpStore %x %25 ;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord ;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 ;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_43 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_43 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}} ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -5141,14 +5018,14 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} ;CHECK: OpStore %x [[phi_result]] - OpReturn - OpFunctionEnd - )" + kStreamWrite6 + kCheckDesc; +OpReturn +OpFunctionEnd +)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } TEST_F(InstBindlessTest, DeviceBufferAddressOOB) { @@ -5172,11 +5049,13 @@ TEST_F(InstBindlessTest, DeviceBufferAddressOOB) { const std::string text = R"( OpCapability Shader OpCapability PhysicalStorageBufferAddresses +;CHECK: OpCapability Linkage ;CHECK: OpCapability Int64 +OpExtension "SPV_KHR_physical_storage_buffer" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel PhysicalStorageBuffer64 GLSL450 OpEntryPoint Vertex %main "main" %u_info -;CHECK: OpEntryPoint Vertex %main "main" %u_info %inst_bindless_input_buffer %inst_bindless_output_buffer %gl_VertexIndex %gl_InstanceIndex +;CHECK: OpEntryPoint Vertex %main "main" %u_info %gl_VertexIndex %gl_InstanceIndex OpSource GLSL 450 OpSourceExtension "GL_EXT_buffer_reference" OpName %main "main" @@ -5194,9 +5073,8 @@ OpDecorate %_arr_int_uint_4 ArrayStride 16 OpMemberDecorate %bufStruct 0 Offset 0 OpDecorate %bufStruct Block OpDecorate %u_info DescriptorSet 0 -OpDecorate %u_info Binding 0)" - + kInputDecorations + kOutputDecorations + -R"(%void = OpTypeVoid +OpDecorate %u_info Binding 0 +%void = OpTypeVoid %3 = OpTypeFunction %void %int = OpTypeInt 32 1 %_ptr_Function_int = OpTypePointer Function %int @@ -5215,9 +5093,9 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer %bool = OpTypeBool %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct %int_n559035791 = OpConstant %int -559035791 -%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int)" - + kInputGlobals + kOutputGlobals + -R"(%main = OpFunction %void None %3 +%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int +)" + kImportStub + R"( +%main = OpFunction %void None %3 %5 = OpLabel %i = OpVariable %_ptr_Function_int Function OpStore %i %int_0 @@ -5232,7 +5110,7 @@ OpBranch %14 ;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex ;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 -;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_55 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_56 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -5256,7 +5134,7 @@ OpBranchConditional %29 %11 %12 ;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex ;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 -;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_60 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_61 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -5280,13 +5158,12 @@ OpStore %i %38 OpBranch %10 %12 = OpLabel OpReturn -OpFunctionEnd)" - + kStreamWrite6 + kCheckDesc; +OpFunctionEnd)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } TEST_F(InstBindlessTest, VertexIndexOOB) { @@ -5332,9 +5209,8 @@ OpDecorate %_arr_uint_uint_1 ArrayStride 16 OpMemberDecorate %foo 0 Offset 0 OpDecorate %foo Block OpDecorate %uniform_index_buffer DescriptorSet 0 -OpDecorate %uniform_index_buffer Binding 0)" - + kInputDecorations + kOutputDecorations + -R"(%void = OpTypeVoid +OpDecorate %uniform_index_buffer Binding 0 +%void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 %v2float = OpTypeVector %float 2 @@ -5370,9 +5246,9 @@ R"(%void = OpTypeVoid %foo = OpTypeStruct %_arr_uint_uint_1 %_ptr_Uniform_foo = OpTypePointer Uniform %foo %uniform_index_buffer = OpVariable %_ptr_Uniform_foo Uniform -%_ptr_Uniform_uint = OpTypePointer Uniform %uint)" - + kInputGlobals + kOutputGlobals + -R"(%main = OpFunction %void None %3 +%_ptr_Uniform_uint = OpTypePointer Uniform %uint +)" + kImportStub + R"( +%main = OpFunction %void None %3 %5 = OpLabel %18 = OpAccessChain %_ptr_Private_v2float %vertices %int_0 OpStore %18 %16 @@ -5391,36 +5267,35 @@ OpStore %26 %25 OpStore %44 %42 %52 = OpAccessChain %_ptr_Uniform_uint %uniform_index_buffer %int_0 %int_0 %53 = OpLoad %uint %52 -; CHECK-NOT: %53 = OpLoad %uint %52 -; CHECK: {{%\w+}} = OpIMul %uint %uint_16 %int_0 -; CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 -; CHECK: {{%\w+}} = OpLoad %int %gl_VertexIndex -; CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_desc_check %uint_23 %uint_87 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %uint %52 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: OpStore %index [[phi_result]] +;CHECK-NOT: %53 = OpLoad %uint %52 +;CHECK: {{%\w+}} = OpIMul %uint %uint_16 %int_0 +;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} +;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 +;CHECK: {{%\w+}} = OpLoad %int %gl_VertexIndex +;CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}} +;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_87 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %uint %52 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: OpStore %index [[phi_result]] OpStore %index %53 -; CHECK-NOT: OpStore %index %53 +;CHECK-NOT: OpStore %index %53 OpReturn ;CHECK: OpReturn -OpFunctionEnd)" - + kStreamWrite6 + kCheckDesc; +OpFunctionEnd)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u); + SinglePassRunAndMatch(text, true, 23u); } // TODO(greg-lunarg): Add tests to verify handling of these cases: diff --git a/test/opt/inst_buff_addr_check_test.cpp b/test/opt/inst_buff_addr_check_test.cpp index 99f88f44c4..72d343852a 100644 --- a/test/opt/inst_buff_addr_check_test.cpp +++ b/test/opt/inst_buff_addr_check_test.cpp @@ -26,123 +26,14 @@ namespace spvtools { namespace opt { namespace { -static const std::string kOutputDecorations = R"( -; CHECK: OpDecorate [[output_buffer_type:%inst_buff_addr_OutputBuffer]] Block -; CHECK: OpMemberDecorate [[output_buffer_type]] 0 Offset 0 -; CHECK: OpMemberDecorate [[output_buffer_type]] 1 Offset 4 -; CHECK: OpDecorate [[output_buffer_var:%\w+]] DescriptorSet 7 -; CHECK: OpDecorate [[output_buffer_var]] Binding 0 +static const std::string kFuncName = "inst_buff_addr_search_and_test"; +static const std::string kImportDeco = R"( +;CHECK: OpDecorate %)" + kFuncName + R"( LinkageAttributes ")" + + kFuncName + R"(" Import )"; - -static const std::string kOutputGlobals = R"( -; CHECK: [[output_buffer_type]] = OpTypeStruct %uint %uint %_runtimearr_uint -; CHECK: [[output_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[output_buffer_type]] -; CHECK: [[output_buffer_var]] = OpVariable [[output_ptr_type]] StorageBuffer -)"; - -static const std::string kStreamWrite3 = R"( -; CHECK: %inst_buff_addr_stream_write_3 = OpFunction %void None {{%\w+}} -; CHECK: [[sw_shader_id:%\w+]] = OpFunctionParameter %uint -; CHECK: [[sw_inst_idx:%\w+]] = OpFunctionParameter %uint -; CHECK: [[sw_stage_info:%\w+]] = OpFunctionParameter %v4uint -; CHECK: [[sw_param_1:%\w+]] = OpFunctionParameter %uint -; CHECK: [[sw_param_2:%\w+]] = OpFunctionParameter %uint -; CHECK: [[sw_param_3:%\w+]] = OpFunctionParameter %uint -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 -; CHECK: {{%\w+}} = OpAtomicIAdd %uint {{%\w+}} %uint_4 %uint_0 %uint_10 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10 -; CHECK: {{%\w+}} = OpArrayLength %uint [[output_buffer_var]] 2 -; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} %uint_10 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[sw_shader_id]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_2 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[sw_inst_idx]] -; CHECK: {{%\w+}} = OpCompositeExtract %uint [[sw_stage_info]] 0 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint [[sw_stage_info]] 1 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint [[sw_stage_info]] 2 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint [[sw_stage_info]] 3 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[sw_param_1]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[sw_param_2]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_9 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[sw_param_3]] -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpReturn -; CHECK: OpFunctionEnd -)"; - -static const std::string kInputDecorations = R"( -; CHECK: OpDecorate [[input_buffer_type:%inst_buff_addr_InputBuffer]] Block -; CHECK: OpMemberDecorate [[input_buffer_type]] 0 Offset 0 -; CHECK: OpDecorate [[input_buffer_var:%\w+]] DescriptorSet 7 -; CHECK: OpDecorate [[input_buffer_var]] Binding 2 -)"; - -static const std::string kInputGlobals = R"( -; CHECK: [[input_buffer_type]] = OpTypeStruct %_runtimearr_ulong -; CHECK: [[input_ptr_type:%\w+]] = OpTypePointer StorageBuffer [[input_buffer_type]] -; CHECK: [[input_buffer_var]] = OpVariable [[input_ptr_type]] StorageBuffer -)"; - -static const std::string kSearchAndTest = R"( -; CHECK: {{%\w+}} = OpFunction %bool None {{%\w+}} -; CHECK: [[param_1:%\w+]] = OpFunctionParameter %ulong -; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %uint %uint_1 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: OpLoopMerge {{%\w+}} {{%\w+}} None -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_ulong [[input_buffer_var]] %uint_0 {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %ulong {{%\w+}} -; CHECK: {{%\w+}} = OpUGreaterThan %bool {{%\w+}} [[param_1]] -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpISub %uint {{%\w+}} %uint_1 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_ulong [[input_buffer_var]] %uint_0 {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %ulong {{%\w+}} -; CHECK: {{%\w+}} = OpISub %ulong [[param_1]] {{%\w+}} -; CHECK: {{%\w+}} = OpUConvert %ulong [[param_2]] -; CHECK: {{%\w+}} = OpIAdd %ulong {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_ulong [[input_buffer_var]] %uint_0 %uint_0 -; CHECK: {{%\w+}} = OpLoad %ulong {{%\w+}} -; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}} -; CHECK: {{%\w+}} = OpISub %uint {{%\w+}} %uint_1 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_ulong [[input_buffer_var]] %uint_0 {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %ulong {{%\w+}} -; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}} -; CHECK: OpReturnValue {{%\w+}} -; CHECK: OpFunctionEnd +static const std::string kImportStub = R"( +;CHECK: %)" + kFuncName + R"( = OpFunction %bool None {{%\w+}} +;CHECK: OpFunctionEnd )"; // clang-format on @@ -171,13 +62,13 @@ TEST_F(InstBuffAddrTest, InstPhysicalStorageBufferStore) { const std::string defs = R"( OpCapability Shader OpCapability PhysicalStorageBufferAddresses -; CHECK: OpCapability Int64 +;CHECK: OpCapability Int64 OpExtension "SPV_EXT_physical_storage_buffer" -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" +;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel PhysicalStorageBuffer64 GLSL450 OpEntryPoint GLCompute %main "main" -; CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID +;CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID OpExecutionMode %main LocalSize 1 1 1 OpSource GLSL 450 OpSourceExtension "GL_EXT_buffer_reference" @@ -202,11 +93,8 @@ OpMemberDecorate %bufStruct 1 Offset 32 OpDecorate %bufStruct Block OpDecorate %u_info DescriptorSet 0 OpDecorate %u_info Binding 0 -; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8 -)" + kInputDecorations + R"( -; CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId )"; const std::string globals = R"( @@ -227,17 +115,11 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer %int_1 = OpConstant %int 1 %int_3239 = OpConstant %int 3239 %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int -; CHECK: %ulong = OpTypeInt 64 0 -; CHECK: %bool = OpTypeBool -; CHECK: %_runtimearr_ulong = OpTypeRuntimeArray %ulong -)" + kInputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_ulong = OpTypePointer StorageBuffer %ulong -; CHECK: %v3uint = OpTypeVector %uint 3 -; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint -; CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kOutputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +;CHECK: %ulong = OpTypeInt 64 0 +;CHECK: %bool = OpTypeBool +;CHECK: %v3uint = OpTypeVector %uint 3 +;CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint +;CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input )"; // clang-format off @@ -247,41 +129,35 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer %17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 %18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17 %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1 -; CHECK-NOT: %17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 -; CHECK-NOT: %18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17 -; CHECK-NOT: %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1 -; CHECK: %20 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 -; CHECK: %21 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %20 -; CHECK: %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %21 %int_1 -; CHECK: {{%\w+}} = OpConvertPtrToU %ulong %22 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_buff_addr_search_and_test {{%\w+}} %uint_4 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel +;CHECK-NOT: %17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 +;CHECK-NOT: %18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17 +;CHECK-NOT: %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1 +;CHECK: %20 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 +;CHECK: %21 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %20 +;CHECK: %22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %21 %int_1 +;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %22 +;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} {{%\w+}} %uint_4 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel OpStore %22 %int_3239 Aligned 16 -; CHECK: OpStore %22 %int_3239 Aligned 16 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}} -; CHECK: {{%\w+}} = OpShiftRightLogical %ulong {{%\w+}} %uint_32 -; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_buff_addr_stream_write_3 %uint_23 %uint_48 {{%\w+}} %uint_3 {{%\w+}} {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel +;CHECK: OpStore %22 %int_3239 Aligned 16 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - const std::string output_funcs = kSearchAndTest + kStreamWrite3; - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch( - defs + decorates + globals + main_func + output_funcs, true, 7u, 23u); + defs + decorates + globals + kImportStub + main_func, true, 23u); } TEST_F(InstBuffAddrTest, InstPhysicalStorageBufferLoadAndStore) { @@ -311,7 +187,7 @@ TEST_F(InstBuffAddrTest, InstPhysicalStorageBufferLoadAndStore) { const std::string defs = R"( OpCapability Shader OpCapability PhysicalStorageBufferAddresses -; CHECK: OpCapability Int64 +;CHECK: OpCapability Int64 OpExtension "SPV_EXT_physical_storage_buffer" OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" @@ -321,7 +197,7 @@ OpExecutionMode %main LocalSize 1 1 1 OpSource GLSL 450 OpSourceExtension "GL_EXT_buffer_reference" OpName %main "main" -; CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID +;CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID OpName %blockType "blockType" OpMemberName %blockType 0 "x" OpMemberName %blockType 1 "next" @@ -339,12 +215,9 @@ OpMemberDecorate %rootBlock 0 Offset 0 OpDecorate %rootBlock Block OpDecorate %r DescriptorSet 0 OpDecorate %r Binding 0 -; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8 -)" + kInputDecorations + R"( -; CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations; - // clang-format on +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId +)"; const std::string globals = R"( %void = OpTypeVoid @@ -362,7 +235,7 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType %int_531 = OpConstant %int 531 %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int -)" + kInputGlobals + kOutputGlobals; +)"; const std::string main_func = R"( %main = OpFunction %void None %3 @@ -373,58 +246,49 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer %22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8 %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0 OpStore %26 %int_531 Aligned 16 -; CHECK-NOT: %22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8 -; CHECK-NOT: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0 -; CHECK: %30 = OpConvertPtrToU %ulong %21 -; CHECK: %67 = OpFunctionCall %bool %inst_buff_addr_search_and_test %30 %uint_8 -; CHECK: OpSelectionMerge %68 None -; CHECK: OpBranchConditional %67 %69 %70 -; CHECK: %69 = OpLabel -; CHECK: %71 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8 -; CHECK: OpBranch %68 -; CHECK: %70 = OpLabel -; CHECK: %72 = OpUConvert %uint %30 -; CHECK: %74 = OpShiftRightLogical %ulong %30 %uint_32 -; CHECK: %75 = OpUConvert %uint %74 -; CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_buff_addr_stream_write_3 %uint_23 %uint_44 {{%\w+}} %uint_3 %72 %75 -; CHECK: {{%\w+}} = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_blockType {{%\w+}} -; CHECK: OpBranch %68 -; CHECK: %68 = OpLabel -; CHECK: {{%\w+}} = OpPhi %_ptr_PhysicalStorageBuffer_blockType %71 %69 {{%\w+}} %70 -; CHECK: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int {{%\w+}} %int_0 -; CHECK: {{%\w+}} = OpConvertPtrToU %ulong %26 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_buff_addr_search_and_test {{%\w+}} %uint_4 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpStore %26 %int_531 Aligned 16 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}} -; CHECK: {{%\w+}} = OpShiftRightLogical %ulong {{%\w+}} %uint_32 -; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_buff_addr_stream_write_3 %uint_23 %uint_46 {{%\w+}} %uint_3 {{%\w+}} {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel +;CHECK-NOT: %22 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8 +;CHECK-NOT: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %22 %int_0 +;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %21 +;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_45 {{%\w+}} {{%\w+}} %uint_8 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %_ptr_PhysicalStorageBuffer_blockType %21 Aligned 8 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_blockType %52 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %_ptr_PhysicalStorageBuffer_blockType {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int {{%\w+}} %int_0 +;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %26 +;CHECK: {{%\w+}} = OpLoad %v3uint %gl_GlobalInvocationID +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_47 {{%\w+}} {{%\w+}} %uint_4 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpStore %26 %int_531 Aligned 16 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - - const std::string output_funcs = kSearchAndTest + kStreamWrite3; + // clang-format on SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch( - defs + decorates + globals + main_func + output_funcs, true, 7u, 23u); + defs + decorates + globals + kImportStub + main_func, true, 23u); } TEST_F(InstBuffAddrTest, StructLoad) { @@ -451,11 +315,11 @@ TEST_F(InstBuffAddrTest, StructLoad) { OpCapability Shader OpCapability Int64 OpCapability PhysicalStorageBufferAddresses -; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" +;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel PhysicalStorageBuffer64 GLSL450 OpEntryPoint Fragment %main "main" -; CHECK: OpEntryPoint Fragment %main "main" %inst_buff_addr_input_buffer %gl_FragCoord %inst_buff_addr_output_buffer +;CHECK: OpEntryPoint Fragment %main "main" %gl_FragCoord OpExecutionMode %main OriginUpperLeft OpSource GLSL 450 OpSourceExtension "GL_ARB_gpu_shader_int64" @@ -474,11 +338,9 @@ OpMemberName %TestBuffer 0 "test" OpMemberDecorate %Test_0 0 Offset 0 OpMemberDecorate %TestBuffer 0 Offset 0 OpDecorate %TestBuffer Block -; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8 -)" + kInputDecorations + R"( -; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations; +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord +)"; const std::string globals = R"( %void = OpTypeVoid @@ -494,53 +356,44 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffe %int_0 = OpConstant %int 0 %_ptr_PhysicalStorageBuffer_Test_0 = OpTypePointer PhysicalStorageBuffer %Test_0 %ulong_18446744073172680704 = OpConstant %ulong 18446744073172680704 -; CHECK: %47 = OpTypeFunction %bool %ulong %uint -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: {{%\w+}} = OpConstantNull %Test_0 +;CHECK: {{%\w+}} = OpConstantNull %Test_0 )"; - // clang-format on - const std::string main_func = - R"( + const std::string main_func = R"( %main = OpFunction %void None %3 %5 = OpLabel %37 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_TestBuffer %ulong_18446744073172680704 %38 = OpAccessChain %_ptr_PhysicalStorageBuffer_Test_0 %37 %int_0 %39 = OpLoad %Test_0 %38 Aligned 16 -; CHECK-NOT: %39 = OpLoad %Test_0 %38 Aligned 16 -; CHECK: {{%\w+}} = OpConvertPtrToU %ulong %38 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_buff_addr_search_and_test {{%\w+}} %uint_4 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %Test_0 %38 Aligned 16 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}} -; CHECK: {{%\w+}} = OpShiftRightLogical %ulong {{%\w+}} %uint_32 -; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_buff_addr_stream_write_3 %uint_23 %uint_37 {{%\w+}} %uint_3 {{%\w+}} {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %Test_0 {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK-NOT: %39 = OpLoad %Test_0 %38 Aligned 16 +;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %38 +;CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord +;CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_38 {{%\w+}} {{%\w+}} %uint_4 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %Test_0 %38 Aligned 16 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result:%\w+]] = OpPhi %Test_0 {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} %40 = OpCopyLogical %Test %39 -; CHECK-NOT: %40 = OpCopyLogical %Test %39 -; CHECK: %40 = OpCopyLogical %Test [[phi_result]] +;CHECK-NOT: %40 = OpCopyLogical %Test %39 +;CHECK: %40 = OpCopyLogical %Test [[phi_result]] OpReturn OpFunctionEnd )"; + // clang-format on - const std::string output_funcs = kSearchAndTest + kStreamWrite3; - - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch( - defs + decorates + globals + main_func + output_funcs, true); + defs + decorates + globals + kImportStub + main_func, true); } TEST_F(InstBuffAddrTest, PaddedStructLoad) { @@ -599,12 +452,9 @@ OpMemberDecorate %Test_0 0 Offset 0 OpMemberDecorate %Test_0 1 Offset 16 OpMemberDecorate %Test_0 2 Offset 24 OpMemberDecorate %TestBuffer 0 Offset 0 -; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8 -)" + kInputDecorations + R"( -; CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex -; CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( +)" + kImportDeco + R"( +;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex +;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex )"; const std::string globals = R"( @@ -627,13 +477,10 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffe %_ptr_PhysicalStorageBuffer_Test_0 = OpTypePointer PhysicalStorageBuffer %Test_0 %_ptr_Function_Test = OpTypePointer Function %Test %ulong_18446744073172680704 = OpConstant %ulong 18446744073172680704 -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: {{%\w+}} = OpConstantNull %Test_0 +;CHECK: {{%\w+}} = OpConstantNull %Test_0 )"; - // clang-format on - const std::string main_func = - R"( + const std::string main_func = R"( %main = OpFunction %void None %3 %5 = OpLabel %param = OpVariable %_ptr_Function_ulong Function @@ -650,40 +497,35 @@ OpFunctionEnd %25 = OpAccessChain %_ptr_PhysicalStorageBuffer_Test_0 %21 %int_0 %26 = OpLoad %Test_0 %25 Aligned 16 %29 = OpCopyLogical %Test %26 -; CHECK-NOT: %30 = OpLoad %Test %28 -; CHECK-NOT: %26 = OpLoad %Test_0 %25 Aligned 16 -; CHECK-NOT: %29 = OpCopyLogical %Test %26 -; CHECK: {{%\w+}} = OpConvertPtrToU %ulong %25 -; CHECK: {{%\w+}} = OpFunctionCall %bool %inst_buff_addr_search_and_test {{%\w+}} %uint_28 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %Test_0 %25 Aligned 16 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}} -; CHECK: {{%\w+}} = OpShiftRightLogical %ulong {{%\w+}} %uint_32 -; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex -; CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_buff_addr_stream_write_3 %uint_23 %uint_62 {{%\w+}} %uint_3 {{%\w+}} {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %Test_0 {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: %29 = OpCopyLogical %Test [[phi_result]] +;CHECK-NOT: %30 = OpLoad %Test %28 +;CHECK-NOT: %26 = OpLoad %Test_0 %25 Aligned 16 +;CHECK-NOT: %29 = OpCopyLogical %Test %26 +;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %25 +;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex +;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_63 {{%\w+}} {{%\w+}} %uint_28 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %Test_0 %25 Aligned 16 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result:%\w+]] = OpPhi %Test_0 {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: %29 = OpCopyLogical %Test [[phi_result]] OpStore %28 %29 %30 = OpLoad %Test %28 OpReturnValue %30 OpFunctionEnd )"; + // clang-format on - const std::string output_funcs = kSearchAndTest + kStreamWrite3; - - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch( - defs + decorates + globals + main_func + output_funcs, true); + defs + decorates + globals + kImportStub + main_func, true); } TEST_F(InstBuffAddrTest, DeviceBufferAddressOOB) { @@ -710,7 +552,7 @@ OpCapability PhysicalStorageBufferAddresses %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel PhysicalStorageBuffer64 GLSL450 OpEntryPoint Vertex %main "main" %u_info -;CHECK: OpEntryPoint Vertex %main "main" %u_info %inst_buff_addr_input_buffer %gl_VertexIndex %gl_InstanceIndex %inst_buff_addr_output_buffer +;CHECK: OpEntryPoint Vertex %main "main" %u_info %gl_VertexIndex %gl_InstanceIndex OpSource GLSL 450 OpSourceExtension "GL_EXT_buffer_reference" OpName %main "main" @@ -729,7 +571,7 @@ OpMemberDecorate %bufStruct 0 Offset 0 OpDecorate %bufStruct Block OpDecorate %u_info DescriptorSet 0 OpDecorate %u_info Binding 0 -)" + kInputDecorations + kOutputDecorations + R"( +)" + kImportDeco + R"( %void = OpTypeVoid %3 = OpTypeFunction %void %int = OpTypeInt 32 1 @@ -750,7 +592,7 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct %int_n559035791 = OpConstant %int -559035791 %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int -)" + kInputGlobals + kOutputGlobals + R"( +)" + kImportStub + R"( %main = OpFunction %void None %3 %5 = OpLabel %i = OpVariable %_ptr_Function_int Function @@ -770,21 +612,18 @@ OpBranchConditional %29 %11 %12 %32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 %33 = OpLoad %int %i %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %32 %int_0 %33 -;CHECK: %41 = OpConvertPtrToU %ulong %36 -;CHECK: %76 = OpFunctionCall %bool %inst_buff_addr_search_and_test %41 %uint_4 -;CHECK: OpSelectionMerge %77 None -;CHECK: OpBranchConditional %76 %78 %79 -;CHECK: %78 = OpLabel OpStore %36 %int_n559035791 Aligned 16 -;CHECK: OpBranch %77 -;CHECK: %79 = OpLabel -;CHECK: %80 = OpUConvert %uint %41 -;CHECK: %82 = OpShiftRightLogical %ulong %41 %uint_32 -;CHECK: %83 = OpUConvert %uint %82 +;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %36 ;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex ;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex ;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_buff_addr_stream_write_3 %uint_23 %uint_62 {{%\w+}} %uint_3 {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_63 {{%\w+}} {{%\w+}} %uint_4 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpStore %36 %int_n559035791 Aligned 16 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel OpBranch %13 @@ -795,12 +634,12 @@ OpStore %i %38 OpBranch %10 %12 = OpLabel OpReturn -OpFunctionEnd)" + kSearchAndTest + kStreamWrite3; +OpFunctionEnd)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7, 23); + SinglePassRunAndMatch(text, true, 23); } TEST_F(InstBuffAddrTest, UVec3ScalarAddressOOB) { @@ -849,7 +688,7 @@ OpMemberDecorate %IndexBuffer 0 Offset 0 OpDecorate %IndexBuffer Block OpDecorate %u_info DescriptorSet 0 OpDecorate %u_info Binding 0 -)" + kInputDecorations + kOutputDecorations + R"( +)" + kImportDeco + R"( %void = OpTypeVoid %3 = OpTypeFunction %void %int = OpTypeInt 32 1 @@ -867,7 +706,7 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_IndexBuffer PhysicalStorageBuff %int_1 = OpConstant %int 1 %_ptr_Uniform_int = OpTypePointer Uniform %int %bool = OpTypeBool -)" + kInputGlobals + kOutputGlobals + R"( +)" + kImportStub + R"( %_ptr_Function_v3uint = OpTypePointer Function %v3uint %_ptr_Uniform__ptr_PhysicalStorageBuffer_IndexBuffer = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_IndexBuffer %_ptr_PhysicalStorageBuffer_v3uint = OpTypePointer PhysicalStorageBuffer %v3uint @@ -893,27 +732,23 @@ OpBranchConditional %29 %11 %12 %37 = OpAccessChain %_ptr_PhysicalStorageBuffer_v3uint %34 %int_0 %35 %38 = OpLoad %v3uint %37 Aligned 4 OpStore %readvec %38 -; CHECK-NOT: %38 = OpLoad %v3uint %37 Aligned 4 -; CHECK-NOT: OpStore %readvec %38 -; CHECK: {{%\w+}} = OpConvertPtrToU %ulong %37 -; CHECK: [[test_result:%\w+]] = OpFunctionCall %bool %inst_buff_addr_search_and_test {{%\w+}} %uint_12 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional [[test_result]] {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %v3uint %37 Aligned 4 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}} -; CHECK: {{%\w+}} = OpShiftRightLogical %ulong {{%\w+}} %uint_32 -; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex -; CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_buff_addr_stream_write_3 %uint_23 %uint_66 {{%\w+}} %uint_3 {{%\w+}} {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %v3uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: OpStore %readvec [[phi_result]] +;CHECK-NOT: %38 = OpLoad %v3uint %37 Aligned 4 +;CHECK-NOT: OpStore %readvec %38 +;CHECK: {{%\w+}} = OpConvertPtrToU %ulong %37 +;CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex +;CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex +;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_0 {{%\w+}} {{%\w+}} %uint_0 +;CHECK: [[test_result:%\w+]] = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_67 {{%\w+}} {{%\w+}} %uint_12 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional [[test_result]] {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %v3uint %37 Aligned 4 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result:%\w+]] = OpPhi %v3uint {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: OpStore %readvec [[phi_result]] OpBranch %13 %13 = OpLabel %39 = OpLoad %int %i @@ -923,13 +758,13 @@ OpBranch %10 %12 = OpLabel OpReturn OpFunctionEnd -)" + kSearchAndTest + kStreamWrite3; +)"; // clang-format on - SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); ValidatorOptions()->scalar_block_layout = true; - SinglePassRunAndMatch(text, true, 7, 23); + SinglePassRunAndMatch(text, true, 23); } } // namespace diff --git a/test/opt/inst_debug_printf_test.cpp b/test/opt/inst_debug_printf_test.cpp index e9774debf6..24c0bc6551 100644 --- a/test/opt/inst_debug_printf_test.cpp +++ b/test/opt/inst_debug_printf_test.cpp @@ -74,7 +74,7 @@ OpExtension "SPV_KHR_non_semantic_info" ; CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %2 "MainPs" %3 %4 -; CHECK: OpEntryPoint Fragment %2 "MainPs" %3 %4 %gl_FragCoord +; CHECK: OpEntryPoint Fragment %2 "MainPs" %3 %4 OpExecutionMode %2 OriginUpperLeft %5 = OpString "Color is %vn" )"; @@ -87,8 +87,6 @@ OpDecorate %7 DescriptorSet 0 OpDecorate %7 Binding 0 OpDecorate %3 Location 0 OpDecorate %4 Location 0 -; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kOutputDecorations; const std::string globals = @@ -109,10 +107,7 @@ OpDecorate %4 Location 0 %_ptr_Output_v4float = OpTypePointer Output %v4float %4 = OpVariable %_ptr_Output_v4float Output ; CHECK: %uint = OpTypeInt 32 0 -; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -; CHECK: %v4uint = OpTypeVector %uint 4 -; CHECK: [[func_type:%\w+]] = OpTypeFunction %void %uint %uint %v4uint %uint %uint %uint %uint %uint +; CHECK: [[func_type:%\w+]] = OpTypeFunction %void %uint %uint %uint %uint %uint %uint %uint ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint )" + kOutputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint @@ -138,12 +133,7 @@ OpDecorate %4 Location 0 ; CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}} ; CHECK: {{%\w+}} = OpCompositeExtract %float %25 3 ; CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_4 {{%\w+}} {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_printf_stream_write_5 %uint_23 %uint_36 {{%\w+}} %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_printf_stream_write_5 %uint_23 %uint_36 %uint_5 {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel OpStore %4 %25 @@ -155,7 +145,6 @@ OpFunctionEnd ; CHECK: %inst_printf_stream_write_5 = OpFunction %void None {{%\w+}} ; CHECK: [[sw_shader_id:%\w+]] = OpFunctionParameter %uint ; CHECK: [[sw_inst_idx:%\w+]] = OpFunctionParameter %uint -; CHECK: [[sw_stage_info:%\w+]] = OpFunctionParameter %v4uint ; CHECK: [[sw_param_1:%\w+]] = OpFunctionParameter %uint ; CHECK: [[sw_param_2:%\w+]] = OpFunctionParameter %uint ; CHECK: [[sw_param_3:%\w+]] = OpFunctionParameter %uint @@ -163,8 +152,8 @@ OpFunctionEnd ; CHECK: [[sw_param_5:%\w+]] = OpFunctionParameter %uint ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_1 -; CHECK: {{%\w+}} = OpAtomicIAdd %uint {{%\w+}} %uint_4 %uint_0 %uint_12 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_12 +; CHECK: {{%\w+}} = OpAtomicIAdd %uint {{%\w+}} %uint_4 %uint_0 %uint_8 +; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8 ; CHECK: {{%\w+}} = OpArrayLength %uint [[output_buffer_var]] 2 ; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None @@ -172,42 +161,26 @@ OpFunctionEnd ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_0 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} %uint_12 +; CHECK: OpStore {{%\w+}} %uint_8 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} [[sw_shader_id]] ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_2 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} [[sw_inst_idx]] -; CHECK: {{%\w+}} = OpCompositeExtract %uint [[sw_stage_info]] 0 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint [[sw_stage_info]] 1 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint [[sw_stage_info]] 2 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint [[sw_stage_info]] 3 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} [[sw_param_1]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8 +; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} [[sw_param_2]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_9 +; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} [[sw_param_3]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10 +; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} [[sw_param_4]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_11 +; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} [[sw_param_5]] ; CHECK: OpBranch {{%\w+}} diff --git a/test/opt/invocation_interlock_placement_test.cpp b/test/opt/invocation_interlock_placement_test.cpp new file mode 100644 index 0000000000..2c4ff65ebb --- /dev/null +++ b/test/opt/invocation_interlock_placement_test.cpp @@ -0,0 +1,613 @@ +// Copyright (c) 2023 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. + +#include "spirv-tools/optimizer.hpp" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using InterlockInvocationPlacementTest = PassTest<::testing::Test>; + +TEST_F(InterlockInvocationPlacementTest, CheckUnchangedIfNotFragment) { + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderSampleInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpExecutionMode %main SampleInterlockOrderedEXT + OpName %main "main" + %void = OpTypeVoid + %1 = OpTypeFunction %void + %main = OpFunction %void None %1 + %2 = OpLabel + OpBeginInvocationInterlockEXT + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_3); + EXPECT_EQ( + Pass::Status::SuccessWithoutChange, + std::get<1>(SinglePassRunAndDisassemble( + kTest, /* skip_nop= */ false, /* do_validation= */ false))); +} + +TEST_F(InterlockInvocationPlacementTest, CheckUnchangedWithoutCapability) { + const std::string kTest = R"( + OpCapability Shader + OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main SampleInterlockOrderedEXT + OpName %main "main" + %void = OpTypeVoid + %1 = OpTypeFunction %void + %main = OpFunction %void None %1 + %2 = OpLabel + OpBeginInvocationInterlockEXT + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_3); + EXPECT_EQ( + Pass::Status::SuccessWithoutChange, + std::get<1>(SinglePassRunAndDisassemble( + kTest, /* skip_nop= */ false, /* do_validation= */ false))); +} + +TEST_F(InterlockInvocationPlacementTest, CheckSingleBasicBlock) { + // We're using OpNoLine as a generic standin for any other instruction, to + // test that begin and end aren't moved. + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderSampleInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main SampleInterlockOrderedEXT + OpName %main "main" + %void = OpTypeVoid + %1 = OpTypeFunction %void + %main = OpFunction %void None %1 +; CHECK: OpLabel + %2 = OpLabel +; CHECK-NEXT: OpNoLine + OpNoLine +; CHECK-NEXT: OpBeginInvocationInterlockEXT + OpBeginInvocationInterlockEXT + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpBeginInvocationInterlockEXT +; CHECK-NEXT: OpNoLine + OpNoLine +; CHECK-NEXT: OpEndInvocationInterlockEXT + OpEndInvocationInterlockEXT +; CHECK-NEXT: OpNoLine + OpNoLine +; CHECK-NEXT: OpReturn + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_3); + const auto result = SinglePassRunAndMatch( + kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(InterlockInvocationPlacementTest, CheckFunctionCallExtractionBegin) { + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderSampleInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main SampleInterlockOrderedEXT + OpName %main "main" + %void = OpTypeVoid + %1 = OpTypeFunction %void + %foo = OpFunction %void None %1 +; CHECK: OpLabel +; CHECK-NOT: OpBeginInvocationInterlockEXT + %2 = OpLabel + OpBeginInvocationInterlockEXT + OpBeginInvocationInterlockEXT + OpReturn +; CHECK: OpFunctionEnd + OpFunctionEnd + %main = OpFunction %void None %1 +; CHECK: OpLabel + %3 = OpLabel +; CHECK-NEXT: OpBeginInvocationInterlockEXT +; CHECK-NEXT: OpFunctionCall + %4 = OpFunctionCall %void %foo +; CHECK-NEXT: OpReturn + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_3); + const auto result = SinglePassRunAndMatch( + kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(InterlockInvocationPlacementTest, CheckFunctionCallExtractionEnd) { + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderSampleInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main SampleInterlockOrderedEXT + OpName %main "main" + %void = OpTypeVoid + %1 = OpTypeFunction %void + %foo = OpFunction %void None %1 +; CHECK: OpLabel +; CHECK-NOT: OpEndInvocationInterlockEXT + %2 = OpLabel + OpEndInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpReturn +; CHECK: OpFunctionEnd + OpFunctionEnd + %main = OpFunction %void None %1 +; CHECK: OpLabel + %3 = OpLabel +; CHECK-NEXT: OpFunctionCall + %4 = OpFunctionCall %void %foo +; CHECK-NEXT: OpEndInvocationInterlockEXT +; CHECK-NEXT: OpReturn + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_3); + const auto result = SinglePassRunAndMatch( + kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(InterlockInvocationPlacementTest, + CheckFunctionCallExtractionRepeatedCall) { + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderSampleInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main SampleInterlockOrderedEXT + OpName %main "main" + %void = OpTypeVoid + %1 = OpTypeFunction %void + %foo = OpFunction %void None %1 +; CHECK: OpLabel +; CHECK-NOT: OpBeginInvocationInterlockEXT +; CHECK-NOT: OpEndInvocationInterlockEXT + %2 = OpLabel + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpReturn +; CHECK: OpFunctionEnd + OpFunctionEnd + %main = OpFunction %void None %1 +; CHECK: OpLabel + %3 = OpLabel +; CHECK-NEXT: OpBeginInvocationInterlockEXT +; CHECK-NEXT: OpFunctionCall + %4 = OpFunctionCall %void %foo +; CHECK-NEXT: OpFunctionCall + %5 = OpFunctionCall %void %foo +; CHECK-NEXT: OpEndInvocationInterlockEXT +; CHECK-NEXT: OpReturn + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_3); + const auto result = SinglePassRunAndMatch( + kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(InterlockInvocationPlacementTest, + CheckFunctionCallExtractionNestedCall) { + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderSampleInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main SampleInterlockOrderedEXT + OpName %main "main" + %void = OpTypeVoid + %1 = OpTypeFunction %void + %foo = OpFunction %void None %1 +; CHECK: OpLabel +; CHECK-NOT: OpBeginInvocationInterlockEXT +; CHECK-NOT: OpEndInvocationInterlockEXT + %2 = OpLabel + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpReturn +; CHECK: OpFunctionEnd + OpFunctionEnd + %bar = OpFunction %void None %1 +; CHECK: OpLabel +; CHECK-NOT: OpBeginInvocationInterlockEXT +; CHECK-NOT: OpEndInvocationInterlockEXT + %3 = OpLabel + %4 = OpFunctionCall %void %foo + OpReturn +; CHECK: OpFunctionEnd + OpFunctionEnd + %main = OpFunction %void None %1 +; CHECK: OpLabel + %5 = OpLabel +; CHECK-NEXT: OpBeginInvocationInterlockEXT +; CHECK-NEXT: OpFunctionCall + %6 = OpFunctionCall %void %bar +; CHECK-NEXT: OpEndInvocationInterlockEXT +; CHECK-NEXT: OpReturn + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_3); + const auto result = SinglePassRunAndMatch( + kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(InterlockInvocationPlacementTest, CheckLoopExtraction) { + // Tests that any begin or end instructions in a loop are moved outside of the + // loop. + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderSampleInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main SampleInterlockOrderedEXT + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %1 = OpTypeFunction %void + %main = OpFunction %void None %1 + + %2 = OpLabel +; CHECK: OpBeginInvocationInterlockEXT +; CHECK-NOT: OpBeginInvocationInterlockEXT +; CHECK-NOT: OpEndInvocationInterlockEXT + OpBranch %3 + + %3 = OpLabel + OpLoopMerge %3 %4 None +; CHECK: OpBranchConditional +; CHECK-NOT: OpBeginInvocationInterlockEXT +; CHECK-NOT: OpEndInvocationInterlockEXT + OpBranchConditional %true %4 %5 + + %4 = OpLabel + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT +; CHECK: OpBranch + OpBranch %3 + +; CHECK-NEXT: OpLabel + %5 = OpLabel +; CHECK-NEXT: OpEndInvocationInterlockEXT +; CHECK-NOT: OpEndInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_3); + const auto result = SinglePassRunAndMatch( + kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(InterlockInvocationPlacementTest, CheckAddBeginToElse) { + // Test that if there is a begin in a single branch of a conditional, begin + // will be added to the other branch. + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderSampleInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main SampleInterlockOrderedEXT + OpName %main "main" + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %1 = OpTypeFunction %void + %main = OpFunction %void None %1 + + %2 = OpLabel +; CHECK-NOT: OpBeginInvocationInterlockEXT + OpSelectionMerge %5 None +; CHECK: OpBranchConditional + OpBranchConditional %true %3 %4 + +; CHECK-NEXT: OpLabel + %3 = OpLabel +; CHECK-NEXT: OpBeginInvocationInterlockEXT + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT +; CHECK-NEXT: OpBranch + OpBranch %5 + + %4 = OpLabel +; CHECK: OpBeginInvocationInterlockEXT +; CHECK-NEXT: OpBranch + OpBranch %5 + +; CHECK-NEXT: OpLabel + %5 = OpLabel + OpBeginInvocationInterlockEXT +; CHECK-NEXT: OpEndInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_3); + const auto result = SinglePassRunAndMatch( + kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(InterlockInvocationPlacementTest, CheckAddEndToElse) { + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderSampleInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main SampleInterlockOrderedEXT + OpName %main "main" + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %1 = OpTypeFunction %void + %main = OpFunction %void None %1 + + %2 = OpLabel +; CHECK: OpBeginInvocationInterlockEXT + OpBeginInvocationInterlockEXT +; CHECK-NOT: OpEndInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpSelectionMerge %5 None +; CHECK: OpBranchConditional + OpBranchConditional %true %3 %4 + +; CHECK-NEXT: OpLabel + %3 = OpLabel + OpBeginInvocationInterlockEXT +; CHECK-NEXT: OpEndInvocationInterlockEXT + OpEndInvocationInterlockEXT +; CHECK-NEXT: OpBranch + OpBranch %5 + + %4 = OpLabel +; CHECK: OpEndInvocationInterlockEXT +; CHECK-NEXT: OpBranch + OpBranch %5 + +; CHECK-NEXT: OpLabel + %5 = OpLabel +; CHECK-NOT: OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_3); + const auto result = SinglePassRunAndMatch( + kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(InterlockInvocationPlacementTest, CheckSplitIfWithoutElseBegin) { + // Test that if there is a begin in the then branch of a conditional, and no + // else branch, an else branch with a begin will created. + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderSampleInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main SampleInterlockOrderedEXT + OpName %main "main" + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %1 = OpTypeFunction %void + %main = OpFunction %void None %1 + + %2 = OpLabel +; CHECK-NOT: OpBeginInvocationInterlockEXT + OpSelectionMerge %5 None +; CHECK: OpBranchConditional + OpBranchConditional %true %3 %5 + +; CHECK-NEXT: OpLabel +; CHECK-NEXT: OpBeginInvocationInterlockEXT +; CHECK-NEXT: OpBranch + +; CHECK-NEXT: OpLabel + %3 = OpLabel +; CHECK-NEXT: OpBeginInvocationInterlockEXT +; CHECK-NOT: OpEndInvocationInterlockEXT + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpBranch %5 + +; CHECK: OpLabel + %5 = OpLabel +; CHECK-NOT: OpBeginInvocationInterlockEXT + OpBeginInvocationInterlockEXT +; CHECK-NEXT: OpEndInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_3); + const auto result = SinglePassRunAndMatch( + kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(InterlockInvocationPlacementTest, CheckSplitIfWithoutElseEnd) { + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderSampleInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main SampleInterlockOrderedEXT + OpName %main "main" + %void = OpTypeVoid + %bool = OpTypeBool + %true = OpConstantTrue %bool + %1 = OpTypeFunction %void + %main = OpFunction %void None %1 + + %2 = OpLabel + +; CHECK: OpBeginInvocationInterlockEXT + OpBeginInvocationInterlockEXT +; CHECK-NOT: OpEndInvocationInterlockEXT + OpEndInvocationInterlockEXT +; CHECK-NEXT: OpSelectionMerge [[merge:%\d+]] + OpSelectionMerge %5 None +; CHECK-NEXT: OpBranchConditional %true [[then:%\d+]] [[else:%\d+]] + OpBranchConditional %true %3 %5 + +; CHECK-NEXT: [[else]] = OpLabel +; CHECK-NEXT: OpEndInvocationInterlockEXT +; CHECK-NEXT: OpBranch [[merge]] + +; CHECK-NEXT: [[then]] = OpLabel + %3 = OpLabel +; CHECK-NEXT: OpEndInvocationInterlockEXT + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT +; CHECK-NEXT: OpBranch [[merge]] + OpBranch %5 + +; CHECK-NEXT: [[merge]] = OpLabel + %5 = OpLabel +; CHECK-NEXT: OpReturn + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_3); + const auto result = SinglePassRunAndMatch( + kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(InterlockInvocationPlacementTest, CheckSplitSwitch) { + // Test that if there is a begin or end in a single branch of a switch, begin + // or end will be added to all the other branches. + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderSampleInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main SampleInterlockOrderedEXT + OpName %main "main" + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %uint_1 = OpConstant %uint 1 + %1 = OpTypeFunction %void + %main = OpFunction %void None %1 + +; CHECK: OpLabel + %2 = OpLabel +; CHECK-NEXT: OpSelectionMerge [[merge:%\d+]] + OpSelectionMerge %8 None +; CHECK-NEXT: OpSwitch %uint_1 [[default:%\d+]] 0 [[case_0:%\d+]] 1 [[case_1:%\d+]] 2 [[case_2:%\d+]] + OpSwitch %uint_1 %8 0 %4 1 %5 2 %8 + +; CHECK-NEXT: [[case_2]] = OpLabel +; CHECK-NEXT: OpBeginInvocationInterlockEXT +; CHECK-NEXT: OpBranch [[merge]] + +; CHECK-NEXT: [[default]] = OpLabel +; CHECK-NEXT: OpBeginInvocationInterlockEXT +; CHECK-NEXT: OpBranch [[merge]] + +; CHECK-NEXT: [[case_0]] = OpLabel + %4 = OpLabel +; CHECK-NEXT: OpBeginInvocationInterlockEXT +; CHECK-NOT: OpEndInvocationInterlockEXT + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT +; CHECK-NEXT: OpNoLine + OpNoLine +; CHECK-NEXT: OpBranch [[merge]] + OpBranch %8 + +; CHECK-NEXT: [[case_1]] = OpLabel + %5 = OpLabel +; CHECK-NEXT: OpBeginInvocationInterlockEXT +; CHECK-NOT: OpEndInvocationInterlockEXT + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT +; CHECK-NEXT: OpNoLine + OpNoLine +; CHECK-NEXT: OpNoLine + OpNoLine +; CHECK-NEXT: OpBranch [[merge]] + OpBranch %8 + +; CHECK-NEXT: [[merge]] = OpLabel + %8 = OpLabel +; CHECK-NOT: OpBeginInvocationInterlockEXT + OpBeginInvocationInterlockEXT +; CHECK-NEXT: OpEndInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_3); + const auto result = SinglePassRunAndMatch( + kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/test/opt/switch_descriptorset_test.cpp b/test/opt/switch_descriptorset_test.cpp new file mode 100644 index 0000000000..f26178f829 --- /dev/null +++ b/test/opt/switch_descriptorset_test.cpp @@ -0,0 +1,193 @@ +// Copyright (c) 2023 LunarG 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. + +// Bindless Check Instrumentation Tests. +// Tests ending with V2 use version 2 record format. + +#include +#include + +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using SwitchDescriptorSetTest = PassTest<::testing::Test>; + +TEST_F(SwitchDescriptorSetTest, Basic) { + // #version 450 + // #extension GL_EXT_buffer_reference : enable + // + // layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct; + // + // layout(set = 7, binding = 7) uniform ufoo { + // bufStruct data; + // uint offset; + // } u_info; + // + // layout(buffer_reference, std140) buffer bufStruct { + // layout(offset = 0) int a[2]; + // layout(offset = 32) int b; + // }; + // + // void main() { + // u_info.data.b = 0xca7; + // } + + const std::string spirv = R"( +OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +OpExtension "SPV_EXT_physical_storage_buffer" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpSource GLSL 450 +OpSourceExtension "GL_EXT_buffer_reference" +OpName %main "main" +OpName %ufoo "ufoo" +OpMemberName %ufoo 0 "data" +OpMemberName %ufoo 1 "offset" +OpName %bufStruct "bufStruct" +OpMemberName %bufStruct 0 "a" +OpMemberName %bufStruct 1 "b" +OpName %u_info "u_info" +OpMemberDecorate %ufoo 0 Offset 0 +OpMemberDecorate %ufoo 1 Offset 8 +OpDecorate %ufoo Block +OpDecorate %_arr_int_uint_2 ArrayStride 16 +OpMemberDecorate %bufStruct 0 Offset 0 +OpMemberDecorate %bufStruct 1 Offset 32 +OpDecorate %bufStruct Block +OpDecorate %u_info DescriptorSet 7 +;CHECK: OpDecorate %u_info DescriptorSet 31 +OpDecorate %u_info Binding 7 +;CHECK: OpDecorate %u_info Binding 7 +%void = OpTypeVoid +%3 = OpTypeFunction %void +OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer +%uint = OpTypeInt 32 0 +%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %uint +%int = OpTypeInt 32 1 +%uint_2 = OpConstant %uint 2 +%_arr_int_uint_2 = OpTypeArray %int %uint_2 +%bufStruct = OpTypeStruct %_arr_int_uint_2 %int +%_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct +%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo +%u_info = OpVariable %_ptr_Uniform_ufoo Uniform +%int_0 = OpConstant %int 0 +%_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct +%int_1 = OpConstant %int 1 +%int_3239 = OpConstant %int 3239 +%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int +%main = OpFunction %void None %3 +%5 = OpLabel +%17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 +%18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17 +%22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1 +OpReturn +OpFunctionEnd +)"; + // clang-format off + + SinglePassRunAndMatch(spirv, true, 7, 31); +} + + +// Make sure DescriptorSet decorations that don't match the requested number +// are left unchanged. +TEST_F(SwitchDescriptorSetTest, Unchanged) { + // #version 450 + // #extension GL_EXT_buffer_reference : enable + // + // layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct; + // + // layout(set = 11, binding = 7) uniform ufoo { + // bufStruct data; + // uint offset; + // } u_info; + // + // layout(buffer_reference, std140) buffer bufStruct { + // layout(offset = 0) int a[2]; + // layout(offset = 32) int b; + // }; + // + // void main() { + // u_info.data.b = 0xca7; + // } + + const std::string spirv = R"( +OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +OpExtension "SPV_EXT_physical_storage_buffer" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpSource GLSL 450 +OpSourceExtension "GL_EXT_buffer_reference" +OpName %main "main" +OpName %ufoo "ufoo" +OpMemberName %ufoo 0 "data" +OpMemberName %ufoo 1 "offset" +OpName %bufStruct "bufStruct" +OpMemberName %bufStruct 0 "a" +OpMemberName %bufStruct 1 "b" +OpName %u_info "u_info" +OpMemberDecorate %ufoo 0 Offset 0 +OpMemberDecorate %ufoo 1 Offset 8 +OpDecorate %ufoo Block +OpDecorate %_arr_int_uint_2 ArrayStride 16 +OpMemberDecorate %bufStruct 0 Offset 0 +OpMemberDecorate %bufStruct 1 Offset 32 +OpDecorate %bufStruct Block +OpDecorate %u_info DescriptorSet 11 +;CHECK: OpDecorate %u_info DescriptorSet 11 +OpDecorate %u_info Binding 7 +;CHECK: OpDecorate %u_info Binding 7 +%void = OpTypeVoid +%3 = OpTypeFunction %void +OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer +%uint = OpTypeInt 32 0 +%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %uint +%int = OpTypeInt 32 1 +%uint_2 = OpConstant %uint 2 +%_arr_int_uint_2 = OpTypeArray %int %uint_2 +%bufStruct = OpTypeStruct %_arr_int_uint_2 %int +%_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct +%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo +%u_info = OpVariable %_ptr_Uniform_ufoo Uniform +%int_0 = OpConstant %int 0 +%_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct +%int_1 = OpConstant %int 1 +%int_3239 = OpConstant %int 3239 +%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int +%main = OpFunction %void None %3 +%5 = OpLabel +%17 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 +%18 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %17 +%22 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %18 %int_1 +OpReturn +OpFunctionEnd +)"; + // clang-format off + + SinglePassRunAndMatch(spirv, true, 7, 31); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index 83a8943645..14a8aa3a56 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -63,6 +63,8 @@ TEST_F(TrimCapabilitiesPassTest, CheckKnownAliasTransformations) { OpCapability DotProductInput4x8BitKHR OpCapability DotProductInput4x8BitPackedKHR OpCapability DotProductKHR + OpCapability ComputeDerivativeGroupQuadsNV + OpCapability ComputeDerivativeGroupLinearNV ; CHECK: OpCapability Linkage ; CHECK-NOT: OpCapability StorageUniform16 ; CHECK-NOT: OpCapability StorageUniformBufferBlock16 @@ -89,6 +91,8 @@ TEST_F(TrimCapabilitiesPassTest, CheckKnownAliasTransformations) { ; CHECK-NOT: OpCapability DotProductInput4x8BitKHR ; CHECK-NOT: OpCapability DotProductInput4x8BitPackedKHR ; CHECK-NOT: OpCapability DotProductKHR +; CHECK-NOT: OpCapability ComputeDerivativeGroupQuadsNV +; CHECK-NOT: OpCapability ComputeDerivativeGroupLinearNV ; CHECK: OpCapability UniformAndStorageBuffer16BitAccess ; CHECK: OpCapability StorageBuffer16BitAccess ; CHECK: OpCapability ShaderViewportIndexLayerEXT @@ -404,7 +408,7 @@ TEST_F(TrimCapabilitiesPassTest, AMDShaderBallotExtensionRemoved) { EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); } -TEST_F(TrimCapabilitiesPassTest, MinLodCapabilityRemoved) { +TEST_F(TrimCapabilitiesPassTest, MinLod_RemovedIfNotUsed) { const std::string kTest = R"( OpCapability Shader OpCapability Sampled1D @@ -439,7 +443,7 @@ TEST_F(TrimCapabilitiesPassTest, MinLodCapabilityRemoved) { EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); } -TEST_F(TrimCapabilitiesPassTest, MinLodCapabilityRemains) { +TEST_F(TrimCapabilitiesPassTest, MinLod_RemainsWithOpImageSampleImplicitLod) { const std::string kTest = R"( OpCapability Shader OpCapability Sampled1D @@ -474,42 +478,159 @@ TEST_F(TrimCapabilitiesPassTest, MinLodCapabilityRemains) { EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); } -TEST_F(TrimCapabilitiesPassTest, StorageInputOutput16RemainsWithInputVariable) { +TEST_F(TrimCapabilitiesPassTest, + MinLod_RemainsWithOpImageSparseSampleImplicitLod) { + const std::string kTest = R"( + OpCapability Shader + OpCapability SparseResidency + OpCapability ImageGatherExtended + OpCapability MinLod +; CHECK: OpCapability MinLod + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %float = OpTypeFloat 32 + %v2float = OpTypeVector %float 2 + %v3float = OpTypeVector %float 3 + %v4float = OpTypeVector %float 4 + %type_image = OpTypeImage %float 2D 2 0 0 1 Unknown + %ptr_type_image = OpTypePointer UniformConstant %type_image + %type_sampler = OpTypeSampler + %ptr_type_sampler = OpTypePointer UniformConstant %type_sampler +%type_sampled_image = OpTypeSampledImage %type_image + %sparse_struct = OpTypeStruct %uint %v4float + %float_0 = OpConstant %float 0 + %float_00 = OpConstantComposite %v2float %float_0 %float_0 + %float_000 = OpConstantComposite %v3float %float_0 %float_0 %float_0 + %image = OpVariable %ptr_type_image UniformConstant + %sampler = OpVariable %ptr_type_sampler UniformConstant + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + %21 = OpLoad %type_image %image + %22 = OpLoad %type_sampler %sampler + %24 = OpSampledImage %type_sampled_image %21 %22 + %25 = OpImageSparseSampleImplicitLod %sparse_struct %24 %float_00 MinLod %float_0 + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, MinLod_DetectsMinLodWithBitmaskImageOperand) { + const std::string kTest = R"( + OpCapability MinLod +; CHECK: OpCapability MinLod + OpCapability Shader + OpCapability SparseResidency + OpCapability ImageGatherExtended + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + %type_sampler = OpTypeSampler + %int = OpTypeInt 32 1 + %float = OpTypeFloat 32 + %v2int = OpTypeVector %int 2 + %v2float = OpTypeVector %float 2 + %v4float = OpTypeVector %float 4 + %ptr_sampler = OpTypePointer UniformConstant %type_sampler + %type_image = OpTypeImage %float 2D 2 0 0 1 Unknown + %ptr_image = OpTypePointer UniformConstant %type_image + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %type_sampled_image = OpTypeSampledImage %type_image + %type_struct = OpTypeStruct %uint %v4float + + %int_1 = OpConstant %int 1 + %float_0 = OpConstant %float 0 + %float_1 = OpConstant %float 1 + %8 = OpConstantComposite %v2float %float_0 %float_0 + %12 = OpConstantComposite %v2int %int_1 %int_1 + + %2 = OpVariable %ptr_sampler UniformConstant + %3 = OpVariable %ptr_image UniformConstant + %27 = OpTypeFunction %void + %1 = OpFunction %void None %27 + %28 = OpLabel + %29 = OpLoad %type_image %3 + %30 = OpLoad %type_sampler %2 + %31 = OpSampledImage %type_sampled_image %29 %30 + %32 = OpImageSparseSampleImplicitLod %type_struct %31 %8 ConstOffset|MinLod %12 %float_0 + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16_RemainsWithInputPointer_Vulkan1_0) { const std::string kTest = R"( OpCapability Shader OpCapability Float16 OpCapability StorageInputOutput16 -; CHECK: OpCapability StorageInputOutput16 OpExtension "SPV_KHR_16bit_storage" +; CHECK: OpCapability StorageInputOutput16 +; CHECK: OpExtension "SPV_KHR_16bit_storage" OpMemoryModel Logical GLSL450 - OpEntryPoint GLCompute %2 "main" %input_var - OpDecorate %input_var BuiltIn LocalInvocationIndex + OpEntryPoint GLCompute %2 "main" %void = OpTypeVoid %half = OpTypeFloat 16 %ptr = OpTypePointer Input %half %1 = OpTypeFunction %void - %input_var = OpVariable %ptr Input %2 = OpFunction %void None %1 %3 = OpLabel OpReturn OpFunctionEnd )"; + SetTargetEnv(SPV_ENV_VULKAN_1_0); const auto result = SinglePassRunAndMatch(kTest, /* skip_nop= */ false); EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); } TEST_F(TrimCapabilitiesPassTest, - StorageInputOutput16RemainsWithInputVariableArray) { + StorageInputOutput16_RemainsWithInputPointer_Vulkan1_1) { const std::string kTest = R"( OpCapability Shader OpCapability Float16 OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" ; CHECK: OpCapability StorageInputOutput16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + %void = OpTypeVoid + %half = OpTypeFloat 16 + %ptr = OpTypePointer Input %half + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_1); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16_RemainsWithInputPointerArray_Vulkan1_0) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 OpExtension "SPV_KHR_16bit_storage" +; CHECK: OpCapability StorageInputOutput16 +; CHECK: OpExtension "SPV_KHR_16bit_storage" OpMemoryModel Logical GLSL450 - OpEntryPoint GLCompute %2 "main" %input_var - OpDecorate %input_var BuiltIn LocalInvocationIndex + OpEntryPoint GLCompute %2 "main" %void = OpTypeVoid %half = OpTypeFloat 16 %uint = OpTypeInt 32 0 @@ -517,55 +638,111 @@ TEST_F(TrimCapabilitiesPassTest, %array = OpTypeArray %half %uint_1 %ptr = OpTypePointer Input %array %1 = OpTypeFunction %void - %input_var = OpVariable %ptr Input %2 = OpFunction %void None %1 %3 = OpLabel OpReturn OpFunctionEnd )"; + SetTargetEnv(SPV_ENV_VULKAN_1_0); const auto result = SinglePassRunAndMatch(kTest, /* skip_nop= */ false); EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); } TEST_F(TrimCapabilitiesPassTest, - StorageInputOutput16RemainsWithInputVariableStruct) { + StorageInputOutput16_RemainsWithInputPointerArray_Vulkan1_1) { const std::string kTest = R"( OpCapability Shader OpCapability Float16 OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" ; CHECK: OpCapability StorageInputOutput16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + %void = OpTypeVoid + %half = OpTypeFloat 16 + %uint = OpTypeInt 32 0 + %uint_1 = OpConstant %uint 1 + %array = OpTypeArray %half %uint_1 + %ptr = OpTypePointer Input %array + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_1); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16_RemainsWithInputPointerStruct_Vulkan1_0) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 OpExtension "SPV_KHR_16bit_storage" +; CHECK: OpCapability StorageInputOutput16 +; CHECK: OpExtension "SPV_KHR_16bit_storage" OpMemoryModel Logical GLSL450 - OpEntryPoint GLCompute %2 "main" %input_var - OpDecorate %input_var BuiltIn LocalInvocationIndex + OpEntryPoint GLCompute %2 "main" %void = OpTypeVoid %half = OpTypeFloat 16 %struct = OpTypeStruct %half %ptr = OpTypePointer Input %struct %1 = OpTypeFunction %void - %input_var = OpVariable %ptr Input %2 = OpFunction %void None %1 %3 = OpLabel OpReturn OpFunctionEnd )"; + SetTargetEnv(SPV_ENV_VULKAN_1_0); const auto result = SinglePassRunAndMatch(kTest, /* skip_nop= */ false); EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); } TEST_F(TrimCapabilitiesPassTest, - StorageInputOutput16RemainsWithInputVariableStructOfStruct) { + StorageInputOutput16_RemainsWithInputPointerStruct_Vulkan1_1) { const std::string kTest = R"( OpCapability Shader OpCapability Float16 OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" ; CHECK: OpCapability StorageInputOutput16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + %void = OpTypeVoid + %half = OpTypeFloat 16 + %struct = OpTypeStruct %half + %ptr = OpTypePointer Input %struct + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_1); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16_RemainsWithInputPointerStructOfStruct_Vulkan1_0) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 OpExtension "SPV_KHR_16bit_storage" +; CHECK: OpCapability StorageInputOutput16 +; CHECK: OpExtension "SPV_KHR_16bit_storage" OpMemoryModel Logical GLSL450 - OpEntryPoint GLCompute %2 "main" %input_var - OpDecorate %input_var BuiltIn LocalInvocationIndex + OpEntryPoint GLCompute %2 "main" %void = OpTypeVoid %half = OpTypeFloat 16 %float = OpTypeFloat 32 @@ -573,28 +750,57 @@ TEST_F(TrimCapabilitiesPassTest, %parent = OpTypeStruct %float %struct %ptr = OpTypePointer Input %parent %1 = OpTypeFunction %void - %input_var = OpVariable %ptr Input %2 = OpFunction %void None %1 %3 = OpLabel OpReturn OpFunctionEnd )"; + SetTargetEnv(SPV_ENV_VULKAN_1_0); const auto result = SinglePassRunAndMatch(kTest, /* skip_nop= */ false); EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); } TEST_F(TrimCapabilitiesPassTest, - StorageInputOutput16RemainsWithInputVariableArrayOfStruct) { + StorageInputOutput16_RemainsWithInputPointerStructOfStruct_Vulkan1_1) { const std::string kTest = R"( OpCapability Shader OpCapability Float16 OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" ; CHECK: OpCapability StorageInputOutput16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + %void = OpTypeVoid + %half = OpTypeFloat 16 + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float %half + %parent = OpTypeStruct %float %struct + %ptr = OpTypePointer Input %parent + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_1); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16_RemainsWithInputPointerArrayOfStruct_Vulkan1_0) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 OpExtension "SPV_KHR_16bit_storage" +; CHECK: OpCapability StorageInputOutput16 +; CHECK: OpExtension "SPV_KHR_16bit_storage" OpMemoryModel Logical GLSL450 - OpEntryPoint GLCompute %2 "main" %input_var - OpDecorate %input_var BuiltIn LocalInvocationIndex + OpEntryPoint GLCompute %2 "main" %void = OpTypeVoid %half = OpTypeFloat 16 %struct = OpTypeStruct %half @@ -603,83 +809,168 @@ TEST_F(TrimCapabilitiesPassTest, %array = OpTypeArray %struct %uint_1 %ptr = OpTypePointer Input %array %1 = OpTypeFunction %void - %input_var = OpVariable %ptr Input %2 = OpFunction %void None %1 %3 = OpLabel OpReturn OpFunctionEnd )"; + SetTargetEnv(SPV_ENV_VULKAN_1_0); const auto result = SinglePassRunAndMatch(kTest, /* skip_nop= */ false); EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); } TEST_F(TrimCapabilitiesPassTest, - StorageInputOutput16RemainsWithInputVariableVector) { + StorageInputOutput16_RemainsWithInputPointerArrayOfStruct_Vulkan1_1) { const std::string kTest = R"( OpCapability Shader OpCapability Float16 OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" ; CHECK: OpCapability StorageInputOutput16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + %void = OpTypeVoid + %half = OpTypeFloat 16 + %struct = OpTypeStruct %half + %uint = OpTypeInt 32 0 + %uint_1 = OpConstant %uint 1 + %array = OpTypeArray %struct %uint_1 + %ptr = OpTypePointer Input %array + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_1); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16_RemainsWithInputPointerVector_Vulkan1_0) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 OpExtension "SPV_KHR_16bit_storage" +; CHECK: OpCapability StorageInputOutput16 +; CHECK: OpExtension "SPV_KHR_16bit_storage" OpMemoryModel Logical GLSL450 - OpEntryPoint GLCompute %2 "main" %input_var - OpDecorate %input_var BuiltIn LocalInvocationIndex + OpEntryPoint GLCompute %2 "main" %void = OpTypeVoid %half = OpTypeFloat 16 %vector = OpTypeVector %half 4 %ptr = OpTypePointer Input %vector %1 = OpTypeFunction %void - %input_var = OpVariable %ptr Input %2 = OpFunction %void None %1 %3 = OpLabel OpReturn OpFunctionEnd )"; + SetTargetEnv(SPV_ENV_VULKAN_1_0); const auto result = SinglePassRunAndMatch(kTest, /* skip_nop= */ false); EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); } TEST_F(TrimCapabilitiesPassTest, - StorageInputOutput16RemainsWithInputVariableMatrix) { + StorageInputOutput16_RemainsWithInputPointerVector_Vulkan1_1) { const std::string kTest = R"( OpCapability Shader OpCapability Float16 OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" ; CHECK: OpCapability StorageInputOutput16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + %void = OpTypeVoid + %half = OpTypeFloat 16 + %vector = OpTypeVector %half 4 + %ptr = OpTypePointer Input %vector + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_1); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16_RemainsWithInputPointerMatrix_Vulkan1_0) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 OpExtension "SPV_KHR_16bit_storage" +; CHECK: OpCapability StorageInputOutput16 +; CHECK: OpExtension "SPV_KHR_16bit_storage" OpMemoryModel Logical GLSL450 - OpEntryPoint GLCompute %2 "main" %input_var - OpDecorate %input_var BuiltIn LocalInvocationIndex + OpEntryPoint GLCompute %2 "main" %void = OpTypeVoid %half = OpTypeFloat 16 %vector = OpTypeVector %half 4 %matrix = OpTypeMatrix %vector 4 %ptr = OpTypePointer Input %matrix %1 = OpTypeFunction %void - %input_var = OpVariable %ptr Input %2 = OpFunction %void None %1 %3 = OpLabel OpReturn OpFunctionEnd )"; + SetTargetEnv(SPV_ENV_VULKAN_1_0); const auto result = SinglePassRunAndMatch(kTest, /* skip_nop= */ false); EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); } TEST_F(TrimCapabilitiesPassTest, - StorageInputOutput16IsRemovedWithoutInputVariable) { + StorageInputOutput16_RemainsWithInputPointerMatrix_Vulkan1_1) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" +; CHECK: OpCapability StorageInputOutput16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + %void = OpTypeVoid + %half = OpTypeFloat 16 + %vector = OpTypeVector %half 4 + %matrix = OpTypeMatrix %vector 4 + %ptr = OpTypePointer Input %matrix + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_1); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16_IsRemovedWithoutInputPointer) { const std::string kTest = R"( OpCapability Shader OpCapability Float16 OpCapability StorageInputOutput16 -; CHECK-NOT: OpCapability StorageInputOutput16 OpExtension "SPV_KHR_16bit_storage" +; CHECK-NOT: OpCapability StorageInputOutput16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" OpMemoryModel Logical GLSL450 - OpEntryPoint GLCompute %2 "main" %input_var - OpDecorate %input_var BuiltIn LocalInvocationIndex + OpEntryPoint GLCompute %2 "main" %void = OpTypeVoid %1 = OpTypeFunction %void %2 = OpFunction %void None %1 @@ -687,48 +978,75 @@ TEST_F(TrimCapabilitiesPassTest, OpReturn OpFunctionEnd )"; + SetTargetEnv(SPV_ENV_VULKAN_1_0); const auto result = SinglePassRunAndMatch(kTest, /* skip_nop= */ false); EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); } TEST_F(TrimCapabilitiesPassTest, - StorageInputOutput16RemainsWithOutputVariable) { + StorageInputOutput16_RemainsWithOutputPointer_Vulkan1_0) { const std::string kTest = R"( OpCapability Shader OpCapability Float16 OpCapability StorageInputOutput16 -; CHECK: OpCapability StorageInputOutput16 OpExtension "SPV_KHR_16bit_storage" +; CHECK: OpCapability StorageInputOutput16 +; CHECK: OpExtension "SPV_KHR_16bit_storage" OpMemoryModel Logical GLSL450 - OpEntryPoint GLCompute %2 "main" %input_var - OpDecorate %input_var BuiltIn LocalInvocationIndex + OpEntryPoint GLCompute %2 "main" %void = OpTypeVoid %half = OpTypeFloat 16 %ptr = OpTypePointer Output %half %1 = OpTypeFunction %void - %input_var = OpVariable %ptr Output %2 = OpFunction %void None %1 %3 = OpLabel OpReturn OpFunctionEnd )"; + SetTargetEnv(SPV_ENV_VULKAN_1_0); const auto result = SinglePassRunAndMatch(kTest, /* skip_nop= */ false); EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); } TEST_F(TrimCapabilitiesPassTest, - StorageInputOutput16IsRemovedWithoutOutputVariable) { + StorageInputOutput16_RemainsWithOutputPointer_Vulkan1_1) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" +; CHECK: OpCapability StorageInputOutput16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + %void = OpTypeVoid + %half = OpTypeFloat 16 + %ptr = OpTypePointer Output %half + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_1); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16_RemovedWithoutOutputPointer) { const std::string kTest = R"( OpCapability Shader OpCapability Float16 OpCapability StorageInputOutput16 -; CHECK-NOT: OpCapability StorageInputOutput16 OpExtension "SPV_KHR_16bit_storage" +; CHECK-NOT: OpCapability StorageInputOutput16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" OpMemoryModel Logical GLSL450 - OpEntryPoint GLCompute %2 "main" %input_var - OpDecorate %input_var BuiltIn LocalInvocationIndex + OpEntryPoint GLCompute %2 "main" %void = OpTypeVoid %1 = OpTypeFunction %void %2 = OpFunction %void None %1 @@ -741,6 +1059,1433 @@ TEST_F(TrimCapabilitiesPassTest, EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); } +TEST_F(TrimCapabilitiesPassTest, + StoragePushConstant16_RemainsSimplePointer_Vulkan1_0) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StoragePushConstant16 + OpExtension "SPV_KHR_16bit_storage" +; CHECK: OpCapability StoragePushConstant16 +; CHECK: OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + %void = OpTypeVoid + %half = OpTypeFloat 16 + %ptr = OpTypePointer PushConstant %half + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_0); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StoragePushConstant16_RemainsSimplePointer_Vulkan1_1) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StoragePushConstant16 + OpExtension "SPV_KHR_16bit_storage" +; CHECK: OpCapability StoragePushConstant16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + %void = OpTypeVoid + %half = OpTypeFloat 16 + %ptr = OpTypePointer PushConstant %half + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_1); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, StoragePushConstant16_RemovedSimplePointer) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StoragePushConstant16 + OpExtension "SPV_KHR_16bit_storage" +; CHECK-NOT: OpCapability StoragePushConstant16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + %void = OpTypeVoid + %half = OpTypeFloat 16 + %ptr = OpTypePointer Function %half + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageUniformBufferBlock16_RemainsSimplePointer_Vulkan1_0) { + // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354 + static_assert(spv::Capability::StorageUniformBufferBlock16 == + spv::Capability::StorageBuffer16BitAccess); + + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageBuffer16BitAccess + OpExtension "SPV_KHR_16bit_storage" + +; CHECK: OpCapability StorageBuffer16BitAccess +; `-> StorageUniformBufferBlock16 +; CHECK: OpExtension "SPV_KHR_16bit_storage" + + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpDecorate %struct BufferBlock + %void = OpTypeVoid + %half = OpTypeFloat 16 + %struct = OpTypeStruct %half + %ptr = OpTypePointer Uniform %struct + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_0); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageUniformBufferBlock16_RemainsSimplePointer_Vulkan1_1) { + // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354 + static_assert(spv::Capability::StorageUniformBufferBlock16 == + spv::Capability::StorageBuffer16BitAccess); + + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageBuffer16BitAccess + OpExtension "SPV_KHR_16bit_storage" + +; CHECK: OpCapability StorageBuffer16BitAccess +; `-> StorageUniformBufferBlock16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" + + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpDecorate %struct BufferBlock + %void = OpTypeVoid + %half = OpTypeFloat 16 + %struct = OpTypeStruct %half + %ptr = OpTypePointer Uniform %struct + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_1); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageUniformBufferBlock16_RemovedSimplePointer) { + // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354 + static_assert(spv::Capability::StorageUniformBufferBlock16 == + spv::Capability::StorageBuffer16BitAccess); + + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageBuffer16BitAccess + OpExtension "SPV_KHR_16bit_storage" + +; CHECK-NOT: OpCapability StorageBuffer16BitAccess +; `-> StorageUniformBufferBlock16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" + + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + %void = OpTypeVoid + %half = OpTypeFloat 16 + %struct = OpTypeStruct %half + %ptr = OpTypePointer Function %struct + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageUniform16_RemovedWithBufferBlockPointer_Vulkan1_0) { + // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354 + static_assert(spv::Capability::StorageUniformBufferBlock16 == + spv::Capability::StorageBuffer16BitAccess); + static_assert(spv::Capability::StorageUniform16 == + spv::Capability::UniformAndStorageBuffer16BitAccess); + + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageBuffer16BitAccess + OpCapability UniformAndStorageBuffer16BitAccess + OpExtension "SPV_KHR_16bit_storage" + +; CHECK: OpCapability StorageBuffer16BitAccess +; `-> StorageUniformBufferBlock16 +; CHECK-NOT: OpCapability UniformAndStorageBuffer16BitAccess +; `-> StorageUniform16 +; CHECK: OpExtension "SPV_KHR_16bit_storage" + + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpDecorate %struct BufferBlock + %void = OpTypeVoid + %half = OpTypeFloat 16 + %struct = OpTypeStruct %half + %ptr = OpTypePointer Uniform %struct + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_0); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageUniform16_RemovedWithBufferBlockPointer_Vulkan1_1) { + // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354 + static_assert(spv::Capability::StorageUniformBufferBlock16 == + spv::Capability::StorageBuffer16BitAccess); + static_assert(spv::Capability::StorageUniform16 == + spv::Capability::UniformAndStorageBuffer16BitAccess); + + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageBuffer16BitAccess + OpCapability UniformAndStorageBuffer16BitAccess + OpExtension "SPV_KHR_16bit_storage" + +; CHECK: OpCapability StorageBuffer16BitAccess +; `-> StorageUniformBufferBlock16 +; CHECK-NOT: OpCapability UniformAndStorageBuffer16BitAccess +; `-> StorageUniform16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" + + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpDecorate %struct BufferBlock + %void = OpTypeVoid + %half = OpTypeFloat 16 + %struct = OpTypeStruct %half + %ptr = OpTypePointer Uniform %struct + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_1); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageUniform16_RemovedWithNonBlockUniformPointer_Vulkan1_0) { + // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354 + static_assert(spv::Capability::StorageUniformBufferBlock16 == + spv::Capability::StorageBuffer16BitAccess); + static_assert(spv::Capability::StorageUniform16 == + spv::Capability::UniformAndStorageBuffer16BitAccess); + + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageBuffer16BitAccess + OpCapability UniformAndStorageBuffer16BitAccess + OpExtension "SPV_KHR_16bit_storage" + +; CHECK-NOT: OpCapability StorageBuffer16BitAccess +; `-> StorageUniformBufferBlock16 +; CHECK: OpCapability UniformAndStorageBuffer16BitAccess +; `-> StorageUniform16 +; CHECK: OpExtension "SPV_KHR_16bit_storage" + + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + %void = OpTypeVoid + %half = OpTypeFloat 16 + %struct = OpTypeStruct %half + %ptr = OpTypePointer Uniform %struct + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_0); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageUniform16_RemovedWithNonBlockUniformPointer_Vulkan1_1) { + // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354 + static_assert(spv::Capability::StorageUniformBufferBlock16 == + spv::Capability::StorageBuffer16BitAccess); + static_assert(spv::Capability::StorageUniform16 == + spv::Capability::UniformAndStorageBuffer16BitAccess); + + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageBuffer16BitAccess + OpCapability UniformAndStorageBuffer16BitAccess + OpExtension "SPV_KHR_16bit_storage" + +; CHECK-NOT: OpCapability StorageBuffer16BitAccess +; `-> StorageUniformBufferBlock16 +; CHECK: OpCapability UniformAndStorageBuffer16BitAccess +; `-> StorageUniform16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" + + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + %void = OpTypeVoid + %half = OpTypeFloat 16 + %struct = OpTypeStruct %half + %ptr = OpTypePointer Uniform %struct + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_1); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, FragmentShaderInterlock_RemovedIfNotUsed) { + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderPixelInterlockEXT + OpCapability FragmentShaderSampleInterlockEXT + OpCapability FragmentShaderShadingRateInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" +; CHECK-NOT: OpCapability FragmentShaderPixelInterlockEXT +; CHECK-NOT: OpCapability FragmentShaderSampleInterlockEXT +; CHECK-NOT: OpCapability FragmentShaderShadingRateInterlockEXT +; CHECK-NOT: OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + FragmentShaderPixelInterlock_RemainsWhenOrderedIsUsed) { + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderPixelInterlockEXT + OpCapability FragmentShaderSampleInterlockEXT + OpCapability FragmentShaderShadingRateInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" +; CHECK: OpCapability FragmentShaderPixelInterlockEXT +; CHECK-NOT: OpCapability FragmentShaderSampleInterlockEXT +; CHECK-NOT: OpCapability FragmentShaderShadingRateInterlockEXT +; CHECK: OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %main PixelInterlockOrderedEXT + %void = OpTypeVoid + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + FragmentShaderPixelInterlock_RemainsWhenUnorderedIsUsed) { + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderPixelInterlockEXT + OpCapability FragmentShaderSampleInterlockEXT + OpCapability FragmentShaderShadingRateInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" +; CHECK: OpCapability FragmentShaderPixelInterlockEXT +; CHECK-NOT: OpCapability FragmentShaderSampleInterlockEXT +; CHECK-NOT: OpCapability FragmentShaderShadingRateInterlockEXT +; CHECK: OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %main PixelInterlockUnorderedEXT + %void = OpTypeVoid + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + FragmentShaderSampleInterlock_RemainsWhenOrderedIsUsed) { + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderPixelInterlockEXT + OpCapability FragmentShaderSampleInterlockEXT + OpCapability FragmentShaderShadingRateInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" +; CHECK-NOT: OpCapability FragmentShaderPixelInterlockEXT +; CHECK: OpCapability FragmentShaderSampleInterlockEXT +; CHECK-NOT: OpCapability FragmentShaderShadingRateInterlockEXT +; CHECK: OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %main SampleInterlockOrderedEXT + %void = OpTypeVoid + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + FragmentShaderSampleInterlock_RemainsWhenUnorderedIsUsed) { + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderPixelInterlockEXT + OpCapability FragmentShaderSampleInterlockEXT + OpCapability FragmentShaderShadingRateInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" +; CHECK-NOT: OpCapability FragmentShaderPixelInterlockEXT +; CHECK: OpCapability FragmentShaderSampleInterlockEXT +; CHECK-NOT: OpCapability FragmentShaderShadingRateInterlockEXT +; CHECK: OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %main SampleInterlockUnorderedEXT + %void = OpTypeVoid + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + FragmentShaderShadingRateInterlock_RemainsWhenOrderedIsUsed) { + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderPixelInterlockEXT + OpCapability FragmentShaderSampleInterlockEXT + OpCapability FragmentShaderShadingRateInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" +; CHECK-NOT: OpCapability FragmentShaderPixelInterlockEXT +; CHECK-NOT: OpCapability FragmentShaderSampleInterlockEXT +; CHECK: OpCapability FragmentShaderShadingRateInterlockEXT +; CHECK: OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %main ShadingRateInterlockOrderedEXT + %void = OpTypeVoid + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + FragmentShaderShadingRateInterlock_RemainsWhenUnorderedIsUsed) { + const std::string kTest = R"( + OpCapability Shader + OpCapability FragmentShaderPixelInterlockEXT + OpCapability FragmentShaderSampleInterlockEXT + OpCapability FragmentShaderShadingRateInterlockEXT + OpExtension "SPV_EXT_fragment_shader_interlock" +; CHECK-NOT: OpCapability FragmentShaderPixelInterlockEXT +; CHECK-NOT: OpCapability FragmentShaderSampleInterlockEXT +; CHECK: OpCapability FragmentShaderShadingRateInterlockEXT +; CHECK: OpExtension "SPV_EXT_fragment_shader_interlock" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %main ShadingRateInterlockUnorderedEXT + %void = OpTypeVoid + %1 = OpTypeFunction %void + %2 = OpFunction %void None %1 + %3 = OpLabel + OpBeginInvocationInterlockEXT + OpEndInvocationInterlockEXT + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, Int64_RemovedWhenUnused) { + const std::string kTest = R"( + OpCapability Int64 +; CHECK-NOT: OpCapability Int64 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %3 = OpTypeFunction %void + %1 = OpFunction %void None %3 + %6 = OpLabel + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, Int64_RemainsWhenUsed) { + const std::string kTest = R"( + OpCapability Int64 +; CHECK: OpCapability Int64 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %int = OpTypeInt 64 0 + %3 = OpTypeFunction %void + %1 = OpFunction %void None %3 + %6 = OpLabel + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, RayQueryKHR_RemovedWhenUnused) { + const std::string kTest = R"( + OpCapability Shader + OpCapability RayQueryKHR + OpExtension "SPV_KHR_ray_query" +; CHECK-NOT: OpCapability RayQueryKHR +; CHECK-NOT: OpExtension "SPV_KHR_ray_query" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %out_var_TEXCOORD1 + OpSource HLSL 660 + OpName %out_var_TEXCOORD1 "out.var.TEXCOORD1" + OpName %main "main" + OpDecorate %out_var_TEXCOORD1 Flat + OpDecorate %out_var_TEXCOORD1 Location 0 + %uint = OpTypeInt 32 0 + %uint_1234 = OpConstant %uint 1234 +%_ptr_Output_uint = OpTypePointer Output %uint + %void = OpTypeVoid + %7 = OpTypeFunction %void +%out_var_TEXCOORD1 = OpVariable %_ptr_Output_uint Output + %main = OpFunction %void None %7 + %8 = OpLabel + OpStore %out_var_TEXCOORD1 %uint_1234 + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + RayQueryKHR_RemainsWhenAccelerationStructureIsPresent) { + const std::string kTest = R"( + OpCapability Shader + OpCapability RayQueryKHR + OpExtension "SPV_KHR_ray_query" +; CHECK: OpCapability RayQueryKHR +; CHECK: OpExtension "SPV_KHR_ray_query" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + OpDecorate %var_bvh DescriptorSet 0 + OpDecorate %var_bvh Binding 0 + %bvh = OpTypeAccelerationStructureKHR + %ptr_bvh = OpTypePointer UniformConstant %bvh + %void = OpTypeVoid + %20 = OpTypeFunction %void + %var_bvh = OpVariable %ptr_bvh UniformConstant + %main = OpFunction %void None %20 + %30 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, RayQueryKHR_RemainsWhenRayQueryTypeIsPresent) { + const std::string kTest = R"( + OpCapability Shader + OpCapability RayQueryKHR + OpExtension "SPV_KHR_ray_query" +; CHECK: OpCapability RayQueryKHR +; CHECK: OpExtension "SPV_KHR_ray_query" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + %query = OpTypeRayQueryKHR + %void = OpTypeVoid + %20 = OpTypeFunction %void + %ptr_query = OpTypePointer Function %query + %main = OpFunction %void None %20 + %30 = OpLabel + %var_query = OpVariable %ptr_query Function + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, RayQueryKHR_RemainsWhenUsed) { + const std::string kTest = R"( + OpCapability Shader + OpCapability RayQueryKHR + OpExtension "SPV_KHR_ray_query" +; CHECK: OpCapability RayQueryKHR +; CHECK: OpExtension "SPV_KHR_ray_query" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + OpDecorate %bvh DescriptorSet 0 + OpDecorate %bvh Binding 0 + OpDecorate %output DescriptorSet 0 + OpDecorate %output Binding 1 + OpDecorate %_runtimearr_float ArrayStride 4 + OpMemberDecorate %type_RWStructuredBuffer_float 0 Offset 0 + OpDecorate %type_RWStructuredBuffer_float BufferBlock + %float = OpTypeFloat 32 + %float_0 = OpConstant %float 0 + %int = OpTypeInt 32 1 + %v3float = OpTypeVector %float 3 + %12 = OpConstantComposite %v3float %float_0 %float_0 %float_0 + %int_0 = OpConstant %int 0 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_1 = OpConstant %uint 1 +%accelerationStructureKHR = OpTypeAccelerationStructureKHR +%_ptr_UniformConstant_accelerationStructureKHR = OpTypePointer UniformConstant %accelerationStructureKHR +%_runtimearr_float = OpTypeRuntimeArray %float +%type_RWStructuredBuffer_float = OpTypeStruct %_runtimearr_float +%_ptr_Uniform_type_RWStructuredBuffer_float = OpTypePointer Uniform %type_RWStructuredBuffer_float + %void = OpTypeVoid + %20 = OpTypeFunction %void +%rayQueryKHR = OpTypeRayQueryKHR +%_ptr_Function_rayQueryKHR = OpTypePointer Function %rayQueryKHR + %bool = OpTypeBool +%_ptr_Uniform_float = OpTypePointer Uniform %float + %bvh = OpVariable %_ptr_UniformConstant_accelerationStructureKHR UniformConstant + %output = OpVariable %_ptr_Uniform_type_RWStructuredBuffer_float Uniform + %main = OpFunction %void None %20 + %24 = OpLabel + %25 = OpVariable %_ptr_Function_rayQueryKHR Function + %26 = OpLoad %accelerationStructureKHR %bvh + OpRayQueryInitializeKHR %25 %26 %uint_0 %uint_0 %12 %float_0 %12 %float_0 + %27 = OpRayQueryProceedKHR %bool %25 + %28 = OpRayQueryGetIntersectionTypeKHR %uint %25 %uint_1 + %29 = OpIEqual %bool %28 %uint_1 + OpSelectionMerge %30 None + OpBranchConditional %29 %31 %30 + %31 = OpLabel + %32 = OpAccessChain %_ptr_Uniform_float %output %int_0 %uint_0 + OpStore %32 %float_0 + OpBranch %30 + %30 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + RayTracingKHR_RemainsWithIntersectionExecutionMode) { + const std::string kTest = R"( + OpCapability RayTracingKHR + OpExtension "SPV_KHR_ray_tracing" +; CHECK: OpCapability RayTracingKHR +; CHECK: OpExtension "SPV_KHR_ray_tracing" + OpMemoryModel Logical GLSL450 + OpEntryPoint IntersectionKHR %main "main" + OpSource HLSL 660 + OpName %main "main" + %void = OpTypeVoid + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %4 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + RayTracingKHR_RemainsWithClosestHitExecutionMode) { + const std::string kTest = R"( + OpCapability RayTracingKHR + OpExtension "SPV_KHR_ray_tracing" +; CHECK: OpCapability RayTracingKHR +; CHECK: OpExtension "SPV_KHR_ray_tracing" + OpMemoryModel Logical GLSL450 + OpEntryPoint ClosestHitKHR %main "main" %a + OpSource HLSL 630 + OpName %Payload "Payload" + OpMemberName %Payload 0 "color" + OpName %a "a" + OpName %main "main" + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %Payload = OpTypeStruct %v4float +%ptr_payload = OpTypePointer IncomingRayPayloadKHR %Payload + %void = OpTypeVoid + %8 = OpTypeFunction %void + %a = OpVariable %ptr_payload IncomingRayPayloadKHR + %main = OpFunction %void None %8 + %9 = OpLabel + %10 = OpLoad %Payload %a + OpStore %a %10 + OpReturn + OpFunctionEnd + + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, RayTracingKHR_RemainsWithAnyHitExecutionMode) { + const std::string kTest = R"( + OpCapability RayTracingKHR + OpExtension "SPV_KHR_ray_tracing" +; CHECK: OpCapability RayTracingKHR +; CHECK: OpExtension "SPV_KHR_ray_tracing" + OpMemoryModel Logical GLSL450 + OpEntryPoint AnyHitKHR %main "main" %a + OpSource HLSL 630 + OpName %Payload "Payload" + OpMemberName %Payload 0 "color" + OpName %a "a" + OpName %main "main" + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %Payload = OpTypeStruct %v4float +%ptr_payload = OpTypePointer IncomingRayPayloadKHR %Payload + %void = OpTypeVoid + %8 = OpTypeFunction %void + %a = OpVariable %ptr_payload IncomingRayPayloadKHR + %main = OpFunction %void None %8 + %9 = OpLabel + %10 = OpLoad %Payload %a + OpStore %a %10 + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, RayTracingKHR_RemainsWithMissExecutionMode) { + const std::string kTest = R"( + OpCapability RayTracingKHR + OpExtension "SPV_KHR_ray_tracing" +; CHECK: OpCapability RayTracingKHR +; CHECK: OpExtension "SPV_KHR_ray_tracing" + OpMemoryModel Logical GLSL450 + OpEntryPoint MissKHR %main "main" %a + OpSource HLSL 630 + OpName %Payload "Payload" + OpMemberName %Payload 0 "color" + OpName %a "a" + OpName %main "main" + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %Payload = OpTypeStruct %v4float +%ptr_payload = OpTypePointer IncomingRayPayloadKHR %Payload + %void = OpTypeVoid + %8 = OpTypeFunction %void + %a = OpVariable %ptr_payload IncomingRayPayloadKHR + %main = OpFunction %void None %8 + %9 = OpLabel + %10 = OpLoad %Payload %a + OpStore %a %10 + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + RayTracingKHR_RemainsWithRayGenerationExecutionMode) { + const std::string kTest = R"( + OpCapability RayTracingKHR + OpExtension "SPV_KHR_ray_tracing" +; CHECK: OpCapability RayTracingKHR +; CHECK: OpExtension "SPV_KHR_ray_tracing" + OpMemoryModel Logical GLSL450 + OpEntryPoint RayGenerationKHR %main "main" + OpSource HLSL 630 + OpName %main "main" + %void = OpTypeVoid + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %4 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + RayTracingKHR_RemainsWithCallableExecutionMode) { + const std::string kTest = R"( +; CHECK: OpCapability RayTracingKHR +; CHECK: OpExtension "SPV_KHR_ray_tracing" + OpCapability RayTracingKHR + OpExtension "SPV_KHR_ray_tracing" + OpMemoryModel Logical GLSL450 + OpEntryPoint CallableKHR %main "main" %a + OpSource HLSL 660 + OpName %Payload "Payload" + OpMemberName %Payload 0 "data" + OpName %a "a" + OpName %main "main" + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %Payload = OpTypeStruct %v4float +%ptr_payload = OpTypePointer IncomingCallableDataKHR %Payload + %void = OpTypeVoid + %8 = OpTypeFunction %void + %a = OpVariable %ptr_payload IncomingCallableDataKHR + %main = OpFunction %void None %8 + %9 = OpLabel + %10 = OpLoad %Payload %a + OpStore %a %10 + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + ImageMSArray_RemainsIfSampledIs2AndArrayedIs1) { + const std::string kTest = R"( + OpCapability ImageMSArray + ; CHECK: OpCapability ImageMSArray + OpCapability Shader + OpCapability StorageImageMultisample + OpCapability StorageImageReadWithoutFormat + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpDecorate %var_image DescriptorSet 0 + OpDecorate %var_image Binding 1 + %void = OpTypeVoid + %func = OpTypeFunction %void + %f32 = OpTypeFloat 32 + %u32 = OpTypeInt 32 0 + %uint_2 = OpConstant %u32 2 + %uint_1 = OpConstant %u32 1 + %v2uint = OpTypeVector %u32 2 + %v4float = OpTypeVector %f32 4 + %image = OpTypeImage %f32 2D 2 1 1 2 Unknown +%ptr_image = OpTypePointer UniformConstant %image + %10 = OpConstantComposite %v2uint %uint_1 %uint_2 +%var_image = OpVariable %ptr_image UniformConstant + %main = OpFunction %void None %func + %main_lab = OpLabel + %18 = OpLoad %image %var_image + %19 = OpImageRead %v4float %18 %10 Sample %uint_2 + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, ImageMSArray_RemovedIfNotUsed) { + const std::string kTest = R"( + OpCapability Shader + OpCapability ImageMSArray +; CHECK-NOT: OpCapability ImageMSArray + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %out_var_SV_Target + OpExecutionMode %main OriginUpperLeft + OpSource HLSL 660 + OpName %out_var_SV_Target "out.var.SV_Target" + OpName %main "main" + OpDecorate %out_var_SV_Target Location 0 + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %7 = OpTypeFunction %void +%out_var_SV_Target = OpVariable %_ptr_Output_v4float Output + %main = OpFunction %void None %7 + %8 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, ImageMSArray_RemovedIfArrayedIsNot1) { + const std::string kTest = R"( + OpCapability ImageMSArray + ; CHECK-NOT: OpCapability ImageMSArray + OpCapability Shader + OpCapability StorageImageMultisample + OpCapability StorageImageReadWithoutFormat + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpDecorate %var_image DescriptorSet 0 + OpDecorate %var_image Binding 1 + %void = OpTypeVoid + %func = OpTypeFunction %void + %f32 = OpTypeFloat 32 + %u32 = OpTypeInt 32 0 + %uint_2 = OpConstant %u32 2 + %uint_1 = OpConstant %u32 1 + %v2uint = OpTypeVector %u32 2 + %v4float = OpTypeVector %f32 4 + %image = OpTypeImage %f32 2D 2 0 1 2 Unknown +%ptr_image = OpTypePointer UniformConstant %image + %10 = OpConstantComposite %v2uint %uint_1 %uint_2 +%var_image = OpVariable %ptr_image UniformConstant + %main = OpFunction %void None %func + %main_lab = OpLabel + %18 = OpLoad %image %var_image + %19 = OpImageRead %v4float %18 %10 Sample %uint_2 + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, ImageMSArray_RemovedIfSampledNot2) { + const std::string kTest = R"( + OpCapability ImageMSArray + ; CHECK-NOT: OpCapability ImageMSArray + OpCapability Shader + OpCapability StorageImageReadWithoutFormat + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpDecorate %var_image DescriptorSet 0 + OpDecorate %var_image Binding 1 + %void = OpTypeVoid + %func = OpTypeFunction %void + %f32 = OpTypeFloat 32 + %u32 = OpTypeInt 32 0 + %uint_3 = OpConstant %u32 3 + %uint_2 = OpConstant %u32 2 + %uint_1 = OpConstant %u32 1 + %v3uint = OpTypeVector %u32 3 + %v4float = OpTypeVector %f32 4 + %image = OpTypeImage %f32 2D 2 1 0 2 Unknown +%ptr_image = OpTypePointer UniformConstant %image + %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3 +%var_image = OpVariable %ptr_image UniformConstant + %main = OpFunction %void None %func + %main_lab = OpLabel + %18 = OpLoad %image %var_image + %19 = OpImageRead %v4float %18 %10 + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, Float64_RemovedWhenUnused) { + const std::string kTest = R"( + OpCapability Float64 +; CHECK-NOT: OpCapability Float64 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %3 = OpTypeFunction %void + %1 = OpFunction %void None %3 + %6 = OpLabel + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, Float64_RemainsWhenUsed) { + const std::string kTest = R"( + OpCapability Float64 +; CHECK: OpCapability Float64 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %float = OpTypeFloat 64 + %3 = OpTypeFunction %void + %1 = OpFunction %void None %3 + %6 = OpLabel + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + ComputeDerivativeGroupQuads_ReamainsWithExecMode) { + const std::string kTest = R"( + OpCapability ComputeDerivativeGroupQuadsNV + OpCapability ComputeDerivativeGroupLinearNV +; CHECK-NOT: OpCapability ComputeDerivativeGroupLinearNV +; CHECK: OpCapability ComputeDerivativeGroupQuadsNV +; CHECK-NOT: OpCapability ComputeDerivativeGroupLinearNV + OpCapability Shader +; CHECK: OpExtension "SPV_NV_compute_shader_derivatives" + OpExtension "SPV_NV_compute_shader_derivatives" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 DerivativeGroupQuadsNV + %void = OpTypeVoid + %3 = OpTypeFunction %void + %1 = OpFunction %void None %3 + %6 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + ComputeDerivativeGroupLinear_ReamainsWithExecMode) { + const std::string kTest = R"( + OpCapability ComputeDerivativeGroupLinearNV + OpCapability ComputeDerivativeGroupQuadsNV +; CHECK-NOT: OpCapability ComputeDerivativeGroupQuadsNV +; CHECK: OpCapability ComputeDerivativeGroupLinearNV +; CHECK-NOT: OpCapability ComputeDerivativeGroupQuadsNV + OpCapability Shader +; CHECK: OpExtension "SPV_NV_compute_shader_derivatives" + OpExtension "SPV_NV_compute_shader_derivatives" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 DerivativeGroupLinearNV + %void = OpTypeVoid + %float = OpTypeFloat 64 + %3 = OpTypeFunction %void + %1 = OpFunction %void None %3 + %6 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageImageReadWithoutFormat_RemovedIfUnused) { + const std::string kTest = R"( + OpCapability StorageImageReadWithoutFormat +; CHECK-NOT: OpCapability StorageImageReadWithoutFormat + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %PSMain "PSMain" %out_var + OpExecutionMode %PSMain OriginUpperLeft + OpDecorate %out_var Location 0 + %float = OpTypeFloat 32 + %float4 = OpTypeVector %float 4 + %float_0 = OpConstant %float 0 +%float4_0000 = OpConstantComposite %float4 %float_0 %float_0 %float_0 %float_0 + %ptr_float4 = OpTypePointer Output %float4 + %void = OpTypeVoid + %9 = OpTypeFunction %void + %out_var = OpVariable %ptr_float4 Output + %PSMain = OpFunction %void None %9 + %10 = OpLabel + OpStore %out_var %float4_0000 + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageImageReadWithoutFormat_RemovedIfUnusedOpImageFetch) { + const std::string kTest = R"( + OpCapability StorageImageReadWithoutFormat +; CHECK-NOT: OpCapability StorageImageReadWithoutFormat + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %PSMain "PSMain" %out_var + OpExecutionMode %PSMain OriginUpperLeft + OpDecorate %out_var Location 0 + OpDecorate %texture DescriptorSet 0 + OpDecorate %texture Binding 1 + %float = OpTypeFloat 32 + %float4 = OpTypeVector %float 4 + %int = OpTypeInt 32 1 + %int2 = OpTypeVector %int 2 + %type_image = OpTypeImage %float 2D 2 0 0 1 Unknown + %ptr_image = OpTypePointer UniformConstant %type_image + %int_0 = OpConstant %int 0 + %int2_00 = OpConstantComposite %int2 %int_0 %int_0 + %ptr_float4 = OpTypePointer Output %float4 + %void = OpTypeVoid + %9 = OpTypeFunction %void + %texture = OpVariable %ptr_image UniformConstant + %out_var = OpVariable %ptr_float4 Output + %PSMain = OpFunction %void None %9 + %10 = OpLabel + %11 = OpLoad %type_image %texture + %12 = OpImageFetch %float4 %11 %int2_00 Lod %int_0 + OpStore %out_var %12 + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageImageReadWithoutFormat_RemainsWhenRequiredWithRead) { + const std::string kTest = R"( + OpCapability StorageImageReadWithoutFormat +; CHECK: OpCapability StorageImageReadWithoutFormat + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %PSMain "PSMain" %out_var + OpExecutionMode %PSMain OriginUpperLeft + OpDecorate %out_var Location 0 + OpDecorate %texture DescriptorSet 0 + OpDecorate %texture Binding 1 + %float = OpTypeFloat 32 + %float4 = OpTypeVector %float 4 + %int = OpTypeInt 32 1 + %int2 = OpTypeVector %int 2 + %type_image = OpTypeImage %float 2D 2 0 0 1 Unknown + %ptr_image = OpTypePointer UniformConstant %type_image + %int_0 = OpConstant %int 0 + %int2_00 = OpConstantComposite %int2 %int_0 %int_0 + %ptr_float4 = OpTypePointer Output %float4 + %void = OpTypeVoid + %9 = OpTypeFunction %void + %texture = OpVariable %ptr_image UniformConstant + %out_var = OpVariable %ptr_float4 Output + %PSMain = OpFunction %void None %9 + %10 = OpLabel + %11 = OpLoad %type_image %texture + %12 = OpImageRead %float4 %11 %int2_00 Lod %int_0 + OpStore %out_var %12 + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageImageReadWithoutFormat_RemainsWhenRequiredWithSparseRead) { + const std::string kTest = R"( + OpCapability StorageImageReadWithoutFormat +; CHECK: OpCapability StorageImageReadWithoutFormat + OpCapability SparseResidency + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %PSMain "PSMain" + OpExecutionMode %PSMain OriginUpperLeft + OpDecorate %texture DescriptorSet 0 + OpDecorate %texture Binding 1 + %float = OpTypeFloat 32 + %float4 = OpTypeVector %float 4 + %int = OpTypeInt 32 1 + %int2 = OpTypeVector %int 2 + %type_image = OpTypeImage %float 2D 2 0 0 2 Unknown + %struct = OpTypeStruct %int %float4 + %ptr_image = OpTypePointer UniformConstant %type_image + %int_0 = OpConstant %int 0 + %int2_00 = OpConstantComposite %int2 %int_0 %int_0 + %void = OpTypeVoid + %9 = OpTypeFunction %void + %texture = OpVariable %ptr_image UniformConstant + %PSMain = OpFunction %void None %9 + %10 = OpLabel + %11 = OpLoad %type_image %texture + %12 = OpImageSparseRead %struct %11 %int2_00 + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageImageReadWithoutFormat_RemovedWithReadOnSubpassData) { + const std::string kTest = R"( + OpCapability StorageImageReadWithoutFormat +; CHECK-NOT: OpCapability StorageImageReadWithoutFormat + OpCapability InputAttachment + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %PSMain "PSMain" %out_var + OpExecutionMode %PSMain OriginUpperLeft + OpDecorate %out_var Location 0 + OpDecorate %texture DescriptorSet 0 + OpDecorate %texture Binding 1 + %float = OpTypeFloat 32 + %float4 = OpTypeVector %float 4 + %int = OpTypeInt 32 1 + %int2 = OpTypeVector %int 2 + %type_image = OpTypeImage %float SubpassData 2 0 0 2 Unknown + %ptr_image = OpTypePointer UniformConstant %type_image + %int_0 = OpConstant %int 0 + %int2_00 = OpConstantComposite %int2 %int_0 %int_0 + %ptr_float4 = OpTypePointer Output %float4 + %void = OpTypeVoid + %9 = OpTypeFunction %void + %texture = OpVariable %ptr_image UniformConstant + %out_var = OpVariable %ptr_float4 Output + %PSMain = OpFunction %void None %9 + %10 = OpLabel + %11 = OpLoad %type_image %texture + %12 = OpImageRead %float4 %11 %int2_00 + OpStore %out_var %12 + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, PhysicalStorageBuffer_RemovedWhenUnused) { + const std::string kTest = R"( + OpCapability PhysicalStorageBufferAddresses +; CHECK-NOT: OpCapability PhysicalStorageBufferAddresses + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %3 = OpTypeFunction %void + %1 = OpFunction %void None %3 + %6 = OpLabel + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + PhysicalStorageBuffer_RemainsWithOpTypeForwardPointer) { + const std::string kTest = R"( + OpCapability PhysicalStorageBufferAddresses +; CHECK: OpCapability PhysicalStorageBufferAddresses + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + %void = OpTypeVoid + %int = OpTypeInt 32 0 + %struct = OpTypeStruct %int + OpTypeForwardPointer %ptr PhysicalStorageBuffer + %ptr = OpTypePointer PhysicalStorageBuffer %struct + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + PhysicalStorageBuffer_RemainsWithPhysicalStorageBufferStorage) { + const std::string kTest = R"( + OpCapability PhysicalStorageBufferAddresses +; CHECK: OpCapability PhysicalStorageBufferAddresses + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + %void = OpTypeVoid + %int = OpTypeInt 32 0 + %struct = OpTypeStruct %int + %ptr = OpTypePointer PhysicalStorageBuffer %struct + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + PhysicalStorageBuffer_RemainsWithRestrictDecoration) { + const std::string kTest = R"( + OpCapability PhysicalStorageBufferAddresses +; CHECK: OpCapability PhysicalStorageBufferAddresses + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + OpDecorate %var RestrictPointer + %void = OpTypeVoid + %int = OpTypeInt 32 0 + %struct = OpTypeStruct %int + %ptr = OpTypePointer Function %struct + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + %var = OpVariable %ptr Function + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + PhysicalStorageBuffer_RemainsWithAliasedDecoration) { + const std::string kTest = R"( + OpCapability PhysicalStorageBufferAddresses +; CHECK: OpCapability PhysicalStorageBufferAddresses + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + OpDecorate %var AliasedPointer + %void = OpTypeVoid + %int = OpTypeInt 32 0 + %struct = OpTypeStruct %int + %ptr = OpTypePointer Function %struct + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + %var = OpVariable %ptr Function + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp index 7febb69749..e32e237a51 100644 --- a/test/val/val_decoration_test.cpp +++ b/test/val/val_decoration_test.cpp @@ -8003,6 +8003,7 @@ TEST_F(ValidateDecorations, WorkgroupBlockVariableWith16BitType) { OpCapability Shader OpCapability Float16 OpCapability Int16 + OpCapability WorkgroupMemoryExplicitLayoutKHR OpCapability WorkgroupMemoryExplicitLayout16BitAccessKHR OpExtension "SPV_KHR_workgroup_memory_explicit_layout" OpMemoryModel Logical GLSL450 @@ -8265,6 +8266,37 @@ TEST_F(ValidateDecorations, WorkgroupSingleBlockVariableBadLayout) { "member 0 at offset 1 is not aligned to 4")); } +TEST_F(ValidateDecorations, WorkgroupBlockNoCapability) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %_ + OpExecutionMode %main LocalSize 1 1 1 + OpMemberDecorate %struct 0 Offset 0 + OpMemberDecorate %struct 1 Offset 4 + OpDecorate %struct Block + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %struct = OpTypeStruct %int %int +%ptr_workgroup = OpTypePointer Workgroup %struct + %_ = OpVariable %ptr_workgroup Workgroup + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_1_SPIRV_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Workgroup Storage Class variables can't be decorated with Block " + "unless declaring the WorkgroupMemoryExplicitLayoutKHR capability")); +} + TEST_F(ValidateDecorations, BadMatrixStrideUniform) { const std::string spirv = R"( OpCapability Shader diff --git a/test/val/val_ext_inst_debug_test.cpp b/test/val/val_ext_inst_debug_test.cpp index 554e78b082..8f0da42d55 100644 --- a/test/val/val_ext_inst_debug_test.cpp +++ b/test/val/val_ext_inst_debug_test.cpp @@ -1012,9 +1012,9 @@ TEST_F(ValidateOpenCL100DebugInfo, DebugTypePointerFail) { CompileSuccessfully(GenerateShaderCodeForDebugInfo( src, size_const, dbg_inst_header, "", extension, "Vertex")); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand Base Type must be a result id of " - "DebugTypeBasic")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("expected operand Base Type is not a valid debug type")); } TEST_F(ValidateOpenCL100DebugInfo, DebugTypeQualifier) { @@ -1077,9 +1077,9 @@ TEST_F(ValidateOpenCL100DebugInfo, DebugTypeQualifierFail) { CompileSuccessfully(GenerateShaderCodeForDebugInfo( src, size_const, dbg_inst_header, "", extension, "Vertex")); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand Base Type must be a result id of " - "DebugTypeBasic")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("expected operand Base Type is not a valid debug type")); } TEST_F(ValidateVulkan100DebugInfo, DebugTypeQualifier) { const std::string src = R"( @@ -1147,9 +1147,9 @@ OpExtension "SPV_KHR_non_semantic_info" CompileSuccessfully(GenerateShaderCodeForDebugInfo( src, constants, dbg_inst_header, "", extension, "Vertex")); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("expected operand Base Type must be a result id of " - "DebugTypeBasic")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("expected operand Base Type is not a valid debug type")); } TEST_F(ValidateOpenCL100DebugInfo, DebugTypeArray) { diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index 9aceaf5774..9a704098de 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -5852,10 +5852,12 @@ TEST_F(ValidateImage, SignExtendV13Bad) { %res1 = OpImageRead %u32vec4 %img %u32vec2_01 SignExtend )"; - EXPECT_THAT(CompileFailure(GenerateShaderCode(body, "", "Fragment", "", - SPV_ENV_UNIVERSAL_1_3), - SPV_ENV_UNIVERSAL_1_3, SPV_ERROR_WRONG_VERSION), - HasSubstr("Invalid image operand 'SignExtend'")); + CompileSuccessfully( + GenerateShaderCode(body, "", "Fragment", "", SPV_ENV_UNIVERSAL_1_3)); + ASSERT_EQ(SPV_ERROR_WRONG_VERSION, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("SignExtend(4096) requires SPIR-V version 1.4 or later")); } TEST_F(ValidateImage, ZeroExtendV13Bad) { @@ -5864,10 +5866,12 @@ TEST_F(ValidateImage, ZeroExtendV13Bad) { %res1 = OpImageRead %u32vec4 %img %u32vec2_01 ZeroExtend )"; - EXPECT_THAT(CompileFailure(GenerateShaderCode(body, "", "Fragment", "", - SPV_ENV_UNIVERSAL_1_3), - SPV_ENV_UNIVERSAL_1_3, SPV_ERROR_WRONG_VERSION), - HasSubstr("Invalid image operand 'ZeroExtend'")); + CompileSuccessfully( + GenerateShaderCode(body, "", "Fragment", "", SPV_ENV_UNIVERSAL_1_3)); + ASSERT_EQ(SPV_ERROR_WRONG_VERSION, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("ZeroExtend(8192) requires SPIR-V version 1.4 or later")); } TEST_F(ValidateImage, SignExtendScalarUIntTexelV14Good) { @@ -6673,6 +6677,1375 @@ TEST_F(ValidateImage, NVBindlessInvalidAddressingMode) { HasSubstr("OpSamplerImageAddressingModeNV bitwidth should be 64 or 32")); } +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADNoDecorationA) { + std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 %4 %5 %6 + OpExecutionMode %2 OriginUpperLeft + OpDecorate %3 Location 0 + OpDecorate %4 DescriptorSet 0 + OpDecorate %4 Binding 1 + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 3 + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 2 + OpDecorate %6 BlockMatchTextureQCOM + %void = OpTypeVoid + %8 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_ptr_Input_float = OpTypePointer Input %float +%_ptr_Function_uint = OpTypePointer Function %uint +%uint_4 = OpConstant %uint 4 + %17 = OpConstantComposite %v2uint %uint_4 %uint_4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %3 = OpVariable %_ptr_Output_v4float Output + %19 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19 + %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %21 = OpTypeSampler +%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21 + %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant + %23 = OpTypeSampledImage %19 + %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %2 = OpFunction %void None %8 + %24 = OpLabel + %25 = OpVariable %_ptr_Function_v2uint Function + %26 = OpLoad %19 %4 + %27 = OpLoad %21 %5 + %28 = OpSampledImage %23 %26 %27 + %29 = OpLoad %v2uint %25 + %30 = OpLoad %19 %6 + %31 = OpLoad %21 %5 + %32 = OpSampledImage %23 %30 %31 + %33 = OpImageBlockMatchSADQCOM %v4float %28 %29 %32 %29 %29 + OpStore %3 %33 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Missing decoration")); +} + +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADNoDecorationB) { + std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 %4 %5 %6 + OpExecutionMode %2 OriginUpperLeft + OpDecorate %3 Location 0 + OpDecorate %4 DescriptorSet 0 + OpDecorate %4 Binding 1 + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 3 + OpDecorate %5 BlockMatchTextureQCOM + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 2 + %void = OpTypeVoid + %8 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_ptr_Input_float = OpTypePointer Input %float +%_ptr_Function_uint = OpTypePointer Function %uint +%uint_4 = OpConstant %uint 4 + %17 = OpConstantComposite %v2uint %uint_4 %uint_4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %3 = OpVariable %_ptr_Output_v4float Output + %19 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19 + %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %21 = OpTypeSampler +%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21 + %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant + %23 = OpTypeSampledImage %19 + %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %2 = OpFunction %void None %8 + %24 = OpLabel + %25 = OpVariable %_ptr_Function_v2uint Function + %26 = OpLoad %19 %4 + %27 = OpLoad %21 %5 + %28 = OpSampledImage %23 %26 %27 + %29 = OpLoad %v2uint %25 + %30 = OpLoad %19 %6 + %31 = OpLoad %21 %5 + %32 = OpSampledImage %23 %30 %31 + %33 = OpImageBlockMatchSADQCOM %v4float %28 %29 %32 %29 %29 + OpStore %3 %33 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Missing decoration")); +} + +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADNoDecorationC) { + std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 %4 %5 + OpExecutionMode %2 OriginUpperLeft + OpDecorate %3 Location 0 + OpDecorate %4 DescriptorSet 0 + OpDecorate %4 Binding 4 + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 5 + OpDecorate %5 BlockMatchTextureQCOM + %void = OpTypeVoid + %7 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Input_float = OpTypePointer Input %float +%_ptr_Function_uint = OpTypePointer Function %uint +%_ptr_Output_v4float = OpTypePointer Output %v4float + %3 = OpVariable %_ptr_Output_v4float Output + %18 = OpTypeImage %float 2D 0 0 0 1 Unknown + %19 = OpTypeSampledImage %18 +%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19 + %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %21 = OpTypeImage %float 2D 0 1 0 1 Unknown + %2 = OpFunction %void None %7 + %22 = OpLabel + %23 = OpVariable %_ptr_Function_v2uint Function + %24 = OpLoad %19 %4 + %25 = OpLoad %v2uint %23 + %26 = OpLoad %19 %5 + %27 = OpLoad %v2uint %23 + %28 = OpLoad %v2uint %23 + %29 = OpImageBlockMatchSADQCOM %v4float %24 %25 %26 %27 %28 + OpStore %3 %29 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Missing decoration")); +} + +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADNoDecorationD) { + std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 %4 %5 + OpExecutionMode %2 OriginUpperLeft + OpDecorate %3 Location 0 + OpDecorate %4 DescriptorSet 0 + OpDecorate %4 Binding 4 + OpDecorate %4 BlockMatchTextureQCOM + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 5 + %void = OpTypeVoid + %7 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Input_float = OpTypePointer Input %float +%_ptr_Function_uint = OpTypePointer Function %uint +%_ptr_Output_v4float = OpTypePointer Output %v4float + %3 = OpVariable %_ptr_Output_v4float Output + %18 = OpTypeImage %float 2D 0 0 0 1 Unknown + %19 = OpTypeSampledImage %18 +%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19 + %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %21 = OpTypeImage %float 2D 0 1 0 1 Unknown + %2 = OpFunction %void None %7 + %22 = OpLabel + %23 = OpVariable %_ptr_Function_v2uint Function + %24 = OpLoad %19 %4 + %25 = OpLoad %v2uint %23 + %26 = OpLoad %19 %5 + %27 = OpLoad %v2uint %23 + %28 = OpLoad %v2uint %23 + %29 = OpImageBlockMatchSADQCOM %v4float %24 %25 %26 %27 %28 + OpStore %3 %29 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Missing decoration")); +} + +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDNoDecorationA) { + std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 %4 %5 %6 + OpExecutionMode %2 OriginUpperLeft + OpDecorate %3 Location 0 + OpDecorate %4 DescriptorSet 0 + OpDecorate %4 Binding 1 + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 3 + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 2 + OpDecorate %6 BlockMatchTextureQCOM + %void = OpTypeVoid + %8 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_ptr_Input_float = OpTypePointer Input %float +%_ptr_Function_uint = OpTypePointer Function %uint +%uint_4 = OpConstant %uint 4 + %17 = OpConstantComposite %v2uint %uint_4 %uint_4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %3 = OpVariable %_ptr_Output_v4float Output + %19 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19 + %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %21 = OpTypeSampler +%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21 + %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant + %23 = OpTypeSampledImage %19 + %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %2 = OpFunction %void None %8 + %24 = OpLabel + %25 = OpVariable %_ptr_Function_v2uint Function + %26 = OpLoad %19 %4 + %27 = OpLoad %21 %5 + %28 = OpSampledImage %23 %26 %27 + %29 = OpLoad %v2uint %25 + %30 = OpLoad %19 %6 + %31 = OpLoad %21 %5 + %32 = OpSampledImage %23 %30 %31 + %33 = OpImageBlockMatchSSDQCOM %v4float %28 %29 %32 %29 %29 + OpStore %3 %33 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Missing decoration")); +} + +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDNoDecorationB) { + std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 %4 %5 %6 + OpExecutionMode %2 OriginUpperLeft + OpDecorate %3 Location 0 + OpDecorate %4 DescriptorSet 0 + OpDecorate %4 Binding 1 + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 3 + OpDecorate %5 BlockMatchTextureQCOM + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 2 + %void = OpTypeVoid + %8 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_ptr_Input_float = OpTypePointer Input %float +%_ptr_Function_uint = OpTypePointer Function %uint +%uint_4 = OpConstant %uint 4 + %17 = OpConstantComposite %v2uint %uint_4 %uint_4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %3 = OpVariable %_ptr_Output_v4float Output + %19 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19 + %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %21 = OpTypeSampler +%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21 + %5 = OpVariable %_ptr_UniformConstant_21 UniformConstant + %23 = OpTypeSampledImage %19 + %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %2 = OpFunction %void None %8 + %24 = OpLabel + %25 = OpVariable %_ptr_Function_v2uint Function + %26 = OpLoad %19 %4 + %27 = OpLoad %21 %5 + %28 = OpSampledImage %23 %26 %27 + %29 = OpLoad %v2uint %25 + %30 = OpLoad %19 %6 + %31 = OpLoad %21 %5 + %32 = OpSampledImage %23 %30 %31 + %33 = OpImageBlockMatchSSDQCOM %v4float %28 %29 %32 %29 %29 + OpStore %3 %33 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Missing decoration")); +} + +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDNoDecorationC) { + std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 %4 %5 + OpExecutionMode %2 OriginUpperLeft + OpDecorate %3 Location 0 + OpDecorate %4 DescriptorSet 0 + OpDecorate %4 Binding 4 + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 5 + OpDecorate %5 BlockMatchTextureQCOM + %void = OpTypeVoid + %7 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Input_float = OpTypePointer Input %float +%_ptr_Function_uint = OpTypePointer Function %uint +%_ptr_Output_v4float = OpTypePointer Output %v4float + %3 = OpVariable %_ptr_Output_v4float Output + %18 = OpTypeImage %float 2D 0 0 0 1 Unknown + %19 = OpTypeSampledImage %18 +%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19 + %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %21 = OpTypeImage %float 2D 0 1 0 1 Unknown + %2 = OpFunction %void None %7 + %22 = OpLabel + %23 = OpVariable %_ptr_Function_v2uint Function + %24 = OpLoad %19 %4 + %25 = OpLoad %v2uint %23 + %26 = OpLoad %19 %5 + %27 = OpLoad %v2uint %23 + %28 = OpLoad %v2uint %23 + %29 = OpImageBlockMatchSSDQCOM %v4float %24 %25 %26 %27 %28 + OpStore %3 %29 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Missing decoration")); +} + +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDNoDecorationD) { + std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 %4 %5 + OpExecutionMode %2 OriginUpperLeft + OpDecorate %3 Location 0 + OpDecorate %4 DescriptorSet 0 + OpDecorate %4 Binding 4 + OpDecorate %4 BlockMatchTextureQCOM + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 5 + %void = OpTypeVoid + %7 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float +%_ptr_Input_float = OpTypePointer Input %float +%_ptr_Function_uint = OpTypePointer Function %uint +%_ptr_Output_v4float = OpTypePointer Output %v4float + %3 = OpVariable %_ptr_Output_v4float Output + %18 = OpTypeImage %float 2D 0 0 0 1 Unknown + %19 = OpTypeSampledImage %18 +%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19 + %4 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %5 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %21 = OpTypeImage %float 2D 0 1 0 1 Unknown + %2 = OpFunction %void None %7 + %22 = OpLabel + %23 = OpVariable %_ptr_Function_v2uint Function + %24 = OpLoad %19 %4 + %25 = OpLoad %v2uint %23 + %26 = OpLoad %19 %5 + %27 = OpLoad %v2uint %23 + %28 = OpLoad %v2uint %23 + %29 = OpImageBlockMatchSSDQCOM %v4float %24 %25 %26 %27 %28 + OpStore %3 %29 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Missing decoration")); +} + +TEST_F(ValidateImage, QCOMImageProcessingSampleWeightedNoDecorationA) { + std::string text = R"( + OpCapability Shader + OpCapability TextureSampleWeightedQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 %4 %5 %6 %7 + OpExecutionMode %2 OriginUpperLeft + OpDecorate %3 Location 0 + OpDecorate %4 DescriptorSet 0 + OpDecorate %4 Binding 1 + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 3 + OpDecorate %6 Location 0 + OpDecorate %7 DescriptorSet 0 + OpDecorate %7 Binding 0 + %void = OpTypeVoid + %9 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %3 = OpVariable %_ptr_Output_v4float Output + %13 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 + %4 = OpVariable %_ptr_UniformConstant_13 UniformConstant + %15 = OpTypeSampler +%_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15 + %5 = OpVariable %_ptr_UniformConstant_15 UniformConstant + %17 = OpTypeSampledImage %13 +%_ptr_Input_v4float = OpTypePointer Input %v4float + %6 = OpVariable %_ptr_Input_v4float Input + %v2float = OpTypeVector %float 2 + %20 = OpTypeImage %float 2D 0 1 0 1 Unknown +%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20 + %7 = OpVariable %_ptr_UniformConstant_20 UniformConstant + %22 = OpTypeSampledImage %20 +%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17 + %2 = OpFunction %void None %9 + %24 = OpLabel + %25 = OpLoad %13 %4 + %26 = OpLoad %15 %5 + %27 = OpSampledImage %17 %25 %26 + %28 = OpLoad %v4float %6 + %29 = OpVectorShuffle %v2float %28 %28 0 1 + %30 = OpLoad %20 %7 + %31 = OpLoad %15 %5 + %32 = OpSampledImage %22 %30 %31 + %33 = OpImageSampleWeightedQCOM %v4float %27 %29 %32 + OpStore %3 %33 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Missing decoration")); +} + +TEST_F(ValidateImage, QCOMImageProcessingSampleWeightedNoDecorationB) { + std::string text = R"( + OpCapability Shader + OpCapability TextureSampleWeightedQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 %4 %5 %6 + OpExecutionMode %2 OriginUpperLeft + OpDecorate %3 Location 0 + OpDecorate %4 Location 0 + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 4 + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 5 + %void = OpTypeVoid + %8 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %3 = OpVariable %_ptr_Output_v4float Output + %12 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12 + %14 = OpTypeSampler +%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14 + %16 = OpTypeSampledImage %12 +%_ptr_Input_v4float = OpTypePointer Input %v4float + %4 = OpVariable %_ptr_Input_v4float Input + %v2float = OpTypeVector %float 2 + %19 = OpTypeImage %float 2D 0 1 0 1 Unknown +%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19 + %21 = OpTypeSampledImage %19 +%_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16 + %5 = OpVariable %_ptr_UniformConstant_16 UniformConstant +%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21 + %6 = OpVariable %_ptr_UniformConstant_21 UniformConstant + %2 = OpFunction %void None %8 + %24 = OpLabel + %25 = OpLoad %16 %5 + %26 = OpLoad %v4float %4 + %27 = OpVectorShuffle %v2float %26 %26 0 1 + %28 = OpLoad %21 %6 + %29 = OpImageSampleWeightedQCOM %v4float %25 %27 %28 + OpStore %3 %29 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Missing decoration")); +} + +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADInvalidUseA) { + std::string text = R"( +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 11 +; Bound: 79 +; Schema: 0 + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %100 %101 %102 %103 %104 + OpExecutionMode %main OriginUpperLeft + OpDecorate %100 Location 0 + OpDecorate %101 Location 0 + OpDecorate %102 DescriptorSet 0 + OpDecorate %102 Binding 1 + OpDecorate %103 DescriptorSet 0 + OpDecorate %103 Binding 3 + OpDecorate %104 DescriptorSet 0 + OpDecorate %104 Binding 2 + OpDecorate %102 BlockMatchTextureQCOM + OpDecorate %104 BlockMatchTextureQCOM + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float + %100 = OpVariable %_ptr_Input_v4float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float + %101 = OpVariable %_ptr_Output_v4float Output + %42 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42 + %102 = OpVariable %_ptr_UniformConstant_42 UniformConstant + %46 = OpTypeSampler +%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46 + %103 = OpVariable %_ptr_UniformConstant_46 UniformConstant + %50 = OpTypeSampledImage %42 + %104 = OpVariable %_ptr_UniformConstant_42 UniformConstant + %v2float = OpTypeVector %float 2 + %main = OpFunction %void None %3 + %5 = OpLabel + %15 = OpVariable %_ptr_Function_v2uint Function + %45 = OpLoad %42 %102 + %49 = OpLoad %46 %103 + %51 = OpSampledImage %50 %45 %49 + %52 = OpLoad %v2uint %15 + %54 = OpLoad %42 %104 + %55 = OpLoad %46 %103 + %56 = OpSampledImage %50 %54 %55 + %57 = OpLoad %v2uint %15 + %58 = OpLoad %v2uint %15 + %59 = OpImageBlockMatchSADQCOM %v4float %51 %52 %56 %57 %58 + OpStore %101 %59 + %69 = OpLoad %42 %102 + %70 = OpLoad %46 %103 + %71 = OpSampledImage %50 %69 %70 + %73 = OpLoad %v4float %100 + %74 = OpVectorShuffle %v2float %73 %73 0 0 + %75 = OpImageSampleImplicitLod %v4float %71 %74 + OpStore %101 %75 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Illegal use of QCOM image processing decorated texture")); +} + +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADInvalidUseB) { + std::string text = R"( +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 11 +; Bound: 79 +; Schema: 0 + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %100 %101 %102 %103 %104 + OpExecutionMode %main OriginUpperLeft + OpDecorate %100 Location 0 + OpDecorate %101 Location 0 + OpDecorate %102 DescriptorSet 0 + OpDecorate %102 Binding 1 + OpDecorate %103 DescriptorSet 0 + OpDecorate %103 Binding 3 + OpDecorate %104 DescriptorSet 0 + OpDecorate %104 Binding 2 + OpDecorate %102 BlockMatchTextureQCOM + OpDecorate %104 BlockMatchTextureQCOM + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float + %100 = OpVariable %_ptr_Input_v4float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float + %101 = OpVariable %_ptr_Output_v4float Output + %42 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42 + %102 = OpVariable %_ptr_UniformConstant_42 UniformConstant + %46 = OpTypeSampler +%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46 + %103 = OpVariable %_ptr_UniformConstant_46 UniformConstant + %50 = OpTypeSampledImage %42 + %104 = OpVariable %_ptr_UniformConstant_42 UniformConstant + %v2float = OpTypeVector %float 2 + %main = OpFunction %void None %3 + %5 = OpLabel + %15 = OpVariable %_ptr_Function_v2uint Function + %45 = OpLoad %42 %102 + %49 = OpLoad %46 %103 + %51 = OpSampledImage %50 %45 %49 + %52 = OpLoad %v2uint %15 + %54 = OpLoad %42 %104 + %55 = OpLoad %46 %103 + %56 = OpSampledImage %50 %54 %55 + %57 = OpLoad %v2uint %15 + %58 = OpLoad %v2uint %15 + %59 = OpImageBlockMatchSADQCOM %v4float %51 %52 %56 %57 %58 + OpStore %101 %59 + %69 = OpLoad %42 %104 + %70 = OpLoad %46 %103 + %71 = OpSampledImage %50 %69 %70 + %73 = OpLoad %v4float %100 + %74 = OpVectorShuffle %v2float %73 %73 0 0 + %75 = OpImageSampleImplicitLod %v4float %71 %74 + OpStore %101 %75 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Illegal use of QCOM image processing decorated texture")); +} + +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADInvalidUseC) { + std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 %4 %5 %6 + OpExecutionMode %2 OriginUpperLeft + OpDecorate %3 Location 0 + OpDecorate %4 Location 0 + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 4 + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 5 + OpDecorate %5 BlockMatchTextureQCOM + OpDecorate %6 BlockMatchTextureQCOM + %void = OpTypeVoid + %8 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float + %3 = OpVariable %_ptr_Input_v4float Input + %uint_4 = OpConstant %uint 4 + %16 = OpConstantComposite %v2uint %uint_4 %uint_4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %4 = OpVariable %_ptr_Output_v4float Output + %18 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18 + %20 = OpTypeSampledImage %18 +%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20 + %5 = OpVariable %_ptr_UniformConstant_20 UniformConstant + %6 = OpVariable %_ptr_UniformConstant_20 UniformConstant + %v2float = OpTypeVector %float 2 + %23 = OpTypeImage %float 2D 0 1 0 1 Unknown + %2 = OpFunction %void None %8 + %24 = OpLabel + %25 = OpVariable %_ptr_Function_v2uint Function + OpStore %25 %16 + %26 = OpLoad %20 %5 + %27 = OpLoad %v2uint %25 + %28 = OpLoad %20 %6 + %29 = OpLoad %v2uint %25 + %30 = OpLoad %v2uint %25 + %31 = OpImageBlockMatchSADQCOM %v4float %26 %27 %28 %29 %30 + OpStore %4 %31 + %32 = OpLoad %20 %5 + %33 = OpLoad %v4float %3 + %34 = OpVectorShuffle %v2float %33 %33 0 2 + %35 = OpImageSampleImplicitLod %v4float %32 %34 + OpStore %4 %35 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Illegal use of QCOM image processing decorated texture")); +} + +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADInvalidUseD) { + std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 %4 %5 %6 + OpExecutionMode %2 OriginUpperLeft + OpDecorate %3 Location 0 + OpDecorate %4 Location 0 + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 4 + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 5 + OpDecorate %5 BlockMatchTextureQCOM + OpDecorate %6 BlockMatchTextureQCOM + %void = OpTypeVoid + %8 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float + %3 = OpVariable %_ptr_Input_v4float Input + %uint_4 = OpConstant %uint 4 + %16 = OpConstantComposite %v2uint %uint_4 %uint_4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %4 = OpVariable %_ptr_Output_v4float Output + %18 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18 + %20 = OpTypeSampledImage %18 +%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20 + %5 = OpVariable %_ptr_UniformConstant_20 UniformConstant + %6 = OpVariable %_ptr_UniformConstant_20 UniformConstant + %v2float = OpTypeVector %float 2 + %23 = OpTypeImage %float 2D 0 1 0 1 Unknown + %2 = OpFunction %void None %8 + %24 = OpLabel + %25 = OpVariable %_ptr_Function_v2uint Function + OpStore %25 %16 + %26 = OpLoad %20 %5 + %27 = OpLoad %v2uint %25 + %28 = OpLoad %20 %6 + %29 = OpLoad %v2uint %25 + %30 = OpLoad %v2uint %25 + %31 = OpImageBlockMatchSADQCOM %v4float %26 %27 %28 %29 %30 + OpStore %4 %31 + %32 = OpLoad %20 %6 + %33 = OpLoad %v4float %3 + %34 = OpVectorShuffle %v2float %33 %33 0 2 + %35 = OpImageSampleImplicitLod %v4float %32 %34 + OpStore %4 %35 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Illegal use of QCOM image processing decorated texture")); +} + +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDInvalidUseA) { + std::string text = R"( +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 11 +; Bound: 79 +; Schema: 0 + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %100 %101 %102 %103 %104 + OpExecutionMode %main OriginUpperLeft + OpDecorate %100 Location 0 + OpDecorate %101 Location 0 + OpDecorate %102 DescriptorSet 0 + OpDecorate %102 Binding 1 + OpDecorate %103 DescriptorSet 0 + OpDecorate %103 Binding 3 + OpDecorate %104 DescriptorSet 0 + OpDecorate %104 Binding 2 + OpDecorate %102 BlockMatchTextureQCOM + OpDecorate %104 BlockMatchTextureQCOM + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float + %100 = OpVariable %_ptr_Input_v4float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float + %101 = OpVariable %_ptr_Output_v4float Output + %42 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42 + %102 = OpVariable %_ptr_UniformConstant_42 UniformConstant + %46 = OpTypeSampler +%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46 + %103 = OpVariable %_ptr_UniformConstant_46 UniformConstant + %50 = OpTypeSampledImage %42 + %104 = OpVariable %_ptr_UniformConstant_42 UniformConstant + %v2float = OpTypeVector %float 2 + %main = OpFunction %void None %3 + %5 = OpLabel + %15 = OpVariable %_ptr_Function_v2uint Function + %45 = OpLoad %42 %102 + %49 = OpLoad %46 %103 + %51 = OpSampledImage %50 %45 %49 + %52 = OpLoad %v2uint %15 + %54 = OpLoad %42 %104 + %55 = OpLoad %46 %103 + %56 = OpSampledImage %50 %54 %55 + %57 = OpLoad %v2uint %15 + %58 = OpLoad %v2uint %15 + %59 = OpImageBlockMatchSSDQCOM %v4float %51 %52 %56 %57 %58 + OpStore %101 %59 + %69 = OpLoad %42 %102 + %70 = OpLoad %46 %103 + %71 = OpSampledImage %50 %69 %70 + %73 = OpLoad %v4float %100 + %74 = OpVectorShuffle %v2float %73 %73 0 0 + %75 = OpImageSampleImplicitLod %v4float %71 %74 + OpStore %101 %75 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Illegal use of QCOM image processing decorated texture")); +} + +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDInvalidUseB) { + std::string text = R"( +; SPIR-V +; Version: 1.0 +; Generator: Khronos Glslang Reference Front End; 11 +; Bound: 79 +; Schema: 0 + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %100 %101 %102 %103 %104 + OpExecutionMode %main OriginUpperLeft + OpDecorate %100 Location 0 + OpDecorate %101 Location 0 + OpDecorate %102 DescriptorSet 0 + OpDecorate %102 Binding 1 + OpDecorate %103 DescriptorSet 0 + OpDecorate %103 Binding 3 + OpDecorate %104 DescriptorSet 0 + OpDecorate %104 Binding 2 + OpDecorate %102 BlockMatchTextureQCOM + OpDecorate %104 BlockMatchTextureQCOM + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float + %100 = OpVariable %_ptr_Input_v4float Input +%_ptr_Output_v4float = OpTypePointer Output %v4float + %101 = OpVariable %_ptr_Output_v4float Output + %42 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42 + %102 = OpVariable %_ptr_UniformConstant_42 UniformConstant + %46 = OpTypeSampler +%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46 + %103 = OpVariable %_ptr_UniformConstant_46 UniformConstant + %50 = OpTypeSampledImage %42 + %104 = OpVariable %_ptr_UniformConstant_42 UniformConstant + %v2float = OpTypeVector %float 2 + %main = OpFunction %void None %3 + %5 = OpLabel + %15 = OpVariable %_ptr_Function_v2uint Function + %45 = OpLoad %42 %102 + %49 = OpLoad %46 %103 + %51 = OpSampledImage %50 %45 %49 + %52 = OpLoad %v2uint %15 + %54 = OpLoad %42 %104 + %55 = OpLoad %46 %103 + %56 = OpSampledImage %50 %54 %55 + %57 = OpLoad %v2uint %15 + %58 = OpLoad %v2uint %15 + %59 = OpImageBlockMatchSSDQCOM %v4float %51 %52 %56 %57 %58 + OpStore %101 %59 + %69 = OpLoad %42 %104 + %70 = OpLoad %46 %103 + %71 = OpSampledImage %50 %69 %70 + %73 = OpLoad %v4float %100 + %74 = OpVectorShuffle %v2float %73 %73 0 0 + %75 = OpImageSampleImplicitLod %v4float %71 %74 + OpStore %101 %75 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Illegal use of QCOM image processing decorated texture")); +} + +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDInvalidUseC) { + std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 %4 %5 %6 + OpExecutionMode %2 OriginUpperLeft + OpDecorate %3 Location 0 + OpDecorate %4 Location 0 + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 4 + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 5 + OpDecorate %5 BlockMatchTextureQCOM + OpDecorate %6 BlockMatchTextureQCOM + %void = OpTypeVoid + %8 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float + %3 = OpVariable %_ptr_Input_v4float Input + %uint_4 = OpConstant %uint 4 + %16 = OpConstantComposite %v2uint %uint_4 %uint_4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %4 = OpVariable %_ptr_Output_v4float Output + %18 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18 + %20 = OpTypeSampledImage %18 +%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20 + %5 = OpVariable %_ptr_UniformConstant_20 UniformConstant + %6 = OpVariable %_ptr_UniformConstant_20 UniformConstant + %v2float = OpTypeVector %float 2 + %23 = OpTypeImage %float 2D 0 1 0 1 Unknown + %2 = OpFunction %void None %8 + %24 = OpLabel + %25 = OpVariable %_ptr_Function_v2uint Function + OpStore %25 %16 + %26 = OpLoad %20 %5 + %27 = OpLoad %v2uint %25 + %28 = OpLoad %20 %6 + %29 = OpLoad %v2uint %25 + %30 = OpLoad %v2uint %25 + %31 = OpImageBlockMatchSSDQCOM %v4float %26 %27 %28 %29 %30 + OpStore %4 %31 + %32 = OpLoad %20 %5 + %33 = OpLoad %v4float %3 + %34 = OpVectorShuffle %v2float %33 %33 0 2 + %35 = OpImageSampleImplicitLod %v4float %32 %34 + OpStore %4 %35 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Illegal use of QCOM image processing decorated texture")); +} + +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDInvalidUseD) { + std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 %4 %5 %6 + OpExecutionMode %2 OriginUpperLeft + OpDecorate %3 Location 0 + OpDecorate %4 Location 0 + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 4 + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 5 + OpDecorate %5 BlockMatchTextureQCOM + OpDecorate %6 BlockMatchTextureQCOM + %void = OpTypeVoid + %8 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v2uint = OpTypeVector %uint 2 +%_ptr_Function_v2uint = OpTypePointer Function %v2uint + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Input_v4float = OpTypePointer Input %v4float + %3 = OpVariable %_ptr_Input_v4float Input + %uint_4 = OpConstant %uint 4 + %16 = OpConstantComposite %v2uint %uint_4 %uint_4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %4 = OpVariable %_ptr_Output_v4float Output + %18 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_18 = OpTypePointer UniformConstant %18 + %20 = OpTypeSampledImage %18 +%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20 + %5 = OpVariable %_ptr_UniformConstant_20 UniformConstant + %6 = OpVariable %_ptr_UniformConstant_20 UniformConstant + %v2float = OpTypeVector %float 2 + %23 = OpTypeImage %float 2D 0 1 0 1 Unknown + %2 = OpFunction %void None %8 + %24 = OpLabel + %25 = OpVariable %_ptr_Function_v2uint Function + OpStore %25 %16 + %26 = OpLoad %20 %5 + %27 = OpLoad %v2uint %25 + %28 = OpLoad %20 %6 + %29 = OpLoad %v2uint %25 + %30 = OpLoad %v2uint %25 + %31 = OpImageBlockMatchSSDQCOM %v4float %26 %27 %28 %29 %30 + OpStore %4 %31 + %32 = OpLoad %20 %6 + %33 = OpLoad %v4float %3 + %34 = OpVectorShuffle %v2float %33 %33 0 2 + %35 = OpImageSampleImplicitLod %v4float %32 %34 + OpStore %4 %35 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Illegal use of QCOM image processing decorated texture")); +} + +TEST_F(ValidateImage, QCOMImageProcessingSampleWeightedInvalidUseA) { + std::string text = R"( + OpCapability Shader + OpCapability TextureSampleWeightedQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 %4 %5 %6 + OpExecutionMode %2 OriginUpperLeft + OpDecorate %3 Location 0 + OpDecorate %4 Location 0 + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 4 + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 5 + OpDecorate %6 WeightTextureQCOM + %void = OpTypeVoid + %8 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %3 = OpVariable %_ptr_Output_v4float Output + %12 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12 + %14 = OpTypeSampledImage %12 +%_ptr_Input_v4float = OpTypePointer Input %v4float + %4 = OpVariable %_ptr_Input_v4float Input + %v2float = OpTypeVector %float 2 + %17 = OpTypeImage %float 2D 0 1 0 1 Unknown +%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17 + %19 = OpTypeSampledImage %17 +%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14 + %5 = OpVariable %_ptr_UniformConstant_14 UniformConstant +%_ptr_UniformConstant_19 = OpTypePointer UniformConstant %19 + %6 = OpVariable %_ptr_UniformConstant_19 UniformConstant + %v3float = OpTypeVector %float 3 + %2 = OpFunction %void None %8 + %23 = OpLabel + %24 = OpLoad %v4float %4 + %25 = OpVectorShuffle %v2float %24 %24 0 1 + %26 = OpLoad %14 %5 + %27 = OpLoad %v4float %4 + %28 = OpVectorShuffle %v2float %27 %27 0 1 + %29 = OpLoad %19 %6 + %30 = OpImageSampleWeightedQCOM %v4float %26 %28 %29 + OpStore %3 %30 + %31 = OpLoad %19 %6 + %32 = OpLoad %v4float %4 + %33 = OpVectorShuffle %v3float %32 %32 0 1 0 + %34 = OpCompositeExtract %float %33 0 + %35 = OpCompositeExtract %float %33 1 + %36 = OpCompositeExtract %float %33 2 + %37 = OpCompositeConstruct %v3float %34 %35 %36 + %38 = OpImageSampleImplicitLod %v4float %31 %37 + OpStore %3 %38 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Illegal use of QCOM image processing decorated texture")); +} + +TEST_F(ValidateImage, QCOMImageProcessingSampleWeightedInvalidUseB) { + std::string text = R"( + OpCapability Shader + OpCapability TextureSampleWeightedQCOM + OpExtension "SPV_QCOM_image_processing" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" %3 %4 %5 %6 %7 + OpExecutionMode %2 OriginUpperLeft + OpDecorate %3 Location 0 + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 1 + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 3 + OpDecorate %4 Location 0 + OpDecorate %7 DescriptorSet 0 + OpDecorate %7 Binding 0 + OpDecorate %7 WeightTextureQCOM + %void = OpTypeVoid + %9 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %3 = OpVariable %_ptr_Output_v4float Output + %13 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 + %5 = OpVariable %_ptr_UniformConstant_13 UniformConstant + %15 = OpTypeSampler +%_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15 + %6 = OpVariable %_ptr_UniformConstant_15 UniformConstant + %17 = OpTypeSampledImage %13 +%_ptr_Input_v4float = OpTypePointer Input %v4float + %4 = OpVariable %_ptr_Input_v4float Input + %v2float = OpTypeVector %float 2 + %20 = OpTypeImage %float 2D 0 1 0 1 Unknown +%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20 + %7 = OpVariable %_ptr_UniformConstant_20 UniformConstant + %22 = OpTypeSampledImage %20 + %v3float = OpTypeVector %float 3 + %2 = OpFunction %void None %9 + %24 = OpLabel + %25 = OpLoad %13 %5 + %26 = OpLoad %15 %6 + %27 = OpSampledImage %17 %25 %26 + %28 = OpLoad %v4float %4 + %29 = OpVectorShuffle %v2float %28 %28 0 1 + %30 = OpLoad %20 %7 + %31 = OpLoad %15 %6 + %32 = OpSampledImage %22 %30 %31 + %33 = OpImageSampleWeightedQCOM %v4float %27 %29 %32 + OpStore %3 %33 + %34 = OpLoad %20 %7 + %35 = OpLoad %15 %6 + %36 = OpSampledImage %22 %34 %35 + %37 = OpLoad %v4float %4 + %38 = OpVectorShuffle %v3float %37 %37 0 1 0 + %39 = OpCompositeExtract %float %38 0 + %40 = OpCompositeExtract %float %38 1 + %41 = OpCompositeExtract %float %38 2 + %42 = OpCompositeConstruct %v3float %39 %40 %41 + %43 = OpImageSampleImplicitLod %v4float %36 %42 + OpStore %3 %43 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Illegal use of QCOM image processing decorated texture")); +} + +TEST_F(ValidateImage, ImageMSArray_ArrayedSampledTypeRequiresCapability) { + const std::string code = R"( + OpCapability Shader + OpCapability StorageImageMultisample + OpCapability StorageImageReadWithoutFormat + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpDecorate %var_image DescriptorSet 0 + OpDecorate %var_image Binding 1 + %void = OpTypeVoid + %func = OpTypeFunction %void + %f32 = OpTypeFloat 32 + %u32 = OpTypeInt 32 0 + %uint_2 = OpConstant %u32 2 + %uint_1 = OpConstant %u32 1 + %v2uint = OpTypeVector %u32 2 + %v4float = OpTypeVector %f32 4 + %image = OpTypeImage %f32 2D 2 1 1 2 Unknown +%ptr_image = OpTypePointer UniformConstant %image + %10 = OpConstantComposite %v2uint %uint_1 %uint_2 +%var_image = OpVariable %ptr_image UniformConstant + %main = OpFunction %void None %func + %main_lab = OpLabel + %18 = OpLoad %image %var_image + %19 = OpImageRead %v4float %18 %10 Sample %uint_2 + OpReturn + OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Capability ImageMSArray is required to access storage image")); +} + +TEST_F(ValidateImage, ImageMSArray_SampledTypeDoesNotRequireCapability) { + const std::string code = R"( + OpCapability Shader + OpCapability StorageImageMultisample + OpCapability StorageImageReadWithoutFormat + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpDecorate %var_image DescriptorSet 0 + OpDecorate %var_image Binding 1 + %void = OpTypeVoid + %func = OpTypeFunction %void + %f32 = OpTypeFloat 32 + %u32 = OpTypeInt 32 0 + %uint_2 = OpConstant %u32 2 + %uint_1 = OpConstant %u32 1 + %v2uint = OpTypeVector %u32 2 + %v4float = OpTypeVector %f32 4 + %image = OpTypeImage %f32 2D 2 0 1 2 Unknown +%ptr_image = OpTypePointer UniformConstant %image + %10 = OpConstantComposite %v2uint %uint_1 %uint_2 +%var_image = OpVariable %ptr_image UniformConstant + %main = OpFunction %void None %func + %main_lab = OpLabel + %18 = OpLoad %image %var_image + %19 = OpImageRead %v4float %18 %10 Sample %uint_2 + OpReturn + OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateImage, ImageMSArray_ArrayedTypeDoesNotRequireCapability) { + const std::string code = R"( + OpCapability Shader + OpCapability StorageImageReadWithoutFormat + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpDecorate %var_image DescriptorSet 0 + OpDecorate %var_image Binding 1 + %void = OpTypeVoid + %func = OpTypeFunction %void + %f32 = OpTypeFloat 32 + %u32 = OpTypeInt 32 0 + %uint_3 = OpConstant %u32 3 + %uint_2 = OpConstant %u32 2 + %uint_1 = OpConstant %u32 1 + %v3uint = OpTypeVector %u32 3 + %v4float = OpTypeVector %f32 4 + %image = OpTypeImage %f32 2D 2 1 0 2 Unknown +%ptr_image = OpTypePointer UniformConstant %image + %10 = OpConstantComposite %v3uint %uint_1 %uint_2 %uint_3 +%var_image = OpVariable %ptr_image UniformConstant + %main = OpFunction %void None %func + %main_lab = OpLabel + %18 = OpLoad %image %var_image + %19 = OpImageRead %v4float %18 %10 + OpReturn + OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(env)); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/tools/fuzz/fuzz.cpp b/tools/fuzz/fuzz.cpp index ca6633a6ce..5f2a0080d4 100644 --- a/tools/fuzz/fuzz.cpp +++ b/tools/fuzz/fuzz.cpp @@ -41,12 +41,6 @@ namespace { enum class FuzzingTarget { kSpirv, kWgsl }; -// Check that the std::system function can actually be used. -bool CheckExecuteCommand() { - int res = std::system(nullptr); - return res != 0; -} - // Execute a command using the shell. // Returns true if and only if the command's exit status was 0. bool ExecuteCommand(const std::string& command) { @@ -770,11 +764,6 @@ int main(int argc, const char** argv) { } break; case FuzzActions::SHRINK: { - if (!CheckExecuteCommand()) { - std::cerr << "could not find shell interpreter for executing a command" - << std::endl; - return 1; - } if (!Shrink(target_env, fuzzer_options, validator_options, binary_in, initial_facts, shrink_transformations_file, shrink_temp_file_prefix, interestingness_test, &binary_out, diff --git a/tools/io.h b/tools/io.h index 8bbee3a0df..a48e3c325e 100644 --- a/tools/io.h +++ b/tools/io.h @@ -144,6 +144,7 @@ class OutputFile { ~OutputFile() { if (fp_ == stdout) { + fflush(stdout); SET_STDOUT_MODE(old_mode_); } else if (fp_ != nullptr) { fclose(fp_); diff --git a/tools/link/linker.cpp b/tools/link/linker.cpp index 381d8b9b51..f3898aab0d 100644 --- a/tools/link/linker.cpp +++ b/tools/link/linker.cpp @@ -59,6 +59,13 @@ Options (in lexicographical order): NOTE: The SPIR-V version used by the linked binary module depends only on the version of the inputs, and is not affected by this option. + --use-highest-version + Upgrade the output SPIR-V version to the highest of the input + files, instead of requiring all of them to have the same + version. + NOTE: If one of the older input files uses an instruction that + is deprecated in the highest SPIR-V version, the output will + be invalid. --verify-ids Verify that IDs in the resulting modules are truly unique. --version @@ -78,6 +85,7 @@ FLAG_LONG_bool( create_library, /* default_value= */ false, FLAG_LONG_bool( allow_partial_linkage, /* default_value= */ false, /* required= */ false); FLAG_SHORT_string(o, /* default_value= */ "", /* required= */ false); FLAG_LONG_string( target_env, /* default_value= */ kDefaultEnvironment, /* required= */ false); +FLAG_LONG_bool( use_highest_version, /* default_value= */ false, /* required= */ false); // clang-format on int main(int, const char* argv[]) { @@ -120,6 +128,7 @@ int main(int, const char* argv[]) { options.SetAllowPartialLinkage(flags::allow_partial_linkage.value()); options.SetCreateLibrary(flags::create_library.value()); options.SetVerifyIds(flags::verify_ids.value()); + options.SetUseHighestVersion(flags::use_highest_version.value()); if (inFiles.empty()) { fprintf(stderr, "error: No input file specified\n"); diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index ce2103ca8a..3dfa021fdd 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -496,6 +496,10 @@ Options (in lexicographical order):)", covers reflection information defined by SPV_GOOGLE_hlsl_functionality1 and SPV_KHR_non_semantic_info)"); printf(R"( + --switch-descriptorset=: + Switch any DescriptoSet decorations using the value to + the new value .)"); + printf(R"( --target-env= Set the target environment. Without this flag the target environment defaults to spv1.5. must be one of diff --git a/tools/reduce/reduce.cpp b/tools/reduce/reduce.cpp index 37600543a8..959f5a2f27 100644 --- a/tools/reduce/reduce.cpp +++ b/tools/reduce/reduce.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -29,12 +30,6 @@ namespace { -// Check that the std::system function can actually be used. -bool CheckExecuteCommand() { - int res = std::system(nullptr); - return res != 0; -} - // Execute a command using the shell. // Returns true if and only if the command's exit status was 0. bool ExecuteCommand(const std::string& command) { @@ -282,12 +277,6 @@ int main(int argc, const char** argv) { return status.code; } - if (!CheckExecuteCommand()) { - std::cerr << "could not find shell interpreter for executing a command" - << std::endl; - return 2; - } - spvtools::reduce::Reducer reducer(target_env); std::stringstream joined; diff --git a/tools/sva/yarn.lock b/tools/sva/yarn.lock index 1f5624e1fd..eed94ced15 100644 --- a/tools/sva/yarn.lock +++ b/tools/sva/yarn.lock @@ -651,9 +651,9 @@ get-caller-file@^2.0.5: integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== get-stream@^6.0.0: version "6.0.1" diff --git a/utils/update_build_version.py b/utils/update_build_version.py index 5a78ada261..f3d05b5d31 100755 --- a/utils/update_build_version.py +++ b/utils/update_build_version.py @@ -62,9 +62,7 @@ def mkdir_p(directory): def command_output(cmd, directory): """Runs a command in a directory and returns its standard output stream. - Captures the standard error stream. - - Raises a RuntimeError if the command fails to launch or otherwise fails. + Returns (False, None) if the command fails to launch or otherwise fails. """ try: # Set shell=True on Windows so that Chromium's git.bat can be found when @@ -74,11 +72,10 @@ def command_output(cmd, directory): stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=os.name == 'nt') - (stdout, stderr) = p.communicate() + (stdout, _) = p.communicate() if p.returncode != 0: - logging.error('Failed to run "{}" in "{}": {}'.format(cmd, directory, stderr.decode())) + return False, None except Exception as e: - logging.error('Failed to run "{}" in "{}": {}'.format(cmd, directory, str(e))) return False, None return p.returncode == 0, stdout @@ -111,26 +108,30 @@ def describe(repo_path): Runs 'git describe', or alternately 'git rev-parse HEAD', in directory. If successful, returns the output; otherwise returns 'unknown hash, '.""" - success, output = command_output(['git', 'describe'], repo_path) - if not success: - output = command_output(['git', 'rev-parse', 'HEAD'], repo_path) - + # if we're in a git repository, attempt to extract version info + success, output = command_output(["git", "rev-parse", "--show-toplevel"], repo_path) if success: - # decode() is needed here for Python3 compatibility. In Python2, - # str and bytes are the same type, but not in Python3. - # Popen.communicate() returns a bytes instance, which needs to be - # decoded into text data first in Python3. And this decode() won't - # hurt Python2. - return output.rstrip().decode() + success, output = command_output(["git", "describe", "--tags", "--match=v*", "--long"], repo_path) + if not success: + success, output = command_output(["git", "rev-parse", "HEAD"], repo_path) + + if success: + # decode() is needed here for Python3 compatibility. In Python2, + # str and bytes are the same type, but not in Python3. + # Popen.communicate() returns a bytes instance, which needs to be + # decoded into text data first in Python3. And this decode() won't + # hurt Python2. + return output.rstrip().decode() # This is the fallback case where git gives us no information, - # e.g. because the source tree might not be in a git tree. + # e.g. because the source tree might not be in a git tree or + # git is not available on the system. # In this case, usually use a timestamp. However, to ensure # reproducible builds, allow the builder to override the wall # clock time with environment variable SOURCE_DATE_EPOCH # containing a (presumably) fixed timestamp. timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) - iso_date = datetime.datetime.utcfromtimestamp(timestamp).isoformat() + iso_date = datetime.datetime.fromtimestamp(timestamp, datetime.timezone.utc).isoformat() return "unknown hash, {}".format(iso_date) def main():