From 727f4346db0ba7356ccf87a2716d96ffd9b18b44 Mon Sep 17 00:00:00 2001 From: Sven van Haastregt Date: Tue, 8 Aug 2023 16:53:33 +0100 Subject: [PATCH 01/95] docs: update references to `main` branch (#5363) The default branch was renamed from `master` to `main`. Update some stale references. Signed-off-by: Sven van Haastregt --- CONTRIBUTING.md | 8 ++++---- docs/downloads.md | 2 +- docs/projects.md | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) 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/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. From 13892fe8671ea6dd44c98bcee2980e204b42b0b1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 8 Aug 2023 16:26:59 +0000 Subject: [PATCH 02/95] Roll external/googletest/ 6f6ab4212..e7fd109b5 (2 commits) (#5356) * Roll external/googletest/ 6f6ab4212..46db91ef6 (9 commits) https://github.com/google/googletest/compare/6f6ab4212aa0...46db91ef6ffc $ git log 6f6ab4212..46db91ef6 --date=short --no-merges --format='%ad %ae %s' 2023-08-07 dinor Make references to `#include`s consistent across docs 2023-08-02 robert.shade Avoid unreachable code warning 2023-08-02 dmauro Update documentation to refer to v1.14 2023-08-02 dmauro Bump version to v1.14 in preparation for release 2023-08-02 dmauro Remove the GTEST_HAS_DOWNCAST_ customization point. 2023-08-02 dmauro Add googletest-message-test to the Bazel tests It appears to have been unintentionally left out 2023-08-01 phoebeliang Make testing::Message support streamed AbslStringify values 2023-08-01 dmauro Update GoogleTest dependencies 2023-07-27 patryk gtest: Supress warning about set unused variable Created with: roll-dep external/googletest * Roll external/re2/ 960c86176..9dc7ae7b5 (1 commit) https://github.com/google/re2/compare/960c861764ff...9dc7ae7b52a1 $ git log 960c86176..9dc7ae7b5 --date=short --no-merges --format='%ad %ae %s' 2023-08-04 junyer Minor Bazel cleanups. Created with: roll-dep external/re2 --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 1d9f0ba1bd..4d507971a2 100644 --- a/DEPS +++ b/DEPS @@ -7,12 +7,12 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '6f6ab4212aa02cfe02e480711246da4fc17b0761', + 'googletest_revision': '46db91ef6ffcc128b2d5f31118ae1108109e3400', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '960c861764ff54c9a12ff683ba55ccaad1a8f73b', + 're2_revision': '9dc7ae7b52a17b75e3f9249ea85ba578bf42f255', 'spirv_headers_revision': '124a9665e464ef98b8b718d572d5f329311061eb', } From 60e684fe7187e103674caa511aad33bf42ff8dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Wed, 9 Aug 2023 12:30:23 +0200 Subject: [PATCH 03/95] opt: fix StorageInputOutput16 trimming. (#5359) * opt: fix StorageInputOutput16 trimming. While integrating this pass into DXC, I found a lot of missing cases. This PR fixes a few issues centered around this capability while laying out fondations for more fixes. 1. The grammar can define extensions in operand & opcode tables. - opcode can rely on common capabilities, but require a new extension. - opcode can also rely on a capability which requires an extension. Sometimes, the extension is listed twice, in the opcode, and capability. But this redundancy is not guaranteed. 2. minVersion check. The condition was flipped: we added the extension when the minVersion was less than current. Didn't noticed the issue as I only tests on the default env. 3. Capability/Extension instructions were not ignored. - `OpCapability Foo` will require the `Foo` capability. - it doesn't mean the module requires the `Foo` capability. Same for extensions. This commit adds disabled tests, for fixes which are too large to be brought into this already large PR. --- source/opt/trim_capabilities_pass.cpp | 222 ++++--- source/opt/trim_capabilities_pass.h | 47 +- test/opt/trim_capabilities_pass_test.cpp | 740 +++++++++++++++++++++-- 3 files changed, 875 insertions(+), 134 deletions(-) diff --git a/source/opt/trim_capabilities_pass.cpp b/source/opt/trim_capabilities_pass.cpp index 1a7633d65c..b32b902e1b 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,53 +36,28 @@ namespace spvtools { namespace opt { namespace { -constexpr uint32_t kVariableStorageClassIndex = 0; +constexpr uint32_t kOpTypePointerStorageClassIndex = 0; constexpr uint32_t kTypeArrayTypeIndex = 0; constexpr uint32_t kOpTypeScalarBitWidthIndex = 0; constexpr uint32_t kTypePointerTypeIdInIdx = 1; -} // namespace - -// ============== Begin opcode handler implementations. ======================= -// -// Adding support for a new capability should only require adding a new handler, -// and updating the -// kSupportedCapabilities/kUntouchableCapabilities/kFordiddenCapabilities lists. -// -// Handler names follow the following convention: -// Handler__() - -static std::optional Handler_OpVariable_StorageInputOutput16( - const Instruction* instruction) { - assert(instruction->opcode() == spv::Op::OpVariable && - "This handler only support OpVariable opcodes."); - - // This capability is only required if the variable as an Input/Output storage - // class. - spv::StorageClass storage_class = spv::StorageClass( - instruction->GetSingleWordInOperand(kVariableStorageClassIndex)); - 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)) { - return std::nullopt; - } - // We need to walk the type definition. - std::queue instructions_to_visit; - instructions_to_visit.push(instruction->type_id()); +// 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.front()); + 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(kTypePointerTypeIdInIdx)); @@ -102,23 +79,83 @@ static std::optional Handler_OpVariable_StorageInputOutput16( }); continue; } + } +} - if (item->opcode() != spv::Op::OpTypeInt && - item->opcode() != spv::Op::OpTypeFloat) { - 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; } - if (item->GetSingleWordInOperand(kOpTypeScalarBitWidthIndex) == 16) { - return spv::Capability::StorageInputOutput16; - } + 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. ======================= +// +// Adding support for a new capability should only require adding a new handler, +// and updating the +// kSupportedCapabilities/kUntouchableCapabilities/kFordiddenCapabilities lists. +// +// Handler names follow the following convention: +// Handler__() + +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(kOpTypePointerStorageClassIndex)); + if (storage_class != spv::StorageClass::Input && + storage_class != spv::StorageClass::Output) { + return std::nullopt; + } + + if (!Has16BitCapability(instruction->context()->get_feature_mgr())) { + return std::nullopt; } - return std::nullopt; + return AnyTypeOf(instruction, is16bitType) + ? std::optional(spv::Capability::StorageInputOutput16) + : std::nullopt; } // Opcode of interest to determine capabilities requirements. constexpr std::array, 1> kOpcodeHandlers{{ - {spv::Op::OpVariable, Handler_OpVariable_StorageInputOutput16}, + // clang-format off + {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageInputOutput16}, + // clang-format on }}; // ============== End opcode handler implementations. ======================= @@ -159,8 +196,9 @@ TrimCapabilitiesPass::TrimCapabilitiesPass() void TrimCapabilitiesPass::addInstructionRequirements( Instruction* instruction, CapabilitySet* capabilities, ExtensionSet* extensions) const { - // Ignoring OpCapability instructions. - if (instruction->opcode() == spv::Op::OpCapability) { + // Ignoring OpCapability and OpExtension instructions. + if (instruction->opcode() == spv::Op::OpCapability || + instruction->opcode() == spv::Op::OpExtension) { return; } @@ -170,13 +208,8 @@ void TrimCapabilitiesPass::addInstructionRequirements( 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); - } + addSupportedCapabilitiesToSet(desc, capabilities); + addSupportedExtensionsToSet(desc, extensions); } } @@ -190,7 +223,9 @@ void TrimCapabilitiesPass::addInstructionRequirements( } // No supported capability relies on a literal string operand. - if (operand.type == SPV_OPERAND_TYPE_LITERAL_STRING) { + if (operand.type == SPV_OPERAND_TYPE_LITERAL_STRING || + operand.type == SPV_OPERAND_TYPE_ID || + operand.type == SPV_OPERAND_TYPE_RESULT_ID) { continue; } @@ -201,12 +236,8 @@ void TrimCapabilitiesPass::addInstructionRequirements( continue; } - addSupportedCapabilitiesToSet(desc->numCapabilities, desc->capabilities, - capabilities); - if (desc->minVersion <= spvVersionForTargetEnv(context()->GetTargetEnv())) { - extensions->insert(desc->extensions, - desc->extensions + desc->numExtensions); - } + addSupportedCapabilitiesToSet(desc, capabilities); + addSupportedExtensionsToSet(desc, extensions); } // Last case: some complex logic needs to be run to determine capabilities. @@ -214,10 +245,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 +274,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 +304,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 +336,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 +349,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..fbcf151c23 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 { @@ -99,25 +100,48 @@ 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); + } + + // 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 +158,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/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index 83a8943645..53b4a06936 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -404,7 +404,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 +439,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 +474,161 @@ 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); +} + +// FIXME(Keenuts): Add support for bitmask operands. +TEST_F(TrimCapabilitiesPassTest, + DISABLED_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 +636,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 +748,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,139 +807,589 @@ 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 -; CHECK-NOT: OpCapability StorageInputOutput16 OpExtension "SPV_KHR_16bit_storage" +; CHECK: 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 + %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, - StorageInputOutput16RemainsWithOutputVariable) { + StorageInputOutput16_IsRemovedWithoutInputPointer) { const std::string kTest = R"( OpCapability Shader OpCapability Float16 OpCapability StorageInputOutput16 -; CHECK: 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 + %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, + StorageInputOutput16_RemainsWithOutputPointer_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" %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 + OpExtension "SPV_KHR_16bit_storage" ; CHECK-NOT: OpCapability StorageInputOutput16 +; CHECK-NOT: OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "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, + DISABLED_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, + DISABLED_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, + DISABLED_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, + DISABLED_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, + DISABLED_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, + DISABLED_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, + DISABLED_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, + DISABLED_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" %input_var - OpDecorate %input_var BuiltIn LocalInvocationIndex + 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, + DISABLED_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, + DISABLED_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); From 3af4244ae1ea6c55d289ad06d30a731277b9596d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 9 Aug 2023 14:30:42 +0000 Subject: [PATCH 04/95] Roll external/googletest/ 46db91ef6..89b25572d (1 commit) (#5365) https://github.com/google/googletest/compare/46db91ef6ffc...89b25572dbd7 $ git log 46db91ef6..89b25572d --date=short --no-merges --format='%ad %ae %s' 2023-08-03 elliotgoodrich Remove public includes of `` Created with: roll-dep external/googletest Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 4d507971a2..953893a079 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '46db91ef6ffcc128b2d5f31118ae1108109e3400', + 'googletest_revision': '89b25572dbd7668499d2cfd01dea905f8c44e019', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From ebda56e3522c1691122cd875ec2fc0bd0a897afe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 10 Aug 2023 14:34:46 +0200 Subject: [PATCH 05/95] opt: add StoragePushConstant16 to trim pass (#5366) * opt: add StoragePushConstant16 to trim pass * fix comment --- source/opt/trim_capabilities_pass.cpp | 25 +++++++++++++++++++++++- source/opt/trim_capabilities_pass.h | 3 ++- test/opt/trim_capabilities_pass_test.cpp | 7 +++---- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/source/opt/trim_capabilities_pass.cpp b/source/opt/trim_capabilities_pass.cpp index b32b902e1b..588a25eecd 100644 --- a/source/opt/trim_capabilities_pass.cpp +++ b/source/opt/trim_capabilities_pass.cpp @@ -151,10 +151,33 @@ Handler_OpTypePointer_StorageInputOutput16(const Instruction* instruction) { : std::nullopt; } +static std::optional +Handler_OpTypePointer_StoragePushConstant16(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 PushConstant storage + // class. + spv::StorageClass storage_class = spv::StorageClass( + instruction->GetSingleWordInOperand(kOpTypePointerStorageClassIndex)); + if (storage_class != spv::StorageClass::PushConstant) { + return std::nullopt; + } + + if (!Has16BitCapability(instruction->context()->get_feature_mgr())) { + return std::nullopt; + } + + return AnyTypeOf(instruction, is16bitType) + ? std::optional(spv::Capability::StoragePushConstant16) + : std::nullopt; +} + // Opcode of interest to determine capabilities requirements. -constexpr std::array, 1> kOpcodeHandlers{{ +constexpr std::array, 2> kOpcodeHandlers{{ // clang-format off {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageInputOutput16}, + {spv::Op::OpTypePointer, Handler_OpTypePointer_StoragePushConstant16}, // clang-format on }}; diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index fbcf151c23..a8666a70c6 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -79,7 +79,8 @@ class TrimCapabilitiesPass : public Pass { spv::Capability::MinLod, spv::Capability::Shader, spv::Capability::ShaderClockKHR, - spv::Capability::StorageInputOutput16 + spv::Capability::StorageInputOutput16, + spv::Capability::StoragePushConstant16 // clang-format on }; diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index 53b4a06936..9928c474a7 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -1058,7 +1058,7 @@ TEST_F(TrimCapabilitiesPassTest, } TEST_F(TrimCapabilitiesPassTest, - DISABLED_StoragePushConstant16_RemainsSimplePointer_Vulkan1_0) { + StoragePushConstant16_RemainsSimplePointer_Vulkan1_0) { const std::string kTest = R"( OpCapability Shader OpCapability Float16 @@ -1084,7 +1084,7 @@ TEST_F(TrimCapabilitiesPassTest, } TEST_F(TrimCapabilitiesPassTest, - DISABLED_StoragePushConstant16_RemainsSimplePointer_Vulkan1_1) { + StoragePushConstant16_RemainsSimplePointer_Vulkan1_1) { const std::string kTest = R"( OpCapability Shader OpCapability Float16 @@ -1109,8 +1109,7 @@ TEST_F(TrimCapabilitiesPassTest, EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); } -TEST_F(TrimCapabilitiesPassTest, - DISABLED_StoragePushConstant16_RemovedSimplePointer) { +TEST_F(TrimCapabilitiesPassTest, StoragePushConstant16_RemovedSimplePointer) { const std::string kTest = R"( OpCapability Shader OpCapability Float16 From 4788ff1578917d7b685f98913eaf634231dc3bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 10 Aug 2023 16:21:35 +0200 Subject: [PATCH 06/95] opt: add StorageUniformBufferBlock16 to trim pass (#5367) Add StorageUniformBufferBlock16 to the list of enabled capabilities. --- source/opt/decoration_manager.cpp | 11 +++++-- source/opt/decoration_manager.h | 7 +++-- source/opt/trim_capabilities_pass.cpp | 37 +++++++++++++++++++++++- source/opt/trim_capabilities_pass.h | 3 +- test/opt/trim_capabilities_pass_test.cpp | 6 ++-- 5 files changed, 53 insertions(+), 11 deletions(-) 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..08cb2f3448 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 diff --git a/source/opt/trim_capabilities_pass.cpp b/source/opt/trim_capabilities_pass.cpp index 588a25eecd..84a848f4c8 100644 --- a/source/opt/trim_capabilities_pass.cpp +++ b/source/opt/trim_capabilities_pass.cpp @@ -173,11 +173,46 @@ Handler_OpTypePointer_StoragePushConstant16(const Instruction* instruction) { : 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); + }); + + return matchesCondition + ? std::optional(spv::Capability::StorageUniformBufferBlock16) + : std::nullopt; +} + // Opcode of interest to determine capabilities requirements. -constexpr std::array, 2> kOpcodeHandlers{{ +constexpr std::array, 3> kOpcodeHandlers{{ // clang-format off {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageInputOutput16}, {spv::Op::OpTypePointer, Handler_OpTypePointer_StoragePushConstant16}, + {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniformBufferBlock16}, // clang-format on }}; diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index a8666a70c6..8a92658579 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -80,7 +80,8 @@ class TrimCapabilitiesPass : public Pass { spv::Capability::Shader, spv::Capability::ShaderClockKHR, spv::Capability::StorageInputOutput16, - spv::Capability::StoragePushConstant16 + spv::Capability::StoragePushConstant16, + spv::Capability::StorageUniformBufferBlock16 // clang-format on }; diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index 9928c474a7..390146b5f9 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -1134,7 +1134,7 @@ TEST_F(TrimCapabilitiesPassTest, StoragePushConstant16_RemovedSimplePointer) { } TEST_F(TrimCapabilitiesPassTest, - DISABLED_StorageUniformBufferBlock16_RemainsSimplePointer_Vulkan1_0) { + StorageUniformBufferBlock16_RemainsSimplePointer_Vulkan1_0) { // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354 static_assert(spv::Capability::StorageUniformBufferBlock16 == spv::Capability::StorageBuffer16BitAccess); @@ -1169,7 +1169,7 @@ TEST_F(TrimCapabilitiesPassTest, } TEST_F(TrimCapabilitiesPassTest, - DISABLED_StorageUniformBufferBlock16_RemainsSimplePointer_Vulkan1_1) { + StorageUniformBufferBlock16_RemainsSimplePointer_Vulkan1_1) { // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354 static_assert(spv::Capability::StorageUniformBufferBlock16 == spv::Capability::StorageBuffer16BitAccess); @@ -1204,7 +1204,7 @@ TEST_F(TrimCapabilitiesPassTest, } TEST_F(TrimCapabilitiesPassTest, - DISABLED_StorageUniformBufferBlock16_RemovedSimplePointer) { + StorageUniformBufferBlock16_RemovedSimplePointer) { // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354 static_assert(spv::Capability::StorageUniformBufferBlock16 == spv::Capability::StorageBuffer16BitAccess); From 8e3da01b45806fbacbb9e6fce9c5f9ae49f60e42 Mon Sep 17 00:00:00 2001 From: David Neto Date: Thu, 10 Aug 2023 12:19:12 -0400 Subject: [PATCH 07/95] Move token version/cap/ext checks from parsing to validation (#5370) A token is allowed to parse even when it's from the wrong version, or is not enabled by a capability or extension. This allows more modules to parse. Version/capability/extension checking is fully moved to validation instead. Fixes: #5364 --- source/assembly_grammar.cpp | 16 +++++---- source/operand.cpp | 52 ++++++------------------------ test/operand_capabilities_test.cpp | 40 +++++++++++++++++++++-- test/val/val_image_test.cpp | 20 +++++++----- 4 files changed, 70 insertions(+), 58 deletions(-) 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/operand.cpp b/source/operand.cpp index c2e5a99da7..3121eed9f1 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; - } + // 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; } } diff --git a/test/operand_capabilities_test.cpp b/test/operand_capabilities_test.cpp index 01b98a63ef..607d3510df 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); } @@ -417,7 +446,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 +498,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/val/val_image_test.cpp b/test/val/val_image_test.cpp index 9aceaf5774..54a9fb6be9 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) { From 8714d7fad25c3af92f85f465b808740cfca6e85a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 10 Aug 2023 19:54:31 +0200 Subject: [PATCH 08/95] enable StorageUniform16 (#5371) Adds support for the StorageUniform16 capability. --- source/opt/trim_capabilities_pass.cpp | 51 +++++++++++++++++++++++- source/opt/trim_capabilities_pass.h | 1 + test/opt/trim_capabilities_pass_test.cpp | 8 ++-- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/source/opt/trim_capabilities_pass.cpp b/source/opt/trim_capabilities_pass.cpp index 84a848f4c8..77a9c4c95e 100644 --- a/source/opt/trim_capabilities_pass.cpp +++ b/source/opt/trim_capabilities_pass.cpp @@ -207,12 +207,61 @@ Handler_OpTypePointer_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 (hasBufferBlockCapability && + decoration_mgr->HasDecoration(item->result_id(), + spv::Decoration::BufferBlock)) { + return false; + } + + if (is16bitType(item)) { + found16bitType = true; + return false; + } + + return true; + }); + + return found16bitType ? std::optional(spv::Capability::StorageUniform16) + : std::nullopt; +} + // Opcode of interest to determine capabilities requirements. -constexpr std::array, 3> kOpcodeHandlers{{ +constexpr std::array, 4> kOpcodeHandlers{{ // clang-format off {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageInputOutput16}, {spv::Op::OpTypePointer, Handler_OpTypePointer_StoragePushConstant16}, {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniformBufferBlock16}, + {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniform16} // clang-format on }}; diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index 8a92658579..281fe78b40 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -81,6 +81,7 @@ class TrimCapabilitiesPass : public Pass { spv::Capability::ShaderClockKHR, spv::Capability::StorageInputOutput16, spv::Capability::StoragePushConstant16, + spv::Capability::StorageUniform16, spv::Capability::StorageUniformBufferBlock16 // clang-format on }; diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index 390146b5f9..2d80b65404 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -1237,7 +1237,7 @@ TEST_F(TrimCapabilitiesPassTest, } TEST_F(TrimCapabilitiesPassTest, - DISABLED_StorageUniform16_RemovedWithBufferBlockPointer_Vulkan1_0) { + StorageUniform16_RemovedWithBufferBlockPointer_Vulkan1_0) { // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354 static_assert(spv::Capability::StorageUniformBufferBlock16 == spv::Capability::StorageBuffer16BitAccess); @@ -1277,7 +1277,7 @@ TEST_F(TrimCapabilitiesPassTest, } TEST_F(TrimCapabilitiesPassTest, - DISABLED_StorageUniform16_RemovedWithBufferBlockPointer_Vulkan1_1) { + StorageUniform16_RemovedWithBufferBlockPointer_Vulkan1_1) { // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354 static_assert(spv::Capability::StorageUniformBufferBlock16 == spv::Capability::StorageBuffer16BitAccess); @@ -1317,7 +1317,7 @@ TEST_F(TrimCapabilitiesPassTest, } TEST_F(TrimCapabilitiesPassTest, - DISABLED_StorageUniform16_RemovedWithNonBlockUniformPointer_Vulkan1_0) { + StorageUniform16_RemovedWithNonBlockUniformPointer_Vulkan1_0) { // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354 static_assert(spv::Capability::StorageUniformBufferBlock16 == spv::Capability::StorageBuffer16BitAccess); @@ -1356,7 +1356,7 @@ TEST_F(TrimCapabilitiesPassTest, } TEST_F(TrimCapabilitiesPassTest, - DISABLED_StorageUniform16_RemovedWithNonBlockUniformPointer_Vulkan1_1) { + StorageUniform16_RemovedWithNonBlockUniformPointer_Vulkan1_1) { // See https://github.com/KhronosGroup/SPIRV-Tools/issues/5354 static_assert(spv::Capability::StorageUniformBufferBlock16 == spv::Capability::StorageBuffer16BitAccess); From d6300ee92b18c849caf834af2ff29bb1951a4817 Mon Sep 17 00:00:00 2001 From: Ryan Harrison Date: Thu, 10 Aug 2023 15:41:20 -0400 Subject: [PATCH 09/95] Fix -Wunreachable-code-loop-increment warning (#5373) --- source/operand.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/operand.cpp b/source/operand.cpp index 3121eed9f1..4a6c3abe82 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -98,9 +98,9 @@ spv_result_t spvOperandTableValueLookup(spv_target_env, // Assumes the underlying table is already sorted ascendingly according to // opcode value. - 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 + 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; From 43b8886490eb6af81fc61e0ff071c51a922af864 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 11 Aug 2023 15:05:25 +0000 Subject: [PATCH 10/95] roll deps (#5374) * Roll external/googletest/ 89b25572d..7e33b6a1c (1 commit) https://github.com/google/googletest/compare/89b25572dbd7...7e33b6a1c497 $ git log 89b25572d..7e33b6a1c --date=short --no-merges --format='%ad %ae %s' 2023-08-10 absl-team Specify SetUpTestSuite is required to be public. Created with: roll-dep external/googletest * Roll external/spirv-headers/ 124a9665e..45fc02a6c (2 commits) https://github.com/KhronosGroup/SPIRV-Headers/compare/124a9665e464...45fc02a6c670 $ git log 124a9665e..45fc02a6c --date=short --no-merges --format='%ad %ae %s' 2023-08-10 dneto Revert "Merge pull request #367 from dneto0/coop-matrix-enums-deps" 2023-07-29 konstantin.seurer Add SPV_AMDX_shader_enqueue Created with: roll-dep external/spirv-headers --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 953893a079..6aaa404014 100644 --- a/DEPS +++ b/DEPS @@ -7,13 +7,13 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '89b25572dbd7668499d2cfd01dea905f8c44e019', + 'googletest_revision': '7e33b6a1c497ced1e98fc60175aeb4678419281c', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', 're2_revision': '9dc7ae7b52a17b75e3f9249ea85ba578bf42f255', - 'spirv_headers_revision': '124a9665e464ef98b8b718d572d5f329311061eb', + 'spirv_headers_revision': '45fc02a6c67016b3e5ff6e4896a61544a40f90f8', } deps = { From 7ddc65c72211197e5cc562f7614c009e1a91b801 Mon Sep 17 00:00:00 2001 From: Viktoria Maximova Date: Fri, 11 Aug 2023 17:53:24 +0200 Subject: [PATCH 11/95] Support 2 Intel extensions (#5357) * SPV_INTEL_global_variable_fpga_decorations Spec: https://github.com/KhronosGroup/SPIRV-Registry/blob/main/extensions/INTEL/SPV_INTEL_global_variable_fpga_decorations.asciidoc * SPV_INTEL_global_variable_host_access Spec: https://github.com/KhronosGroup/SPIRV-Registry/blob/main/extensions/INTEL/SPV_INTEL_global_variable_host_access.asciidoc This change follows headers change: https://github.com/KhronosGroup/SPIRV-Headers/pull/356 --- include/spirv-tools/libspirv.h | 5 +++++ source/operand.cpp | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index 0208097a80..a699ddcd92 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -293,6 +293,11 @@ 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, + // 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/source/operand.cpp b/source/operand.cpp index 4a6c3abe82..5349a2d49c 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -212,6 +212,10 @@ 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_IMAGE: case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: return "image"; @@ -348,6 +352,8 @@ 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: return true; default: break; From fddcc8cedca662b0e90690f2556d46f359e5a9a8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 14 Aug 2023 10:12:05 -0400 Subject: [PATCH 12/95] Roll external/re2/ 9dc7ae7b5..6148386f0 (3 commits) (#5379) https://github.com/google/re2/compare/9dc7ae7b52a1...6148386f0c8f $ git log 9dc7ae7b5..6148386f0 --date=short --no-merges --format='%ad %ae %s' 2023-08-11 junyer Add support for `(?expr)`. 2023-08-11 junyer Add a `WORKSPACE.bzlmod` file. 2023-08-11 junyer Migrate to Bzlmod. Created with: roll-dep external/re2 Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 6aaa404014..6f04627134 100644 --- a/DEPS +++ b/DEPS @@ -12,7 +12,7 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '9dc7ae7b52a17b75e3f9249ea85ba578bf42f255', + 're2_revision': '6148386f0c8f03da1ab0bf982a4dbe080b4ea7bc', 'spirv_headers_revision': '45fc02a6c67016b3e5ff6e4896a61544a40f90f8', } From 0f17d05c48828c78c44233155ef2741ecad33a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 15 Aug 2023 15:50:57 +0200 Subject: [PATCH 13/95] opt: add bitmask support for capability trimming (#5372) Some operands are not simple values, but bitmasks. The lookup in the table for required decomposing the mask into single values. This commit adds support for such operands, like MinLod|Offset. --- source/opt/trim_capabilities_pass.cpp | 85 ++++++++++++++++-------- source/opt/trim_capabilities_pass.h | 7 ++ test/opt/trim_capabilities_pass_test.cpp | 4 +- 3 files changed, 66 insertions(+), 30 deletions(-) diff --git a/source/opt/trim_capabilities_pass.cpp b/source/opt/trim_capabilities_pass.cpp index 77a9c4c95e..8d533190a8 100644 --- a/source/opt/trim_capabilities_pass.cpp +++ b/source/opt/trim_capabilities_pass.cpp @@ -300,45 +300,56 @@ 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 and OpExtension instructions. - if (instruction->opcode() == spv::Op::OpCapability || - instruction->opcode() == spv::Op::OpExtension) { + const spv_opcode_desc_t* desc = {}; + auto result = context()->grammar().lookupOpcode(opcode, &desc); + if (result != SPV_SUCCESS) { 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, capabilities); - addSupportedExtensionsToSet(desc, extensions); - } + addSupportedCapabilitiesToSet(desc, capabilities); + addSupportedExtensionsToSet(desc, extensions); +} + +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; } - // 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; + // 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; + } - // No supported capability relies on a literal string operand. - if (operand.type == SPV_OPERAND_TYPE_LITERAL_STRING || - operand.type == SPV_OPERAND_TYPE_ID || - operand.type == SPV_OPERAND_TYPE_RESULT_ID) { + // 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; } const spv_operand_desc_t* desc = {}; - auto result = context()->grammar().lookupOperand(operand.type, - operand.words[0], &desc); + auto result = context()->grammar().lookupOperand(operand.type, mask, &desc); if (result != SPV_SUCCESS) { continue; } @@ -346,6 +357,26 @@ void TrimCapabilitiesPass::addInstructionRequirements( 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. auto[begin, end] = opcodeHandlers_.equal_range(instruction->opcode()); diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index 281fe78b40..5f9bedd667 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -132,6 +132,13 @@ class TrimCapabilitiesPass : public Pass { 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. diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index 2d80b65404..0080201dcd 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -517,9 +517,7 @@ TEST_F(TrimCapabilitiesPassTest, EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); } -// FIXME(Keenuts): Add support for bitmask operands. -TEST_F(TrimCapabilitiesPassTest, - DISABLED_MinLod_DetectsMinLodWithBitmaskImageOperand) { +TEST_F(TrimCapabilitiesPassTest, MinLod_DetectsMinLodWithBitmaskImageOperand) { const std::string kTest = R"( OpCapability MinLod ; CHECK: OpCapability MinLod From c55888661031fa12106ad211b0342e702408e141 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Tue, 15 Aug 2023 06:53:10 -0700 Subject: [PATCH 14/95] Fix failing action when PR is already open. (#5380) --- .github/workflows/autoroll.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/autoroll.yml b/.github/workflows/autoroll.yml index 6a7a814df2..68b0ab6fcc 100644 --- a/.github/workflows/autoroll.yml +++ b/.github/workflows/autoroll.yml @@ -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 -r s-perron || 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 }} From 89ca3aa571fe238944b31e88d5d8fe75fab0227a Mon Sep 17 00:00:00 2001 From: Wooyoung Kim Date: Tue, 15 Aug 2023 12:15:21 -0700 Subject: [PATCH 15/95] SPV_QCOM_image_processing support (#5223) --- source/val/validate.cpp | 2 + source/val/validate.h | 8 + source/val/validate_image.cpp | 158 +++- source/val/validate_memory.cpp | 2 + source/val/validation_state.cpp | 72 +- source/val/validation_state.h | 18 + test/val/val_image_test.cpp | 1259 +++++++++++++++++++++++++++++++ 7 files changed, 1488 insertions(+), 31 deletions(-) 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_image.cpp b/source/val/validate_image.cpp index 8062d962c3..7c8dfee765 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. // @@ -983,6 +983,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 +1090,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 +2145,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 +2314,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 +2327,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/val/val_image_test.cpp b/test/val/val_image_test.cpp index 54a9fb6be9..cf317ec989 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -6677,6 +6677,1265 @@ 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")); +} + } // namespace } // namespace val } // namespace spvtools From b12fc2904a46a41d34209685af0a421733eccebe Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Aug 2023 21:50:45 -0700 Subject: [PATCH 16/95] Roll external/googletest/ 7e33b6a1c..987e22561 (5 commits) (#5381) * Roll external/googletest/ 7e33b6a1c..987e22561 (5 commits) https://github.com/google/googletest/compare/7e33b6a1c497...987e22561475 $ git log 7e33b6a1c..987e22561 --date=short --no-merges --format='%ad %ae %s' 2023-08-15 dinor gtest_help_test: Make method names `snake_case`, conforming with [the style guide](https://google.github.io/styleguide/pyguide#316-naming) 2023-08-15 dinor gtest_help_test: Inline test helper functions 2023-08-15 dinor gtest_help_test: Delete obsolete helper `TestUnknownFlagWithAbseil` 2023-08-07 yaneurabeya Fix RETest/1.ImplicitConstructorWorks on non-ABSL platforms 2023-08-07 yaneurabeya Fix GTestHelpTest.TestHelpFlag on FreeBSD Created with: roll-dep external/googletest * Roll external/spirv-headers/ 45fc02a6c..b8b9eb864 (1 commit) https://github.com/KhronosGroup/SPIRV-Headers/compare/45fc02a6c670...b8b9eb8640c8 $ git log 45fc02a6c..b8b9eb864 --date=short --no-merges --format='%ad %ae %s' 2023-08-16 viktoria.maksimova Headers support for two Intel extensions (#356) Created with: roll-dep external/spirv-headers --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 6f04627134..975ccd3014 100644 --- a/DEPS +++ b/DEPS @@ -7,13 +7,13 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '7e33b6a1c497ced1e98fc60175aeb4678419281c', + 'googletest_revision': '987e225614755fec7253aa95bf959c09e0d380d7', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', 're2_revision': '6148386f0c8f03da1ab0bf982a4dbe080b4ea7bc', - 'spirv_headers_revision': '45fc02a6c67016b3e5ff6e4896a61544a40f90f8', + 'spirv_headers_revision': 'b8b9eb8640c8c0107ba580fbcb10f969022ca32c', } deps = { From bfc94f63a7adbcf8ae166f5f108ac9f69079efc0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 19 Aug 2023 09:03:17 +0000 Subject: [PATCH 17/95] roll deps (#5382) * Roll external/googletest/ 987e22561..9fce54804 (2 commits) https://github.com/google/googletest/compare/987e22561475...9fce54804484 $ git log 987e22561..9fce54804 --date=short --no-merges --format='%ad %ae %s' 2023-08-17 absl-team Improve error message for invalid parameterized test names. 2023-07-26 patryk googletest: ansi color fix Created with: roll-dep external/googletest * Roll external/re2/ 6148386f0..08d338fe4 (1 commit) https://github.com/google/re2/compare/6148386f0c8f...08d338fe481f $ git log 6148386f0..08d338fe4 --date=short --no-merges --format='%ad %ae %s' 2023-08-17 junyer Clean up `__GNUC__` conditions. Created with: roll-dep external/re2 --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 975ccd3014..7e7cf9f5d4 100644 --- a/DEPS +++ b/DEPS @@ -7,12 +7,12 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '987e225614755fec7253aa95bf959c09e0d380d7', + 'googletest_revision': '9fce5480448488e17a50bcbf88d2f3bdb637ad6c', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '6148386f0c8f03da1ab0bf982a4dbe080b4ea7bc', + 're2_revision': '08d338fe481fe19adde12fa24b014412d15bdfa0', 'spirv_headers_revision': 'b8b9eb8640c8c0107ba580fbcb10f969022ca32c', } From 6520d83effb26e7c57a8292b9c9733da9e8f8f46 Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Mon, 21 Aug 2023 17:05:33 -0600 Subject: [PATCH 18/95] linker: Add --use-highest-version option (#5376) Currently spirv-link fails if all input files don't use the same SPIR-V version. Add an option to instead use the highest input version as the output version. Note that if one of the 'old' input files uses an opcode that is deprecated in the 'new' version, the output spirv will be invalid. --- include/spirv-tools/linker.hpp | 17 +++++++++-------- source/link/linker.cpp | 15 ++++++++++----- test/link/binary_version_test.cpp | 16 ++++++++++++++++ tools/link/linker.cpp | 9 +++++++++ 4 files changed, 44 insertions(+), 13 deletions(-) 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/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/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/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"); From 714966003d58fd6338c7db64bbd8d24fffb2f6ad Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Mon, 21 Aug 2023 18:16:35 -0600 Subject: [PATCH 19/95] opt: Add SwitchDescriptorSetPass (#5375) This is a simple pass to change DescriptorSet decoration values. --- Android.mk | 1 + BUILD.gn | 2 + include/spirv-tools/optimizer.hpp | 5 + source/opt/CMakeLists.txt | 2 + source/opt/optimizer.cpp | 39 +++++ source/opt/passes.h | 1 + source/opt/switch_descriptorset_pass.cpp | 46 ++++++ source/opt/switch_descriptorset_pass.h | 52 ++++++ test/opt/CMakeLists.txt | 1 + test/opt/switch_descriptorset_test.cpp | 193 +++++++++++++++++++++++ tools/opt/opt.cpp | 4 + 11 files changed, 346 insertions(+) create mode 100644 source/opt/switch_descriptorset_pass.cpp create mode 100644 source/opt/switch_descriptorset_pass.h create mode 100644 test/opt/switch_descriptorset_test.cpp diff --git a/Android.mk b/Android.mk index dcb8d63191..0a875e977f 100644 --- a/Android.mk +++ b/Android.mk @@ -182,6 +182,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.gn b/BUILD.gn index bc48e43b2a..1997e708f0 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -789,6 +789,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/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp index 8579c8c4df..260fa72c98 100644 --- a/include/spirv-tools/optimizer.hpp +++ b/include/spirv-tools/optimizer.hpp @@ -992,6 +992,11 @@ 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); } // namespace spvtools #endif // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_ diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt index 99a74cd7f8..8c903eca82 100644 --- a/source/opt/CMakeLists.txt +++ b/source/opt/CMakeLists.txt @@ -121,6 +121,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 @@ -237,6 +238,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/optimizer.cpp b/source/opt/optimizer.cpp index 6301be6ca1..b8f5283422 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 @@ -549,6 +550,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, to_set; + 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", @@ -1076,6 +1110,11 @@ Optimizer::PassToken CreateTrimCapabilitiesPass() { return MakeUnique( MakeUnique()); } + +Optimizer::PassToken CreateSwitchDescriptorSetPass(uint32_t from, uint32_t to) { + return MakeUnique( + MakeUnique(from, to)); +} } // namespace spvtools extern "C" { diff --git a/source/opt/passes.h b/source/opt/passes.h index f87216dd63..83caa4a77d 100644 --- a/source/opt/passes.h +++ b/source/opt/passes.h @@ -82,6 +82,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/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt index 432a17d092..3a56e93087 100644 --- a/test/opt/CMakeLists.txt +++ b/test/opt/CMakeLists.txt @@ -103,6 +103,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/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/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 From 2601f644eeb33e0c3a9ff97173a7df3aaa1c1281 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 22 Aug 2023 19:25:56 +0000 Subject: [PATCH 20/95] Roll external/googletest/ 9fce54804..61332bd7e (2 commits) (#5383) https://github.com/google/googletest/compare/9fce54804484...61332bd7e881 $ git log 9fce54804..61332bd7e --date=short --no-merges --format='%ad %ae %s' 2023-08-21 dmauro CI: Update the Linux hybrid-latest docker container used for testing 2023-08-21 absl-team Clean up typos: Exhaused => Exhausted Created with: roll-dep external/googletest Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 7e7cf9f5d4..0f064df81e 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '9fce5480448488e17a50bcbf88d2f3bdb637ad6c', + 'googletest_revision': '61332bd7e8810edd7ff9febfa71ece2e25b18df0', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From abd548b8178026b1ac1675deb0abcd43ae9c1907 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Aug 2023 22:29:43 +0000 Subject: [PATCH 21/95] roll deps (#5384) * Roll external/googletest/ 61332bd7e..cb5cd96bc (6 commits) https://github.com/google/googletest/compare/61332bd7e881...cb5cd96bcafc $ git log 61332bd7e..cb5cd96bc --date=short --no-merges --format='%ad %ae %s' 2023-08-22 dinor googletest: Replace http with https in links to docs 2023-08-20 elior.s Update advanced.md 2023-08-11 sch Changed 2 public links from http to https 2023-08-11 sch Changed 3 public links from http to https 2023-08-11 sch Changed 2 public links from http to https 2023-08-11 sch Changed 3 public links from http to https Created with: roll-dep external/googletest * Roll external/re2/ 08d338fe4..73031bbc0 (1 commit) https://github.com/google/re2/compare/08d338fe481f...73031bbc08cb $ git log 08d338fe4..73031bbc0 --date=short --no-merges --format='%ad %ae %s' 2023-08-22 junyer Reset the Bzlmod compatibility level to 1. Created with: roll-dep external/re2 --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 0f064df81e..524aedb639 100644 --- a/DEPS +++ b/DEPS @@ -7,12 +7,12 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '61332bd7e8810edd7ff9febfa71ece2e25b18df0', + 'googletest_revision': 'cb5cd96bcafc15eaaf73517357b596e9ca1e71b4', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '08d338fe481fe19adde12fa24b014412d15bdfa0', + 're2_revision': '73031bbc08cb3e3200497be4a50e37d6f3acc1d0', 'spirv_headers_revision': 'b8b9eb8640c8c0107ba580fbcb10f969022ca32c', } From 1b3c4cb6855f7db1636985e1652ebbf91f81cd50 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 24 Aug 2023 20:29:14 +0000 Subject: [PATCH 22/95] roll deps (#5386) * Roll external/googletest/ cb5cd96bc..460ae9826 (1 commit) https://github.com/google/googletest/compare/cb5cd96bcafc...460ae98267b8 $ git log cb5cd96bc..460ae9826 --date=short --no-merges --format='%ad %ae %s' 2023-08-22 sch changed http to https Created with: roll-dep external/googletest * Roll external/spirv-headers/ b8b9eb864..d790ced75 (1 commit) https://github.com/KhronosGroup/SPIRV-Headers/compare/b8b9eb8640c8...d790ced752b5 $ git log b8b9eb864..d790ced75 --date=short --no-merges --format='%ad %ae %s' 2023-08-23 dneto Validate enums have sensible versions and are visible (#369) Created with: roll-dep external/spirv-headers --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 524aedb639..6da3d168a1 100644 --- a/DEPS +++ b/DEPS @@ -7,13 +7,13 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': 'cb5cd96bcafc15eaaf73517357b596e9ca1e71b4', + 'googletest_revision': '460ae98267b83db4ca2730d368d53f8aee3b636e', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', 're2_revision': '73031bbc08cb3e3200497be4a50e37d6f3acc1d0', - 'spirv_headers_revision': 'b8b9eb8640c8c0107ba580fbcb10f969022ca32c', + 'spirv_headers_revision': 'd790ced752b5bfc06b6988baadef6eb2d16bdf96', } deps = { From b6893ccdfb6e46fa3e093f557b1e5ee124d51f35 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 29 Aug 2023 00:14:32 +0000 Subject: [PATCH 23/95] Roll external/googletest/ 460ae9826..8a6feabf0 (1 commit) (#5388) https://github.com/google/googletest/compare/460ae98267b8...8a6feabf04be $ git log 460ae9826..8a6feabf0 --date=short --no-merges --format='%ad %ae %s' 2023-08-25 dinor googletest: Add universal printer for `std::span` Created with: roll-dep external/googletest Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 6da3d168a1..e30ecc1fd6 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '460ae98267b83db4ca2730d368d53f8aee3b636e', + 'googletest_revision': '8a6feabf04bec8fb125e0df0ad1195c42350725f', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From d09c753a4a784944cd6748ae6a8aa1c0436bbbfb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 30 Aug 2023 14:24:26 +0000 Subject: [PATCH 24/95] Roll external/re2/ 73031bbc0..523f9b097 (1 commit) (#5389) https://github.com/google/re2/compare/73031bbc08cb...523f9b097163 $ git log 73031bbc0..523f9b097 --date=short --no-merges --format='%ad %ae %s' 2023-08-29 junyer Strip `-Wl` for `static-testinstall` and `shared-testinstall` as well. Created with: roll-dep external/re2 Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index e30ecc1fd6..3dd6017533 100644 --- a/DEPS +++ b/DEPS @@ -12,7 +12,7 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '73031bbc08cb3e3200497be4a50e37d6f3acc1d0', + 're2_revision': '523f9b097163895957f0fdd91cb8aa595c7f65a1', 'spirv_headers_revision': 'd790ced752b5bfc06b6988baadef6eb2d16bdf96', } From 51367c40fd10aa39016a3121a7f6b70ef6cbf836 Mon Sep 17 00:00:00 2001 From: Joyce Date: Wed, 30 Aug 2023 14:47:06 -0300 Subject: [PATCH 25/95] Enable OpenSSF Scorecard and Badge (#5377) * Create scorecard.yml Signed-off-by: Joyce * Update README.md Signed-off-by: Joyce --------- Signed-off-by: Joyce --- .github/workflows/scorecard.yml | 53 +++++++++++++++++++++++++++++++++ README.md | 1 + 2 files changed, 54 insertions(+) create mode 100644 .github/workflows/scorecard.yml diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 0000000000..b45d0915f2 --- /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@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86 # v2.1.2 + with: + results_file: results.sarif + results_format: sarif + # To enable Branch-Protection uncomment the `repo_token` line below + # To create the Fine-grained PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-fine-grained-pat-optional. + # repo_token: ${{ secrets.SCORECARD_TOKEN }} + publish_results: true # allows the repo to include the Scorecard badge + + # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF + # format to the repository Actions tab. + - name: "Upload artifact" + uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 + 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@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4 + with: + sarif_file: results.sarif 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. From 9b923f7cc3dde6e1a4886b577677e52c3093ffcc Mon Sep 17 00:00:00 2001 From: Mike Gorchak <74101708+mgorchak-blackberry@users.noreply.github.com> Date: Wed, 30 Aug 2023 14:51:03 -0400 Subject: [PATCH 26/95] QNX has support for ANSI ESC codes, default terminal is QANSI. (#5387) --- source/print.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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"; } From 4c16c35b16bbd462a0e89707ebeecc0bce956b2f Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Mon, 4 Sep 2023 02:27:56 -0700 Subject: [PATCH 27/95] opt: add FragmentShader*InterlockEXT to capability trim pass (#5390) * opt: add FragmentShader*InterlockEXT to capability trim pass * move to addInstructionRequirementsForOpcode --- source/opt/trim_capabilities_pass.cpp | 7 + source/opt/trim_capabilities_pass.h | 3 + test/opt/trim_capabilities_pass_test.cpp | 196 +++++++++++++++++++++++ 3 files changed, 206 insertions(+) diff --git a/source/opt/trim_capabilities_pass.cpp b/source/opt/trim_capabilities_pass.cpp index 8d533190a8..f8e4d81871 100644 --- a/source/opt/trim_capabilities_pass.cpp +++ b/source/opt/trim_capabilities_pass.cpp @@ -303,6 +303,13 @@ TrimCapabilitiesPass::TrimCapabilitiesPass() void TrimCapabilitiesPass::addInstructionRequirementsForOpcode( spv::Op opcode, CapabilitySet* capabilities, ExtensionSet* extensions) const { + // 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; + } + const spv_opcode_desc_t* desc = {}; auto result = context()->grammar().lookupOpcode(opcode, &desc); if (result != SPV_SUCCESS) { diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index 5f9bedd667..16b5781aea 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -74,6 +74,9 @@ class TrimCapabilitiesPass : public Pass { // contains unsupported instruction, the pass could yield bad results. static constexpr std::array kSupportedCapabilities{ // clang-format off + spv::Capability::FragmentShaderPixelInterlockEXT, + spv::Capability::FragmentShaderSampleInterlockEXT, + spv::Capability::FragmentShaderShadingRateInterlockEXT, spv::Capability::Groups, spv::Capability::Linkage, spv::Capability::MinLod, diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index 0080201dcd..a791fe2883 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -1392,6 +1392,202 @@ TEST_F(TrimCapabilitiesPassTest, EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); } +TEST_F(TrimCapabilitiesPassTest, FragmentShaderRemoved) { + 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, FragmentShaderPixelInterlockOrderedRemains) { + 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, FragmentShaderPixelInterlockUnorderedRemains) { + 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, FragmentShaderSampleInterlockOrderedRemains) { + 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, + FragmentShaderSampleInterlockUnorderedRemains) { + 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, + FragmentShaderShadingRateInterlockOrderedRemains) { + 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, + FragmentShaderShadingRateInterlockUnorderedRemains) { + 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); +} + } // namespace } // namespace opt } // namespace spvtools From 3cc7e1c4c318aa4c4a7a8972b6066ab2d9d217cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 4 Sep 2023 23:32:28 +0200 Subject: [PATCH 28/95] NFC: rename tests using capability as prefix (#5396) --- test/opt/trim_capabilities_pass_test.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index a791fe2883..90954439fd 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -1392,7 +1392,7 @@ TEST_F(TrimCapabilitiesPassTest, EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); } -TEST_F(TrimCapabilitiesPassTest, FragmentShaderRemoved) { +TEST_F(TrimCapabilitiesPassTest, FragmentShaderInterlock_RemovedIfNotUsed) { const std::string kTest = R"( OpCapability Shader OpCapability FragmentShaderPixelInterlockEXT @@ -1417,7 +1417,8 @@ TEST_F(TrimCapabilitiesPassTest, FragmentShaderRemoved) { EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); } -TEST_F(TrimCapabilitiesPassTest, FragmentShaderPixelInterlockOrderedRemains) { +TEST_F(TrimCapabilitiesPassTest, + FragmentShaderPixelInterlock_RemainsWhenOrderedIsUsed) { const std::string kTest = R"( OpCapability Shader OpCapability FragmentShaderPixelInterlockEXT @@ -1445,7 +1446,8 @@ TEST_F(TrimCapabilitiesPassTest, FragmentShaderPixelInterlockOrderedRemains) { EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); } -TEST_F(TrimCapabilitiesPassTest, FragmentShaderPixelInterlockUnorderedRemains) { +TEST_F(TrimCapabilitiesPassTest, + FragmentShaderPixelInterlock_RemainsWhenUnorderedIsUsed) { const std::string kTest = R"( OpCapability Shader OpCapability FragmentShaderPixelInterlockEXT @@ -1473,7 +1475,8 @@ TEST_F(TrimCapabilitiesPassTest, FragmentShaderPixelInterlockUnorderedRemains) { EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); } -TEST_F(TrimCapabilitiesPassTest, FragmentShaderSampleInterlockOrderedRemains) { +TEST_F(TrimCapabilitiesPassTest, + FragmentShaderSampleInterlock_RemainsWhenOrderedIsUsed) { const std::string kTest = R"( OpCapability Shader OpCapability FragmentShaderPixelInterlockEXT @@ -1502,7 +1505,7 @@ TEST_F(TrimCapabilitiesPassTest, FragmentShaderSampleInterlockOrderedRemains) { } TEST_F(TrimCapabilitiesPassTest, - FragmentShaderSampleInterlockUnorderedRemains) { + FragmentShaderSampleInterlock_RemainsWhenUnorderedIsUsed) { const std::string kTest = R"( OpCapability Shader OpCapability FragmentShaderPixelInterlockEXT @@ -1531,7 +1534,7 @@ TEST_F(TrimCapabilitiesPassTest, } TEST_F(TrimCapabilitiesPassTest, - FragmentShaderShadingRateInterlockOrderedRemains) { + FragmentShaderShadingRateInterlock_RemainsWhenOrderedIsUsed) { const std::string kTest = R"( OpCapability Shader OpCapability FragmentShaderPixelInterlockEXT @@ -1560,7 +1563,7 @@ TEST_F(TrimCapabilitiesPassTest, } TEST_F(TrimCapabilitiesPassTest, - FragmentShaderShadingRateInterlockUnorderedRemains) { + FragmentShaderShadingRateInterlock_RemainsWhenUnorderedIsUsed) { const std::string kTest = R"( OpCapability Shader OpCapability FragmentShaderPixelInterlockEXT From 1121c23198901cf7c9f9b615f14045493a346e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 5 Sep 2023 15:47:46 +0200 Subject: [PATCH 29/95] opt: add Int64 capability to trim pass (#5398) Adds support for Int64 capability trimming. --- source/opt/trim_capabilities_pass.cpp | 16 ++++++++-- source/opt/trim_capabilities_pass.h | 1 + test/opt/trim_capabilities_pass_test.cpp | 39 ++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/source/opt/trim_capabilities_pass.cpp b/source/opt/trim_capabilities_pass.cpp index f8e4d81871..6c6b4a0998 100644 --- a/source/opt/trim_capabilities_pass.cpp +++ b/source/opt/trim_capabilities_pass.cpp @@ -40,6 +40,7 @@ constexpr uint32_t kOpTypePointerStorageClassIndex = 0; constexpr uint32_t kTypeArrayTypeIndex = 0; constexpr uint32_t kOpTypeScalarBitWidthIndex = 0; constexpr uint32_t kTypePointerTypeIdInIdx = 1; +constexpr uint32_t kOpTypeIntSizeIndex = 0; // DFS visit of the type defined by `instruction`. // If `condition` is true, children of the current node are visited. @@ -255,13 +256,24 @@ static std::optional Handler_OpTypePointer_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; +} + // Opcode of interest to determine capabilities requirements. -constexpr std::array, 4> kOpcodeHandlers{{ +constexpr std::array, 5> kOpcodeHandlers{{ // clang-format off {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageInputOutput16}, {spv::Op::OpTypePointer, Handler_OpTypePointer_StoragePushConstant16}, {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniformBufferBlock16}, - {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniform16} + {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniform16}, + {spv::Op::OpTypeInt, Handler_OpTypeInt_Int64 }, // clang-format on }}; diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index 16b5781aea..2728617990 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -78,6 +78,7 @@ class TrimCapabilitiesPass : public Pass { spv::Capability::FragmentShaderSampleInterlockEXT, spv::Capability::FragmentShaderShadingRateInterlockEXT, spv::Capability::Groups, + spv::Capability::Int64, spv::Capability::Linkage, spv::Capability::MinLod, spv::Capability::Shader, diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index 90954439fd..fb64ecd3a6 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -1591,6 +1591,45 @@ TEST_F(TrimCapabilitiesPassTest, 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); +} + } // namespace } // namespace opt } // namespace spvtools From 158bc7bd6b3078d1a38488ae8d1322657ed6cf15 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 14:32:00 +0000 Subject: [PATCH 30/95] Roll external/re2/ 523f9b097..e0077036c (2 commits) (#5391) https://github.com/google/re2/compare/523f9b097163...e0077036ca06 $ git log 523f9b097..e0077036c --date=short --no-merges --format='%ad %ae %s' 2023-08-31 junyer `@rules_python` fails due to Bazel running as root. 2023-08-31 junyer Prepare to tag release `2023-09-01`. Created with: roll-dep external/re2 Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 3dd6017533..e8a4dabf3f 100644 --- a/DEPS +++ b/DEPS @@ -12,7 +12,7 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '523f9b097163895957f0fdd91cb8aa595c7f65a1', + 're2_revision': 'e0077036ca06238db4abef5ba18ced3e5b9a5893', 'spirv_headers_revision': 'd790ced752b5bfc06b6988baadef6eb2d16bdf96', } From 1f07f483efe062ae1bd758b93d107de2b4aefc42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 5 Sep 2023 16:36:14 +0200 Subject: [PATCH 31/95] opt: add raytracing/rayquery to trim pass (#5397) Adds the RayTracingKHR and RayQueryKHR capabilities to the supported capabilities list (this includes the linked extension). (NV and KHR capabilities/extensions shared the same IDs, so it also works for NV flavors of those). --- source/opt/trim_capabilities_pass.h | 3 + test/opt/trim_capabilities_pass_test.cpp | 323 +++++++++++++++++++++++ 2 files changed, 326 insertions(+) diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index 2728617990..27803555b1 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -81,6 +81,9 @@ class TrimCapabilitiesPass : public Pass { spv::Capability::Int64, spv::Capability::Linkage, spv::Capability::MinLod, + spv::Capability::RayQueryKHR, + spv::Capability::RayTracingKHR, + spv::Capability::RayTraversalPrimitiveCullingKHR, spv::Capability::Shader, spv::Capability::ShaderClockKHR, spv::Capability::StorageInputOutput16, diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index fb64ecd3a6..0a4eba27bc 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -1630,6 +1630,329 @@ TEST_F(TrimCapabilitiesPassTest, Int64_RemainsWhenUsed) { 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); +} + } // namespace } // namespace opt } // namespace spvtools From d474a070887a3896387570b051ce2d02027468de Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Tue, 5 Sep 2023 09:10:16 -0700 Subject: [PATCH 32/95] Add SPV_EXT_fragment_shader_interlock to allow lists (#5393) --- source/opt/aggressive_dead_code_elim_pass.cpp | 1 + source/opt/local_access_chain_convert_pass.cpp | 3 ++- source/opt/local_single_block_elim_pass.cpp | 3 ++- source/opt/local_single_store_elim_pass.cpp | 3 ++- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp index 87324cdb13..1af0b7f99a 100644 --- a/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/source/opt/aggressive_dead_code_elim_pass.cpp @@ -999,6 +999,7 @@ void AggressiveDCEPass::InitExtensions() { "SPV_KHR_fragment_shader_barycentric", "SPV_NV_bindless_texture", "SPV_EXT_shader_atomic_float_add", + "SPV_EXT_fragment_shader_interlock", }); } diff --git a/source/opt/local_access_chain_convert_pass.cpp b/source/opt/local_access_chain_convert_pass.cpp index d024af60a8..fac4cea64f 100644 --- a/source/opt/local_access_chain_convert_pass.cpp +++ b/source/opt/local_access_chain_convert_pass.cpp @@ -427,7 +427,8 @@ 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"}); } 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..2b7f7278bb 100644 --- a/source/opt/local_single_block_elim_pass.cpp +++ b/source/opt/local_single_block_elim_pass.cpp @@ -287,7 +287,8 @@ 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"}); } } // namespace opt diff --git a/source/opt/local_single_store_elim_pass.cpp b/source/opt/local_single_store_elim_pass.cpp index fefe2ce9e0..e52d721ac2 100644 --- a/source/opt/local_single_store_elim_pass.cpp +++ b/source/opt/local_single_store_elim_pass.cpp @@ -137,7 +137,8 @@ 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"}); } bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) { std::vector users; From 4e0b94ed7aa8c4b8f7a852f32d0e17d1e1d1c11d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 5 Sep 2023 20:36:03 +0200 Subject: [PATCH 33/95] opt: add ImageMSArray capability to trim pass. (#5395) From the Capability's text in the SPIRV spec: ``` An MS operand in OpTypeImage indicates multisampled, used with an OpTypeImage having Sampled == 2 and Arrayed == 1. ``` Adding this logic to the capability trimming pass. --- source/opt/trim_capabilities_pass.cpp | 31 ++++- source/opt/trim_capabilities_pass.h | 3 +- test/opt/trim_capabilities_pass_test.cpp | 137 +++++++++++++++++++++++ 3 files changed, 165 insertions(+), 6 deletions(-) diff --git a/source/opt/trim_capabilities_pass.cpp b/source/opt/trim_capabilities_pass.cpp index 6c6b4a0998..4b3d74af65 100644 --- a/source/opt/trim_capabilities_pass.cpp +++ b/source/opt/trim_capabilities_pass.cpp @@ -39,8 +39,11 @@ namespace { 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 kOpTypeImageArrayedIndex = 3; +constexpr uint32_t kOpTypeImageMSIndex = kOpTypeImageArrayedIndex + 1; +constexpr uint32_t kOpTypeImageSampledIndex = kOpTypeImageMSIndex + 1; // DFS visit of the type defined by `instruction`. // If `condition` is true, children of the current node are visited. @@ -61,7 +64,7 @@ static void DFSWhile(const Instruction* instruction, UnaryPredicate condition) { if (item->opcode() == spv::Op::OpTypePointer) { instructions_to_visit.push( - item->GetSingleWordInOperand(kTypePointerTypeIdInIdx)); + item->GetSingleWordInOperand(kTypePointerTypeIdInIndex)); continue; } @@ -266,14 +269,32 @@ static std::optional Handler_OpTypeInt_Int64( 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; +} + // Opcode of interest to determine capabilities requirements. -constexpr std::array, 5> kOpcodeHandlers{{ +constexpr std::array, 7> kOpcodeHandlers{{ // clang-format off + {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_StorageUniformBufferBlock16}, {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniform16}, - {spv::Op::OpTypeInt, Handler_OpTypeInt_Int64 }, + {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniform16}, + {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageUniformBufferBlock16}, // clang-format on }}; diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index 27803555b1..b9ad7a938e 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -89,7 +89,8 @@ class TrimCapabilitiesPass : public Pass { spv::Capability::StorageInputOutput16, spv::Capability::StoragePushConstant16, spv::Capability::StorageUniform16, - spv::Capability::StorageUniformBufferBlock16 + spv::Capability::StorageUniformBufferBlock16, + spv::Capability::ImageMSArray // clang-format on }; diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index 0a4eba27bc..d7bdafe1c0 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -1953,6 +1953,143 @@ TEST_F(TrimCapabilitiesPassTest, 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); +} + } // namespace } // namespace opt } // namespace spvtools From 440f018cc4cc614e0e4e52abef8a519071d30d9b Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Tue, 5 Sep 2023 15:38:49 -0400 Subject: [PATCH 34/95] Fix `AddMemberDecoration` variable names. (#5399) The prototype does not match the implementation. Fixes Typo in declaration DecorationManager::AddMemberDecoration #5392 --- source/opt/decoration_manager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/opt/decoration_manager.h b/source/opt/decoration_manager.h index 08cb2f3448..2be016a71a 100644 --- a/source/opt/decoration_manager.h +++ b/source/opt/decoration_manager.h @@ -142,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&); From d660bb55be0c5591cb733c9c2ebf5a9d97129d3a Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 6 Sep 2023 12:35:57 -0400 Subject: [PATCH 35/95] Add SPV_KHR_physical_storage_buffer to allowlists (#5402) Fixes #4896 --- source/opt/aggressive_dead_code_elim_pass.cpp | 1 + source/opt/local_single_block_elim_pass.cpp | 1 + source/opt/local_single_store_elim_pass.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp index 1af0b7f99a..55feca811e 100644 --- a/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/source/opt/aggressive_dead_code_elim_pass.cpp @@ -988,6 +988,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", diff --git a/source/opt/local_single_block_elim_pass.cpp b/source/opt/local_single_block_elim_pass.cpp index 2b7f7278bb..0acffda335 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", diff --git a/source/opt/local_single_store_elim_pass.cpp b/source/opt/local_single_store_elim_pass.cpp index e52d721ac2..77b3420ce9 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", From 47b63a4d7da04ae8d3f50a5df560c4b879308257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 7 Sep 2023 15:39:28 +0200 Subject: [PATCH 36/95] val: re-add ImageMSArray validation (#5394) This has been removed in #4752, but not added since. * fixup! val: re-add ImageMSArray validation clang-format --- source/val/validate_image.cpp | 13 ++-- test/val/val_image_test.cpp | 110 ++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 9 deletions(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 7c8dfee765..39eeb4bd7e 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -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 + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Capability ImageMSArray is required to access storage " + << "image"; } } else if (info.sampled != 0) { return _.diag(SPV_ERROR_INVALID_DATA, inst) diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index cf317ec989..9a704098de 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -7936,6 +7936,116 @@ TEST_F(ValidateImage, QCOMImageProcessingSampleWeightedInvalidUseB) { 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 From 5e6054c1cb0dd3f1b23dd535a2ab99303d9ca070 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 18:37:12 +0000 Subject: [PATCH 37/95] Roll external/re2/ e0077036c..a807e8a3a (6 commits) (#5401) https://github.com/google/re2/compare/e0077036ca06...a807e8a3aac2 $ git log e0077036c..a807e8a3a --date=short --no-merges --format='%ad %ae %s' 2023-09-07 junyer Revert "Make the extension work for Python 3.8+." 2023-09-07 junyer Make the extension work for Python 3.8+. 2023-09-07 junyer Try plumbing the platform name a different way. 2023-09-07 junyer Add a "dry run" mode to the Python workflow. 2023-09-04 junyer Switch to `python -m build`. 2023-09-04 junyer Mark three dependencies as `dev_dependency = True`. Created with: roll-dep external/re2 Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index e8a4dabf3f..30c9ba90cd 100644 --- a/DEPS +++ b/DEPS @@ -12,7 +12,7 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': 'e0077036ca06238db4abef5ba18ced3e5b9a5893', + 're2_revision': 'a807e8a3aac2cc33c77b7071efea54fcabe38e0c', 'spirv_headers_revision': 'd790ced752b5bfc06b6988baadef6eb2d16bdf96', } From 361638cfd0abc3655f59bee755c3af6200b57289 Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Mon, 11 Sep 2023 12:26:10 -0700 Subject: [PATCH 38/95] Make sure that fragment shader interlock instructions are not removed by DCE (#5400) --- test/opt/aggressive_dead_code_elim_test.cpp | 45 ++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) 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 From 2d6996f7313a51a74a07c07f2bedfd56b1ece583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Cruz?= Date: Mon, 11 Sep 2023 21:52:31 +0100 Subject: [PATCH 39/95] Check for git repository before git commands (#5403) When we are attempting to fetch the version info from the git repository, first check if we're actually in one, otherwise spurious errors messages get printed. --- utils/update_build_version.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/utils/update_build_version.py b/utils/update_build_version.py index 5a78ada261..1d7f565150 100755 --- a/utils/update_build_version.py +++ b/utils/update_build_version.py @@ -111,17 +111,19 @@ 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 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() + # if we're in a git repository, attempt to extract version info + if os.path.exists(".git"): + success, output = command_output(["git", "describe"], repo_path) + if not 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. From fc54e178e94060dff8c06dc6957736e713737e53 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Mon, 11 Sep 2023 20:24:32 -0400 Subject: [PATCH 40/95] Change autoroll pr review id (#5404) The autoroll pr reviews add me as the reviewer. I want to change this so that it requests a reveiw from a team instead. --- .github/workflows/autoroll.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/autoroll.yml b/.github/workflows/autoroll.yml index 68b0ab6fcc..ec457533f8 100644 --- a/.github/workflows/autoroll.yml +++ b/.github/workflows/autoroll.yml @@ -48,7 +48,7 @@ jobs: run: | git push --force --set-upstream origin roll_deps # Create a PR. If it aready exists, the command fails, so ignore the return code. - gh pr create --base main -f -r s-perron || true + gh pr create --base main -f -r KhronosGroup/spirv-tools-autoroll || 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 From a996591b1c67e789e88e99ae3881272f5fc47374 Mon Sep 17 00:00:00 2001 From: David Neto Date: Wed, 13 Sep 2023 17:43:12 -0400 Subject: [PATCH 41/95] Update SPIRV-Headers, add cache control operand kinds (#5406) * Update SPIRV-Headers, add cache control operand kinds Adds SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL and SPV_OPERAND_TYPE_STORE_CACHE_CONTROL, from SPV_INTEL_cache_controls Fixes: #5404 * Update tests: remove Kernel from constant sampler enum dependencies This corresponds to header change https://github.com/KhronosGroup/SPIRV-Headers/pull/378 --- DEPS | 2 +- include/spirv-tools/libspirv.h | 4 ++++ source/operand.cpp | 6 ++++++ test/operand_capabilities_test.cpp | 22 +++++++++------------- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/DEPS b/DEPS index 30c9ba90cd..b181769f63 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': 'a807e8a3aac2cc33c77b7071efea54fcabe38e0c', - 'spirv_headers_revision': 'd790ced752b5bfc06b6988baadef6eb2d16bdf96', + 'spirv_headers_revision': 'fc7d2462765183c784a0c46beb13eee9e506a067', } deps = { diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index a699ddcd92..b70f084a8e 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -297,6 +297,10 @@ typedef enum spv_operand_type_t { 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. diff --git a/source/operand.cpp b/source/operand.cpp index 5349a2d49c..6577f8f7db 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -216,6 +216,10 @@ const char* spvOperandTypeStr(spv_operand_type_t type) { 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"; @@ -354,6 +358,8 @@ bool spvOperandIsConcrete(spv_operand_type_t type) { 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/test/operand_capabilities_test.cpp b/test/operand_capabilities_test.cpp index 607d3510df..4872228170 100644 --- a/test/operand_capabilities_test.cpp +++ b/test/operand_capabilities_test.cpp @@ -266,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 From a40483d313bdfa7f9873883284c86f6e9a3294be Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 20 Sep 2023 00:29:21 -0400 Subject: [PATCH 42/95] roll deps (#5408) * Roll external/googletest/ 8a6feabf0..adc514538 (7 commits) https://github.com/google/googletest/compare/8a6feabf04be...adc514538678 $ git log 8a6feabf0..adc514538 --date=short --no-merges --format='%ad %ae %s' 2023-09-18 absl-team Update code with IWYU annotations. 2023-09-18 absl-team Use the `empty()` method to check for emptiness instead of `length()` 2023-09-14 hirshleifer GoogleTest FAQ: minor punctuation fixes 2023-09-14 hirshleifer Remove Googletest FAQ entry for obsolete `ProtocolMessageEquals` and `ProtocolMessageEquiv` 2023-09-03 tanzinul.islam Count threads after thread-creation while still holding mutex lock 2023-08-26 tanzinul.islam Reuse TempDir() function 2023-08-18 tanzinul.islam Prefer $TMPDIR to /data/local/tmp on Android Created with: roll-dep external/googletest * Roll external/re2/ a807e8a3a..09de536bb (1 commit) https://github.com/google/re2/compare/a807e8a3aac2...09de536bb7c7 $ git log a807e8a3a..09de536bb --date=short --no-merges --format='%ad %ae %s' 2023-09-14 junyer Use Abseil's character class functions. Created with: roll-dep external/re2 --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index b181769f63..74c5cd99dc 100644 --- a/DEPS +++ b/DEPS @@ -7,12 +7,12 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '8a6feabf04bec8fb125e0df0ad1195c42350725f', + 'googletest_revision': 'adc514538678a61b13c240f7b41babbc03b2ac24', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': 'a807e8a3aac2cc33c77b7071efea54fcabe38e0c', + 're2_revision': '09de536bb7c77c2e0869a001f012d49560f56cbe', 'spirv_headers_revision': 'fc7d2462765183c784a0c46beb13eee9e506a067', } From ee7598d49798e7bf34fabe55b5a438a381d450c8 Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Wed, 20 Sep 2023 10:50:30 -0600 Subject: [PATCH 43/95] instrument: Use Import linkage for instrumentation functions (#5355) These functions are getting far too complicated to code in SPIRV-Tools C++. Replace them with import stubs so that the real implementations can live in Vulkan-ValidationLayers where they belong. VVL will need to define these functions in spirv and link them to the instrumented version of the user's shader. From here on out, VVL can redefine the functions and any data they use without updating SPIRV-Tools. Changing the function declarations will still require both VVL and SPIRV-Tools to be updated in lock step. --- include/spirv-tools/instrument.hpp | 122 - include/spirv-tools/optimizer.hpp | 9 +- source/opt/inst_bindless_check_pass.cpp | 648 +--- source/opt/inst_bindless_check_pass.h | 15 +- source/opt/inst_buff_addr_check_pass.cpp | 293 +- source/opt/inst_buff_addr_check_pass.h | 13 +- source/opt/inst_debug_printf_pass.cpp | 236 ++ source/opt/inst_debug_printf_pass.h | 128 +- source/opt/instrument_pass.cpp | 400 -- source/opt/instrument_pass.h | 197 +- source/opt/ir_context.h | 6 + source/opt/module.h | 8 + source/opt/optimizer.cpp | 14 +- test/opt/inst_bindless_check_test.cpp | 4412 ++++++++++------------ test/opt/inst_buff_addr_check_test.cpp | 511 +-- 15 files changed, 2712 insertions(+), 4300 deletions(-) diff --git a/include/spirv-tools/instrument.hpp b/include/spirv-tools/instrument.hpp index 34e169a9ef..ae9278b0fc 100644 --- a/include/spirv-tools/instrument.hpp +++ b/include/spirv-tools/instrument.hpp @@ -133,71 +133,6 @@ 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 @@ -216,63 +151,6 @@ 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/optimizer.hpp b/include/spirv-tools/optimizer.hpp index 260fa72c98..ef639524cd 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 diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp index 339fb1b62c..f84d5b2985 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 @@ -1311,6 +725,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, diff --git a/source/opt/inst_bindless_check_pass.h b/source/opt/inst_bindless_check_pass.h index 289f02f1ab..f99b59d0a5 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) {} ~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..e1fde77133 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,15 @@ 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::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, diff --git a/source/opt/inst_buff_addr_check_pass.h b/source/opt/inst_buff_addr_check_pass.h index 9c4b3ed9a9..70076a3712 100644 --- a/source/opt/inst_buff_addr_check_pass.h +++ b/source/opt/inst_buff_addr_check_pass.h @@ -29,10 +29,9 @@ namespace opt { class InstBuffAddrCheckPass : public InstrumentPass { public: // For test harness only - InstBuffAddrCheckPass() : InstrumentPass(7, 23, kInstValidationIdBuffAddr) {} + InstBuffAddrCheckPass() : InstrumentPass(0, 23) {} // 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) {} ~InstBuffAddrCheckPass() override = default; @@ -41,9 +40,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 +57,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 +110,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..a48a28f6b1 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" @@ -210,9 +211,244 @@ 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, + 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]; +} + +void InstDebugPrintfPass::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); +} + +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() { diff --git a/source/opt/inst_debug_printf_pass.h b/source/opt/inst_debug_printf_pass.h index 70b0a72bd7..3a2078a7dd 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) {} // For all other interfaces InstDebugPrintfPass(uint32_t desc_set, uint32_t shader_id) - : InstrumentPass(desc_set, shader_id, kInstValidationIdDebugPrintf) {} + : InstrumentPass(desc_set, shader_id) {} ~InstDebugPrintfPass() override = default; @@ -41,6 +41,104 @@ 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. 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 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 @@ -80,13 +178,37 @@ class InstDebugPrintfPass : public InstrumentPass { void GenOutputCode(Instruction* printf_inst, uint32_t stage_idx, 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..829de491cd 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); @@ -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) { @@ -1091,10 +695,6 @@ bool InstrumentPass::InstProcessEntryPointCallTree(InstProcessFunction& pfn) { } 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..8b643742dd 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,12 +77,11 @@ 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, + InstrumentPass(uint32_t desc_set, uint32_t shader_id, bool opt_direct_reads = false) : Pass(), desc_set_(desc_set), shader_id_(shader_id), - validation_id_(validation_id), opt_direct_reads_(opt_direct_reads) {} // Initialize state for instrumentation of module. @@ -113,108 +104,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 +135,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 +166,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 +184,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 +203,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 +243,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 +308,11 @@ 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_; + bool opt_direct_reads_{false}; }; } // namespace opt 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/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 b8f5283422..afff9ece43 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -434,13 +434,13 @@ 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(CreateInstBuffAddrCheckPass(23)); RegisterPass(CreateAggressiveDCEPass(true)); } else if (pass_name == "convert-relaxed-to-half") { RegisterPass(CreateConvertRelaxedToHalfPass()); @@ -980,10 +980,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, @@ -992,10 +991,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() { diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp index 1c192c4366..0deec5c6a5 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,69 @@ 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, MultipleDebugFunctions) { @@ -1188,11 +923,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 +956,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 +991,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 +1029,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 +1077,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 +1101,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 +1129,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 +1146,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 +1187,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 +1205,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 +1223,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 +1235,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 +1309,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 +1364,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 +1387,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 +1412,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 +1430,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 +1444,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 +1493,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 +1518,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 +1534,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 +1549,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 +1587,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 +1612,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 +1630,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 +1644,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 +1688,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 +1707,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 +1720,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 +1736,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 +1783,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 +1807,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 +1823,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 +1834,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 +1879,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 +1904,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 +1923,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 +1935,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 +1987,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 +2010,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 +2033,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 +2051,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 +2133,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 +2157,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 +2180,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 +2195,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 +2277,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 +2301,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 +2324,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 +2340,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 +2421,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 +2445,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 +2468,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 +2484,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 +;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 )"; - - 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, @@ -2905,13 +2572,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 +2596,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 +2619,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 +2635,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 +2723,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 +2747,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 +2770,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,85 +2786,84 @@ 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 -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); -} - -TEST_F(InstBindlessTest, - InstBoundsCallableInitLoadVariableSizedSampledImagesArray) { - // #version 460 - // #extension GL_EXT_nonuniform_qualifier : require - // #extension GL_NV_ray_tracing : require - // - // layout(set = 1, binding = 2, std140) buffer StorageBuffer { - // uint index; - // float red; - // } sbo; - // - // layout(set = 1, binding = 3, rgba32f) readonly uniform image2D images[]; - // - // void main() - // { +;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 +)"; + // clang-format on + + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(defs + kImportStub + main_func, + true, 23u); +} + +TEST_F(InstBindlessTest, + InstBoundsCallableInitLoadVariableSizedSampledImagesArray) { + // #version 460 + // #extension GL_EXT_nonuniform_qualifier : require + // #extension GL_NV_ray_tracing : require + // + // layout(set = 1, binding = 2, std140) buffer StorageBuffer { + // uint index; + // float red; + // } sbo; + // + // layout(set = 1, binding = 3, rgba32f) readonly uniform image2D images[]; + // + // void main() + // { // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; // } @@ -3212,13 +2871,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 +2895,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 +2918,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 +2931,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 +3030,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 +3065,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 +3101,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 +3120,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 +3148,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 +3198,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 +3244,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 +3423,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 +3520,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 +3530,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 +3556,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 +3657,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 +3668,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 +3680,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 +3693,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 +3711,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 +3804,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 +3852,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 +3955,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 +3966,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 +4002,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 +4073,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 +4083,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 +4117,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 +4188,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 +4198,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 +4233,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 +4307,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 +4322,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 +4346,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 +4410,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 +4432,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 +4517,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 +4580,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 +4602,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 +4670,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 +4693,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 +4765,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 +4796,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 +4820,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 +4840,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 +4857,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 +4881,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 +4905,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 +4956,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 +4993,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 +5014,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 From 27673a054447e37810a38e7ce8d35a0a88af4a75 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Tue, 26 Sep 2023 12:06:29 -0400 Subject: [PATCH 44/95] Remove reviewer from autoroller (#5414) For some reason the `gh` command to create a pull request with a team as the reviewer is not working. That command works when I run it locally. I don't know what the problem is, but I will just stop adding a reviewer. Then anyone can look at it. --- .github/workflows/autoroll.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/autoroll.yml b/.github/workflows/autoroll.yml index ec457533f8..e5a7ee0814 100644 --- a/.github/workflows/autoroll.yml +++ b/.github/workflows/autoroll.yml @@ -48,7 +48,7 @@ jobs: run: | git push --force --set-upstream origin roll_deps # Create a PR. If it aready exists, the command fails, so ignore the return code. - gh pr create --base main -f -r KhronosGroup/spirv-tools-autoroll || true + 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 From 48c97c131190392a3c80f107f421d68b2570b4f0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 27 Sep 2023 11:09:18 -0400 Subject: [PATCH 45/95] roll deps (#5415) * Roll external/googletest/ adc514538..e47544ad3 (5 commits) https://github.com/google/googletest/compare/adc514538678...e47544ad31cb $ git log adc514538..e47544ad3 --date=short --no-merges --format='%ad %ae %s' 2023-09-25 absl-team Resolve `-Wundef` triggering on `GTEST_CREATE_SHARED_LIBRARY` and `GTEST_LINKED_AS_SHARED_LIBRARY` with shared libraries in GoogleTest 2023-09-22 absl-team Update C++ feature detection in `gtest-port.h` to rely on feature test macros where possible. 2023-09-21 absl-team Use `absl::HasAbslStringify`, instead of the internal version. 2023-09-21 dinor googletest: Update absl to version with HasAbslStringify 2023-09-21 mitja Fix compile warnings in gmock-function-mocker.h Created with: roll-dep external/googletest * Roll external/re2/ 09de536bb..26f7d889e (1 commit) https://github.com/google/re2/compare/09de536bb7c7...26f7d889e1f7 $ git log 09de536bb..26f7d889e --date=short --no-merges --format='%ad %ae %s' 2023-09-25 junyer Add Clang 17 to the build matrix. Created with: roll-dep external/re2 * Roll external/spirv-headers/ fc7d24627..79743b899 (3 commits) https://github.com/KhronosGroup/SPIRV-Headers/compare/fc7d24627651...79743b899fde $ git log fc7d24627..79743b899 --date=short --no-merges --format='%ad %ae %s' 2023-09-20 fwahlster Add LiteralFloat to operand_kinds (#380) 2023-09-20 40001162+alelenv Add headers for SPV_NV_displacement_micromap. (#374) 2023-09-20 fwahlster remove additional version "1.0" from SecondaryViewportRelativeNV (#379) Created with: roll-dep external/spirv-headers --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index 74c5cd99dc..eb1b947db4 100644 --- a/DEPS +++ b/DEPS @@ -7,13 +7,13 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': 'adc514538678a61b13c240f7b41babbc03b2ac24', + 'googletest_revision': 'e47544ad31cb3ceecd04cc13e8fe556f8df9fe0b', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '09de536bb7c77c2e0869a001f012d49560f56cbe', - 'spirv_headers_revision': 'fc7d2462765183c784a0c46beb13eee9e506a067', + 're2_revision': '26f7d889e1f7e75e95e65490086538edf9f5275c', + 'spirv_headers_revision': '79743b899fde5c954897b2694291002626358fac', } deps = { From 1bc0e6f59abc3c9cd75f93baef47e9612a448045 Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Wed, 27 Sep 2023 16:54:10 -0700 Subject: [PATCH 46/95] Add a new legalization pass to dedupe invocation interlock instructions (#5409) Add a new legalization pass to dedupe invocation interlock instructions DXC will be adding support for HLSL's rasterizer ordered views by using the SPV_EXT_fragment_shader_interlock_extension. That extension stipulates that if an entry point has an interlock ordering execution mode, it must dynamically execute OpBeginInvocationInterlockEXT and OpEndInvocationInterlockEXT, in that order, exactly once. This would be difficult to determine in DXC's SPIR-V backend, so instead we will emit these instructions potentially multiple times, and use this legalization pass to ensure that the final SPIR-V follows the specification. This PR uses data-flow analysis to determine where to place begin and end instructions; in essence, determining whether a block contains or is preceded by a begin instruction is similar to a specialized case of a reaching definitions analysis, where we have only a single definition, such as `bool has_begun = false`. For this simpler case, we can compute the set of blocks using BFS to determine the reachability of the begin instruction. We need to do this for both begin and end instructions, so I have generalized portions of the code to run both forward and backward over the CFG for each respective case. --- Android.mk | 1 + BUILD.gn | 1 + include/spirv-tools/optimizer.hpp | 6 + source/opt/CMakeLists.txt | 2 + .../invocation_interlock_placement_pass.cpp | 493 ++++++++++++++ .../opt/invocation_interlock_placement_pass.h | 158 +++++ source/opt/optimizer.cpp | 8 +- source/opt/passes.h | 1 + test/opt/CMakeLists.txt | 1 + .../invocation_interlock_placement_test.cpp | 613 ++++++++++++++++++ 10 files changed, 1283 insertions(+), 1 deletion(-) create mode 100644 source/opt/invocation_interlock_placement_pass.cpp create mode 100644 source/opt/invocation_interlock_placement_pass.h create mode 100644 test/opt/invocation_interlock_placement_test.cpp diff --git a/Android.mk b/Android.mk index 0a875e977f..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 \ diff --git a/BUILD.gn b/BUILD.gn index 1997e708f0..7a8cc8e8e3 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -693,6 +693,7 @@ 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/ir_builder.h", "source/opt/ir_context.cpp", "source/opt/ir_context.h", diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp index ef639524cd..53ebc59f00 100644 --- a/include/spirv-tools/optimizer.hpp +++ b/include/spirv-tools/optimizer.hpp @@ -994,6 +994,12 @@ Optimizer::PassToken CreateTrimCapabilitiesPass(); // 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/opt/CMakeLists.txt b/source/opt/CMakeLists.txt index 8c903eca82..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 @@ -191,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 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/optimizer.cpp b/source/opt/optimizer.cpp index afff9ece43..2a7c4110b2 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -158,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() { @@ -1113,6 +1114,11 @@ 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 83caa4a77d..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" diff --git a/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt index 3a56e93087..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 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 From dc9900967d51cd82de0c5ae644b1c3947c9c9b85 Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Mon, 2 Oct 2023 06:39:31 -0700 Subject: [PATCH 47/95] Update BUILD.gn to include header for new pass (#5421) Fixes #5420 --- BUILD.gn | 1 + 1 file changed, 1 insertion(+) diff --git a/BUILD.gn b/BUILD.gn index 7a8cc8e8e3..9ff36d83db 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -694,6 +694,7 @@ static_library("spvtools_opt") { "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", From 847715d6c65200987c079fb13ca7925760faec23 Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Mon, 2 Oct 2023 09:15:39 -0600 Subject: [PATCH 48/95] instrument: Ensure linking works even of nothing is changed (#5419) spirv-link requires that memory models match between its input files. Ensure this is the case by always returning SuccessWithChange and always changing the memory model to match the instrumentation code in Vulkan-ValidationLayers. Also, disable the DCE pass in the --inst-* command line options, since it will only work after linking. --- source/opt/inst_bindless_check_pass.cpp | 7 ++++--- source/opt/inst_buff_addr_check_pass.cpp | 14 +++++++++----- source/opt/optimizer.cpp | 2 -- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp index f84d5b2985..8e7d4f83e8 100644 --- a/source/opt/inst_bindless_check_pass.cpp +++ b/source/opt/inst_bindless_check_pass.cpp @@ -724,7 +724,6 @@ 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(); @@ -747,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_buff_addr_check_pass.cpp b/source/opt/inst_buff_addr_check_pass.cpp index e1fde77133..e6c550878a 100644 --- a/source/opt/inst_buff_addr_check_pass.cpp +++ b/source/opt/inst_buff_addr_check_pass.cpp @@ -301,6 +301,11 @@ Pass::Status InstBuffAddrCheckPass::ProcessImpl() { 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 @@ -311,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/optimizer.cpp b/source/opt/optimizer.cpp index 2a7c4110b2..675bd1bd94 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -439,10 +439,8 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterPass(CreateSimplificationPass()); RegisterPass(CreateDeadBranchElimPass()); RegisterPass(CreateBlockMergePass()); - RegisterPass(CreateAggressiveDCEPass(true)); } else if (pass_name == "inst-buff-addr-check") { RegisterPass(CreateInstBuffAddrCheckPass(23)); - RegisterPass(CreateAggressiveDCEPass(true)); } else if (pass_name == "convert-relaxed-to-half") { RegisterPass(CreateConvertRelaxedToHalfPass()); } else if (pass_name == "relax-float-ops") { From 4fab7435bf2e1be1abb6d308bdd6298ac95de88d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 4 Oct 2023 01:42:27 -0700 Subject: [PATCH 49/95] Roll external/googletest/ e47544ad3..beb552fb4 (2 commits) (#5424) https://github.com/google/googletest/compare/e47544ad31cb...beb552fb47e9 $ git log e47544ad3..beb552fb4 --date=short --no-merges --format='%ad %ae %s' 2023-10-03 dinor gmock_cook_book: Document `DoAll`'s return type requirement 2023-09-29 dzimitriy cmake: Fix comments in cmake files Created with: roll-dep external/googletest Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index eb1b947db4..5a490e343c 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': 'e47544ad31cb3ceecd04cc13e8fe556f8df9fe0b', + 'googletest_revision': 'beb552fb47e9e8a6ddab20526663c2dddd601ec6', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From 023a8c79e9ae54478790d14429822fc07cb8ed5e Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Thu, 5 Oct 2023 02:12:09 -0700 Subject: [PATCH 50/95] opt: add Float64 capability to trim pass (#5428) --- source/opt/trim_capabilities_pass.cpp | 14 ++++++++- source/opt/trim_capabilities_pass.h | 1 + test/opt/trim_capabilities_pass_test.cpp | 39 ++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/source/opt/trim_capabilities_pass.cpp b/source/opt/trim_capabilities_pass.cpp index 4b3d74af65..5df1999140 100644 --- a/source/opt/trim_capabilities_pass.cpp +++ b/source/opt/trim_capabilities_pass.cpp @@ -36,6 +36,7 @@ namespace spvtools { namespace opt { namespace { +constexpr uint32_t kOpTypeFloatSizeIndex = 0; constexpr uint32_t kOpTypePointerStorageClassIndex = 0; constexpr uint32_t kTypeArrayTypeIndex = 0; constexpr uint32_t kOpTypeScalarBitWidthIndex = 0; @@ -132,6 +133,16 @@ static bool Has16BitCapability(const FeatureManager* feature_manager) { // Handler names follow the following convention: // Handler__() +static std::optional Handler_OpTypeFloat_Float64( + const Instruction* instruction) { + assert(instruction->opcode() == spv::Op::OpTypeFloat && + "This handler only support OpTypeFloat opcodes."); + + 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 && @@ -286,8 +297,9 @@ static std::optional Handler_OpTypeImage_ImageMSArray( } // Opcode of interest to determine capabilities requirements. -constexpr std::array, 7> kOpcodeHandlers{{ +constexpr std::array, 8> kOpcodeHandlers{{ // clang-format off + {spv::Op::OpTypeFloat, Handler_OpTypeFloat_Float64 }, {spv::Op::OpTypeImage, Handler_OpTypeImage_ImageMSArray}, {spv::Op::OpTypeInt, Handler_OpTypeInt_Int64 }, {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageInputOutput16}, diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index b9ad7a938e..9202b2e9af 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -74,6 +74,7 @@ class TrimCapabilitiesPass : public Pass { // contains unsupported instruction, the pass could yield bad results. static constexpr std::array kSupportedCapabilities{ // clang-format off + spv::Capability::Float64, spv::Capability::FragmentShaderPixelInterlockEXT, spv::Capability::FragmentShaderSampleInterlockEXT, spv::Capability::FragmentShaderShadingRateInterlockEXT, diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index d7bdafe1c0..8aaf860dc9 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -2090,6 +2090,45 @@ TEST_F(TrimCapabilitiesPassTest, ImageMSArray_RemovedIfSampledNot2) { 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); +} + } // namespace } // namespace opt } // namespace spvtools From 866e60defc05326c5cf0ad711ec453dd25e6edec Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 5 Oct 2023 11:58:05 -0400 Subject: [PATCH 51/95] Roll external/spirv-headers/ 79743b899..e867c0663 (2 commits) (#5427) https://github.com/KhronosGroup/SPIRV-Headers/compare/79743b899fde...e867c0663176 $ git log 79743b899..e867c0663 --date=short --no-merges --format='%ad %ae %s' 2023-10-04 95509728+pradyumans Add a Source Language for Slang (#383) 2023-10-04 95509728+pradyumans Register Slang Compiler for SPIR-V (#382) Created with: roll-dep external/spirv-headers Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 5a490e343c..cc77744df0 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': '26f7d889e1f7e75e95e65490086538edf9f5275c', - 'spirv_headers_revision': '79743b899fde5c954897b2694291002626358fac', + 'spirv_headers_revision': 'e867c06631767a2d96424cbec530f9ee5e78180f', } deps = { From df2f2a0313bf4b960aa25ddeefbf9cb46d7c8705 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Oct 2023 13:16:31 -0400 Subject: [PATCH 52/95] build(deps): bump get-func-name from 2.0.0 to 2.0.2 in /tools/sva (#5418) Bumps [get-func-name](https://github.com/chaijs/get-func-name) from 2.0.0 to 2.0.2. - [Release notes](https://github.com/chaijs/get-func-name/releases) - [Commits](https://github.com/chaijs/get-func-name/commits/v2.0.2) --- updated-dependencies: - dependency-name: get-func-name dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/sva/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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" From ce995b319e0adf3f6c863342af17ec84fa6b3dfb Mon Sep 17 00:00:00 2001 From: Joyce Date: Thu, 5 Oct 2023 14:18:28 -0300 Subject: [PATCH 53/95] Hash pin workflows and config dependabot (#5412) * Step Security: hash pin and dependabot Signed-off-by: Joyce Brum * add license to dependabot.yml Signed-off-by: Joyce --------- Signed-off-by: Joyce Brum Signed-off-by: Joyce --- .github/dependabot.yml | 25 +++++++++++++++++++++++++ .github/workflows/autoroll.yml | 2 +- .github/workflows/bazel.yml | 4 ++-- .github/workflows/release.yml | 2 +- .github/workflows/wasm.yml | 2 +- 5 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 .github/dependabot.yml 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 e5a7ee0814..ab38975324 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@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 # Checkout the depot tools they are needed by roll_deps.sh - name: Checkout depot tools diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 5c353718e7..7ab0f0e2c8 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@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 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/release.yml b/.github/workflows/release.yml index ada943169e..ac8bade0fb 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@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: Prepare CHANGELOG for version run: | python utils/generate_changelog.py CHANGES "${{ github.ref_name }}" VERSION_CHANGELOG diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 62c9af3842..f031e6c16a 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@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: fetch-depth: '0' - name: Build web From 933db564ca660477b360480b8a1d7589d7c6694e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 10:01:14 +0000 Subject: [PATCH 54/95] roll deps (#5432) * Roll external/googletest/ beb552fb4..2dd1c1319 (1 commit) https://github.com/google/googletest/compare/beb552fb47e9...2dd1c1319500 $ git log beb552fb4..2dd1c1319 --date=short --no-merges --format='%ad %ae %s' 2023-10-05 absl-team Fix RE::Init for Android and NetBSD. Created with: roll-dep external/googletest * Roll external/re2/ 26f7d889e..35bb195de (1 commit) https://github.com/google/re2/compare/26f7d889e1f7...35bb195dec32 $ git log 26f7d889e..35bb195de --date=short --no-merges --format='%ad %ae %s' 2023-10-05 junyer Update Unicode data to 15.1.0. Created with: roll-dep external/re2 --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index cc77744df0..13095e3a54 100644 --- a/DEPS +++ b/DEPS @@ -7,12 +7,12 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': 'beb552fb47e9e8a6ddab20526663c2dddd601ec6', + 'googletest_revision': '2dd1c131950043a8ad5ab0d2dda0e0970596586a', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '26f7d889e1f7e75e95e65490086538edf9f5275c', + 're2_revision': '35bb195dec329ab061472b19b0f4cb68ab3dde0a', 'spirv_headers_revision': 'e867c06631767a2d96424cbec530f9ee5e78180f', } From 74005dfa67c48ac9c20dd7fce848166f40d02473 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 10 Oct 2023 20:30:48 +0000 Subject: [PATCH 55/95] Roll external/re2/ 35bb195de..b673de358 (2 commits) (#5433) https://github.com/google/re2/compare/35bb195dec32...b673de35837a $ git log 35bb195de..b673de358 --date=short --no-merges --format='%ad %ae %s' 2023-10-06 junyer Clean up some fuzzer-related cruft. 2023-10-05 allenwebb Use a variable for `PKG_CONFIG` for distros that cross-compile. Created with: roll-dep external/re2 Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 13095e3a54..3d6f3314cc 100644 --- a/DEPS +++ b/DEPS @@ -12,7 +12,7 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '35bb195dec329ab061472b19b0f4cb68ab3dde0a', + 're2_revision': 'b673de35837aad63146957b9c305dbdbd82ce6b7', 'spirv_headers_revision': 'e867c06631767a2d96424cbec530f9ee5e78180f', } From 360d469b9eac54d6c6e20f609f9ec35e3a5380ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Wed, 11 Oct 2023 17:43:50 +0200 Subject: [PATCH 56/95] Prepare release v2023.5.rc1 (#5423) Prepare release v2023.5.rc1 --- CHANGES | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/CHANGES b/CHANGES index 97caaee192..a7929eba34 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,32 @@ Revision history for SPIRV-Tools +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) From 661f429b11e4392139a6c0630ceb3e3182cdb0f4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 11 Oct 2023 19:14:22 +0000 Subject: [PATCH 57/95] Roll external/re2/ b673de358..ece4cecab (2 commits) (#5437) https://github.com/google/re2/compare/b673de35837a...ece4cecab5c8 $ git log b673de358..ece4cecab --date=short --no-merges --format='%ad %ae %s' 2023-10-10 junyer Enable parse headers features. Enforcing that headers are self-contained. 2023-10-10 junyer Enable layering check features. Useful on Clang only. Created with: roll-dep external/re2 Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 3d6f3314cc..6e3c67e231 100644 --- a/DEPS +++ b/DEPS @@ -12,7 +12,7 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': 'b673de35837aad63146957b9c305dbdbd82ce6b7', + 're2_revision': 'ece4cecab5c8445d93abd98d88c899f370b4ea4a', 'spirv_headers_revision': 'e867c06631767a2d96424cbec530f9ee5e78180f', } From 3985f0da0c38e21f32200aff3c033a646fc93a55 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 16 Oct 2023 14:43:23 +0000 Subject: [PATCH 58/95] Roll external/spirv-headers/ e867c0663..4183b260f (1 commit) (#5439) https://github.com/KhronosGroup/SPIRV-Headers/compare/e867c0663176...4183b260f4cc $ git log e867c0663..4183b260f --date=short --no-merges --format='%ad %ae %s' 2023-10-11 89833130+rjodinchr ClspvReflection non-sematic: add NormalizedSamplerMaskPushConstant (#377) Created with: roll-dep external/spirv-headers Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 6e3c67e231..77c86f6073 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': 'ece4cecab5c8445d93abd98d88c899f370b4ea4a', - 'spirv_headers_revision': 'e867c06631767a2d96424cbec530f9ee5e78180f', + 'spirv_headers_revision': '4183b260f4cccae52a89efdfcdd43c4897989f42', } deps = { From 5bb595091b3048d20afeb37a9a193350dccd607d Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Mon, 16 Oct 2023 12:03:33 -0700 Subject: [PATCH 59/95] Add ComputeDerivativeGroup*NV capabilities to trim capabilities pass. (#5430) * Add ComputeDerivativeGroup*NV capabilities to trim capabilities pass. * Add SPV_NV_compute_shader_derivatives to allow lists No tests needed for this. The code path is well tested. Just adding new data. --- source/opt/aggressive_dead_code_elim_pass.cpp | 4 ++ .../opt/local_access_chain_convert_pass.cpp | 3 +- source/opt/local_single_block_elim_pass.cpp | 3 +- source/opt/local_single_store_elim_pass.cpp | 3 +- source/opt/trim_capabilities_pass.h | 4 +- test/opt/trim_capabilities_pass_test.cpp | 57 +++++++++++++++++++ 6 files changed, 70 insertions(+), 4 deletions(-) diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp index 55feca811e..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", @@ -1001,7 +1003,9 @@ void AggressiveDCEPass::InitExtensions() { "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/local_access_chain_convert_pass.cpp b/source/opt/local_access_chain_convert_pass.cpp index fac4cea64f..ea1bdeeb3b 100644 --- a/source/opt/local_access_chain_convert_pass.cpp +++ b/source/opt/local_access_chain_convert_pass.cpp @@ -428,7 +428,8 @@ void LocalAccessChainConvertPass::InitExtensions() { "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_EXT_fragment_shader_interlock"}); + "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 0acffda335..7502d0497e 100644 --- a/source/opt/local_single_block_elim_pass.cpp +++ b/source/opt/local_single_block_elim_pass.cpp @@ -289,7 +289,8 @@ void LocalSingleBlockLoadStoreElimPass::InitExtensions() { "SPV_KHR_vulkan_memory_model", "SPV_NV_bindless_texture", "SPV_EXT_shader_atomic_float_add", - "SPV_EXT_fragment_shader_interlock"}); + "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 77b3420ce9..f6fc2760e0 100644 --- a/source/opt/local_single_store_elim_pass.cpp +++ b/source/opt/local_single_store_elim_pass.cpp @@ -139,7 +139,8 @@ void LocalSingleStoreElimPass::InitExtensionAllowList() { "SPV_KHR_vulkan_memory_model", "SPV_NV_bindless_texture", "SPV_EXT_shader_atomic_float_add", - "SPV_EXT_fragment_shader_interlock"}); + "SPV_EXT_fragment_shader_interlock", + "SPV_NV_compute_shader_derivatives"}); } bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) { std::vector users; diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index 9202b2e9af..92777a229d 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -91,7 +91,9 @@ class TrimCapabilitiesPass : public Pass { spv::Capability::StoragePushConstant16, spv::Capability::StorageUniform16, spv::Capability::StorageUniformBufferBlock16, - spv::Capability::ImageMSArray + spv::Capability::ImageMSArray, + spv::Capability::ComputeDerivativeGroupQuadsNV, + spv::Capability::ComputeDerivativeGroupLinearNV // clang-format on }; diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index 8aaf860dc9..8f49c55cbe 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 @@ -2129,6 +2133,59 @@ TEST_F(TrimCapabilitiesPassTest, Float64_RemainsWhenUsed) { 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); +} + } // namespace } // namespace opt } // namespace spvtools From a9c61d1376854031a7d6265defb4cdded00e9d48 Mon Sep 17 00:00:00 2001 From: Fumitoshi Ukai Date: Thu, 19 Oct 2023 01:49:51 +0900 Subject: [PATCH 60/95] update_build_version.py produce deterministic header. (#5426) When building, .git directory may not exist in current directory (e.g. chromium build), so it will produce with current timestamp, which becomes non-deterministic build. Check if repo_path is in git repository and use git info. Also fix fallback logic when 'git describe' failed. 'git rev-parse HEAD' result was not used because it didn't update success. --- utils/update_build_version.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/utils/update_build_version.py b/utils/update_build_version.py index 1d7f565150..ea8020c79d 100755 --- a/utils/update_build_version.py +++ b/utils/update_build_version.py @@ -112,10 +112,11 @@ def describe(repo_path): successful, returns the output; otherwise returns 'unknown hash, '.""" # if we're in a git repository, attempt to extract version info - if os.path.exists(".git"): + success, output = command_output(["git", "rev-parse", "--show-toplevel"], repo_path) + if success: success, output = command_output(["git", "describe"], repo_path) if not success: - output = command_output(["git", "rev-parse", "HEAD"], repo_path) + success, output = command_output(["git", "rev-parse", "HEAD"], repo_path) if success: # decode() is needed here for Python3 compatibility. In Python2, From 5084f58e5d187b16f84d2af936ff94ea2f46a00c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:56:29 -0400 Subject: [PATCH 61/95] build(deps): bump the github-actions group with 4 updates (#5445) Bumps the github-actions group with 4 updates: [actions/checkout](https://github.com/actions/checkout), [ossf/scorecard-action](https://github.com/ossf/scorecard-action), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [github/codeql-action](https://github.com/github/codeql-action). Updates `actions/checkout` from 3.1.0 to 4.1.1 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3.1.0...b4ffde65f46336ab88eb53be808477a3936bae11) Updates `ossf/scorecard-action` from 2.1.2 to 2.3.0 - [Release notes](https://github.com/ossf/scorecard-action/releases) - [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md) - [Commits](https://github.com/ossf/scorecard-action/compare/e38b1902ae4f44df626f11ba0734b14fb91f8f86...483ef80eb98fb506c348f7d62e28055e49fe2398) Updates `actions/upload-artifact` from 3.1.0 to 3.1.3 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/3cea5372237819ed00197afe530f5a7ea3e805c8...a8a3f3ad30e3422c9c7b888a15615d19a852ae32) Updates `github/codeql-action` from 2.2.4 to 2.22.3 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/17573ee1cc1b9d061760f3a006fc4aac4f944fd5...0116bc2df50751f9724a2e35ef1f24d22f90e4e1) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: ossf/scorecard-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/autoroll.yml | 2 +- .github/workflows/bazel.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/scorecard.yml | 8 ++++---- .github/workflows/wasm.yml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/autoroll.yml b/.github/workflows/autoroll.yml index ab38975324..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@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 # Checkout the depot tools they are needed by roll_deps.sh - name: Checkout depot tools diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 7ab0f0e2c8..347f884ff5 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -18,7 +18,7 @@ jobs: runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: '0' - name: Download dependencies diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ac8bade0fb..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@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - 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 index b45d0915f2..82e79d672f 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -23,12 +23,12 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86 # v2.1.2 + uses: ossf/scorecard-action@483ef80eb98fb506c348f7d62e28055e49fe2398 # v2.3.0 with: results_file: results.sarif results_format: sarif @@ -40,7 +40,7 @@ jobs: # 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@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 with: name: SARIF file path: results.sarif @@ -48,6 +48,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4 + uses: github/codeql-action/upload-sarif@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3 with: sarif_file: results.sarif diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index f031e6c16a..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@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: '0' - name: Build web From 73876defc8d9bd7ff42d5f71b15eb3db0cf86c65 Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Thu, 19 Oct 2023 13:02:46 -0700 Subject: [PATCH 62/95] opt: support 64-bit OpAccessChain index in FixStorageClass (#5446) The SPIR-V specification allows any scalar integer type as an index. DXC usually emits indexes as 32-bit integer types, however, in some cases it is possible to make it emit 64-bit indexes instead (as in https://github.com/microsoft/DirectXShaderCompiler/issues/5638). --- source/opt/fix_storage_class.cpp | 8 +++++- test/opt/fix_storage_class_test.cpp | 41 +++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) 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/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 From 1928c76cd6a5a6aa41a8fdb862dc23effb597748 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Oct 2023 06:07:08 +0000 Subject: [PATCH 63/95] Roll external/googletest/ 2dd1c1319..829c19901 (1 commit) (#5444) * Roll external/googletest/ 2dd1c1319..116b7e552 (3 commits) https://github.com/google/googletest/compare/2dd1c1319500...116b7e55281c $ git log 2dd1c1319..116b7e552 --date=short --no-merges --format='%ad %ae %s' 2023-10-19 absl-team Improve error message for invalid parameterized test names. 2023-10-17 absl-team s/::testing::/testing::/ in test documentation outside of using statements to align with best practice 2023-10-17 dinor gtest-death-test-internal: Delete obsolete string constants Created with: roll-dep external/googletest * Roll external/re2/ ece4cecab..928a015e6 (1 commit) https://github.com/google/re2/compare/ece4cecab5c8...928a015e6ecc $ git log ece4cecab..928a015e6 --date=short --no-merges --format='%ad %ae %s' 2023-10-18 junyer Improve comments about `absl::optional` support. Created with: roll-dep external/re2 * Roll external/spirv-headers/ 4183b260f..88bc5e321 (1 commit) https://github.com/KhronosGroup/SPIRV-Headers/compare/4183b260f4cc...88bc5e321c28 $ git log 4183b260f..88bc5e321 --date=short --no-merges --format='%ad %ae %s' 2023-10-18 bertrand.wlodarczyk Headers support for new FPGAMemoryAttributesINTEL (#384) Created with: roll-dep external/spirv-headers --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index 77c86f6073..3898910fa8 100644 --- a/DEPS +++ b/DEPS @@ -7,13 +7,13 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '2dd1c131950043a8ad5ab0d2dda0e0970596586a', + 'googletest_revision': '116b7e55281c4200151524b093ecc03757a4ffda', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': 'ece4cecab5c8445d93abd98d88c899f370b4ea4a', - 'spirv_headers_revision': '4183b260f4cccae52a89efdfcdd43c4897989f42', + 're2_revision': '928a015e6ecc02519abb5d4a8732099545c48346', + 'spirv_headers_revision': '88bc5e321c2839707df8b1ab534e243e00744177', } deps = { From 01e851be93a4be2d91194ed6ec8626038aae5bfb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 21 Oct 2023 07:55:37 +0000 Subject: [PATCH 64/95] Roll external/re2/ 928a015e6..601d9ea3e (1 commit) (#5448) https://github.com/google/re2/compare/928a015e6ecc...601d9ea3e6a7 $ git log 928a015e6..601d9ea3e --date=short --no-merges --format='%ad %ae %s' 2023-10-20 junyer Set `SOURCE_DATE_EPOCH` for reproducible builds. Created with: roll-dep external/re2 Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 3898910fa8..9ea4d17842 100644 --- a/DEPS +++ b/DEPS @@ -12,7 +12,7 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '928a015e6ecc02519abb5d4a8732099545c48346', + 're2_revision': '601d9ea3e6a768cb666e71012f0baf812a2d48da', 'spirv_headers_revision': '88bc5e321c2839707df8b1ab534e243e00744177', } From 33bac514432c2ecc138556a976075d87b8f25a5f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 25 Oct 2023 21:37:34 +0000 Subject: [PATCH 65/95] Roll external/googletest/ 116b7e552..518387203 (1 commit) (#5450) https://github.com/google/googletest/compare/116b7e55281c...518387203b57 $ git log 116b7e552..518387203 --date=short --no-merges --format='%ad %ae %s' 2023-10-23 dinor StartsWith: Explicitly construct matcher-typed strings from matchee parameter Created with: roll-dep external/googletest Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 9ea4d17842..e8d5f40f29 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '116b7e55281c4200151524b093ecc03757a4ffda', + 'googletest_revision': '518387203b573f35477fa6872dd54620e70d2bdb', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From 4f014aff9c653e5e16de1cc5f7130e99e02982e5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 26 Oct 2023 06:40:22 +0000 Subject: [PATCH 66/95] Roll external/re2/ 601d9ea3e..a0b3bc60c (1 commit) (#5453) https://github.com/google/re2/compare/601d9ea3e6a7...a0b3bc60c3a4 $ git log 601d9ea3e..a0b3bc60c --date=short --no-merges --format='%ad %ae %s' 2023-10-25 junyer Add support for Python 3.12. Created with: roll-dep external/re2 Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index e8d5f40f29..f867b28474 100644 --- a/DEPS +++ b/DEPS @@ -12,7 +12,7 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '601d9ea3e6a768cb666e71012f0baf812a2d48da', + 're2_revision': 'a0b3bc60c3a42b4e572bf643fa0e10bf60dcc872', 'spirv_headers_revision': '88bc5e321c2839707df8b1ab534e243e00744177', } From c87755bb9fb5df188775738996d0eac56b2ebcb9 Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Wed, 1 Nov 2023 23:48:40 +0900 Subject: [PATCH 67/95] spirv-val: Add WorkgroupMemoryExplicitLayoutKHR check for Block (#5461) --- source/val/validate_decorations.cpp | 13 +++++++++--- test/val/val_decoration_test.cpp | 32 +++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) 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/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 From a08f648c86fd7e9a16d55405530cda0dd259a7b2 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 1 Nov 2023 15:19:48 -0700 Subject: [PATCH 68/95] Remove references to __FILE__ (#5462) * Remove references to __FILE__ Uses of `__FILE__` leak the directory structure of the machine used to build because it adds a string to the string table with the full path name. I've removed the uses that show up in the release builds. Fixes #5416 --- BUILD.bazel | 14 ---------- source/opt/log.h | 27 +++++-------------- source/opt/type_manager.cpp | 6 ++--- test/CMakeLists.txt | 1 - test/log_test.cpp | 53 ------------------------------------- 5 files changed, 9 insertions(+), 92 deletions(-) delete mode 100644 test/log_test.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/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/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/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/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 From 7210d247cdf4040ae141ab8df8c71deba8c881a3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 2 Nov 2023 14:02:47 +0000 Subject: [PATCH 69/95] Roll external/googletest/ 518387203..5b7fd63d6 (1 commit) (#5454) * Roll external/googletest/ 518387203..b10fad38c (2 commits) https://github.com/google/googletest/compare/518387203b57...b10fad38c402 $ git log 518387203..b10fad38c --date=short --no-merges --format='%ad %ae %s' 2023-10-26 absl-team Export gmock-spec-builders. 2023-10-25 theorbuehler Add missing include for raise(3) Created with: roll-dep external/googletest * Roll external/re2/ a0b3bc60c..24d460a9d (6 commits) https://github.com/google/re2/compare/a0b3bc60c3a4...24d460a9db60 $ git log a0b3bc60c..24d460a9d --date=short --no-merges --format='%ad %ae %s' 2023-11-01 vovkos Don't check `kind_ == Prog::kManyMatch` in `DFA::InlinedSearchLoop()`. 2023-11-01 junyer Replace a couple of `assert(3)` calls. 2023-10-31 junyer Prepare to tag release `2023-11-01`. 2023-10-27 junyer Bump some versions in `MODULE.bazel`. 2023-10-27 junyer Simplify `ci-cmake.yml` via `matrix`. 2023-10-27 junyer GitHub Actions now provides GCC 13. Created with: roll-dep external/re2 --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index f867b28474..8e86c2f6a0 100644 --- a/DEPS +++ b/DEPS @@ -7,12 +7,12 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '518387203b573f35477fa6872dd54620e70d2bdb', + 'googletest_revision': 'b10fad38c4026a29ea6561ab15fc4818170d1c10', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': 'a0b3bc60c3a42b4e572bf643fa0e10bf60dcc872', + 're2_revision': '24d460a9db6048b9d3e05cfdea13ec9d592545ad', 'spirv_headers_revision': '88bc5e321c2839707df8b1ab534e243e00744177', } From eacc969b7d15a48ef9b1c49b1773c6ce408b5411 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Nov 2023 10:05:53 -0400 Subject: [PATCH 70/95] build(deps): bump the github-actions group with 2 updates (#5457) Bumps the github-actions group with 2 updates: [ossf/scorecard-action](https://github.com/ossf/scorecard-action) and [github/codeql-action](https://github.com/github/codeql-action). Updates `ossf/scorecard-action` from 2.3.0 to 2.3.1 - [Release notes](https://github.com/ossf/scorecard-action/releases) - [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md) - [Commits](https://github.com/ossf/scorecard-action/compare/483ef80eb98fb506c348f7d62e28055e49fe2398...0864cf19026789058feabb7e87baa5f140aac736) Updates `github/codeql-action` from 2.22.3 to 2.22.5 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/0116bc2df50751f9724a2e35ef1f24d22f90e4e1...74483a38d39275f33fcff5f35b679b5ca4a26a99) --- updated-dependencies: - dependency-name: ossf/scorecard-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 82e79d672f..63ee9aae5e 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -28,7 +28,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@483ef80eb98fb506c348f7d62e28055e49fe2398 # v2.3.0 + uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 with: results_file: results.sarif results_format: sarif @@ -48,6 +48,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@0116bc2df50751f9724a2e35ef1f24d22f90e4e1 # v2.22.3 + uses: github/codeql-action/upload-sarif@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5 with: sarif_file: results.sarif From 9e7a1f2ddd65514f6edc8303bd909fa735054bcc Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 2 Nov 2023 10:29:57 -0700 Subject: [PATCH 71/95] Fix array size calculation (#5463) The function that get the number of elements in a composite variable returns an incorrect values for the arrays. This is fixed, so that it returns the correct number of elements for arrays where the number of elements is represented as a 32-bit integer and is known at compile time. Fixes #4953 --- source/opt/folding_rules.cpp | 15 +++++++++++---- test/opt/fold_test.cpp | 23 +++++++++++++++++++++-- 2 files changed, 32 insertions(+), 6 deletions(-) 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/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, From fbf047cc8b51d396d66c747f1eee472feb1b2441 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 9 Nov 2023 20:35:08 +0000 Subject: [PATCH 72/95] Roll external/re2/ 24d460a9d..974f44c8d (4 commits) (#5470) * Roll external/re2/ 24d460a9d..974f44c8d (4 commits) https://github.com/google/re2/compare/24d460a9db60...974f44c8d452 $ git log 24d460a9d..974f44c8d --date=short --no-merges --format='%ad %ae %s' 2023-11-07 junyer Bazel fails if the username is unknown. 2023-11-07 junyer A non-root user can't futz with `/usr/local/bin`. 2023-11-07 junyer Specify the UID, not the username. 2023-11-07 junyer Don't run as root within the container. Created with: roll-dep external/re2 * Roll external/spirv-headers/ 88bc5e321..38f39dae5 (1 commit) https://github.com/KhronosGroup/SPIRV-Headers/compare/88bc5e321c28...38f39dae5baa $ git log 88bc5e321..38f39dae5 --date=short --no-merges --format='%ad %ae %s' 2023-11-08 115671160+spencer-lunarg Fix SPV_KHR_workgroup_memory_explicit_layout implicit declare (#388) Created with: roll-dep external/spirv-headers --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 8e86c2f6a0..3442a17fa0 100644 --- a/DEPS +++ b/DEPS @@ -12,8 +12,8 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '24d460a9db6048b9d3e05cfdea13ec9d592545ad', - 'spirv_headers_revision': '88bc5e321c2839707df8b1ab534e243e00744177', + 're2_revision': '974f44c8d45242e710dc0a85a4defffdb3ce07fc', + 'spirv_headers_revision': '38f39dae5baaa24431b24ac659054ebe972fa1e6', } deps = { From 6b1e609ef1609ac695cc465374d7e50831c1937b Mon Sep 17 00:00:00 2001 From: Natalie Chouinard <1953083+sudonatalie@users.noreply.github.com> Date: Fri, 10 Nov 2023 18:43:11 -0500 Subject: [PATCH 73/95] Support missing git in update_build_version.py (#5473) Return False instead of raising an exception when running git commands fail, which allows the script to fallback to alternative options. Fixes #5469 --- utils/update_build_version.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/utils/update_build_version.py b/utils/update_build_version.py index ea8020c79d..68156bda4a 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 @@ -127,7 +124,8 @@ def describe(repo_path): 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 From d88742fbd8a2d4abed75679ab3338c869502955b Mon Sep 17 00:00:00 2001 From: sethp Date: Mon, 13 Nov 2023 08:28:30 -0800 Subject: [PATCH 74/95] fix(build): git describe all tagged versions (#5447) Previously, the version string would include `v2022.4-N-...` indicating N commits since the last annotated tag (`v2022.4`). This change broadens the search from just annotated tags to all tags that match `v*`, including the latest version `v2023.4.rc2`. See also: https://github.com/KhronosGroup/SPIRV-Tools/pull/5417#issuecomment-1764772856 --- utils/update_build_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/update_build_version.py b/utils/update_build_version.py index 68156bda4a..a61331ea25 100755 --- a/utils/update_build_version.py +++ b/utils/update_build_version.py @@ -111,7 +111,7 @@ def describe(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: - success, output = command_output(["git", "describe"], repo_path) + 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) From c91e9d09b5dba4461872cb4f0a40e95df699536d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 14 Nov 2023 15:29:31 +0100 Subject: [PATCH 75/95] opt: add StorageImageReadWithoutFormat to cap trim (#5475) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The StorageImageReadWithoutFormat capability is only required when an image type with the format set to Unknown is used with some specific OpImageRead or OpImageSparseRead instructions. This patch adds the required code to the capability trimming pass to remove the StorageImageReadWithoutFormat capability when not required. Signed-off-by: Nathan GauĂ«r --- source/opt/trim_capabilities_pass.cpp | 66 +++++++-- source/opt/trim_capabilities_pass.h | 1 + test/opt/trim_capabilities_pass_test.cpp | 180 +++++++++++++++++++++++ 3 files changed, 237 insertions(+), 10 deletions(-) diff --git a/source/opt/trim_capabilities_pass.cpp b/source/opt/trim_capabilities_pass.cpp index 5df1999140..05499471d4 100644 --- a/source/opt/trim_capabilities_pass.cpp +++ b/source/opt/trim_capabilities_pass.cpp @@ -42,9 +42,13 @@ constexpr uint32_t kTypeArrayTypeIndex = 0; constexpr uint32_t kOpTypeScalarBitWidthIndex = 0; constexpr uint32_t kTypePointerTypeIdInIndex = 1; constexpr uint32_t kOpTypeIntSizeIndex = 0; -constexpr uint32_t kOpTypeImageArrayedIndex = 3; +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. @@ -296,17 +300,59 @@ static std::optional Handler_OpTypeImage_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, 8> kOpcodeHandlers{{ +constexpr std::array, 10> kOpcodeHandlers{{ // clang-format off - {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}, + {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 }}; diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index 92777a229d..84eff6ef76 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -87,6 +87,7 @@ class TrimCapabilitiesPass : public Pass { spv::Capability::RayTraversalPrimitiveCullingKHR, spv::Capability::Shader, spv::Capability::ShaderClockKHR, + spv::Capability::StorageImageReadWithoutFormat, spv::Capability::StorageInputOutput16, spv::Capability::StoragePushConstant16, spv::Capability::StorageUniform16, diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index 8f49c55cbe..5636d5f933 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -2186,6 +2186,186 @@ TEST_F(TrimCapabilitiesPassTest, 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); +} + } // namespace } // namespace opt } // namespace spvtools From f43c464d536360163b78a9cf08ef8dac5fdeb8b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 14 Nov 2023 18:49:04 +0100 Subject: [PATCH 76/95] opt: add PhysicalStorageBufferAddresses to trim (#5476) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PhysicalStorageBufferAddresses capability can now be trimmed. From the spec, it seems any instruction enabled by this required some operand to have the PhysicalStorageBuffer storage class. This means checking the storage class is enough. Now, because the pass uses the grammar, we don't need to add any new logic. Signed-off-by: Nathan GauĂ«r --- source/opt/trim_capabilities_pass.h | 9 +- test/opt/trim_capabilities_pass_test.cpp | 120 +++++++++++++++++++++++ 2 files changed, 125 insertions(+), 4 deletions(-) diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index 84eff6ef76..73d5dc80d5 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -74,14 +74,18 @@ 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, @@ -91,10 +95,7 @@ class TrimCapabilitiesPass : public Pass { spv::Capability::StorageInputOutput16, spv::Capability::StoragePushConstant16, spv::Capability::StorageUniform16, - spv::Capability::StorageUniformBufferBlock16, - spv::Capability::ImageMSArray, - spv::Capability::ComputeDerivativeGroupQuadsNV, - spv::Capability::ComputeDerivativeGroupLinearNV + spv::Capability::StorageUniformBufferBlock16 // clang-format on }; diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index 5636d5f933..14a8aa3a56 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -2366,6 +2366,126 @@ TEST_F(TrimCapabilitiesPassTest, 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 From 8ee3ae5244f5c3fd09ca43b2a7c0d178b6960a18 Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Wed, 15 Nov 2023 03:00:54 +0900 Subject: [PATCH 77/95] Add comment to --inst-debug-printf option (#5466) --- source/opt/optimizer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index 675bd1bd94..d00b87c3be 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -446,6 +446,11 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { } 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()); From c8510a5e890efc019102f497992e395374f15129 Mon Sep 17 00:00:00 2001 From: ncesario-lunarg <71668273+ncesario-lunarg@users.noreply.github.com> Date: Wed, 15 Nov 2023 08:36:36 -0700 Subject: [PATCH 78/95] Fix python warning seen on Fedora 39 (#5474) Python 3.12 on Fedora 39 is producing a deprecation warning about datetime.utcfromtimestamp. See https://docs.python.org/3/library/datetime.html#datetime.datetime.utcfromtimestamp for more details. --- utils/update_build_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/update_build_version.py b/utils/update_build_version.py index a61331ea25..f3d05b5d31 100755 --- a/utils/update_build_version.py +++ b/utils/update_build_version.py @@ -131,7 +131,7 @@ def describe(repo_path): # 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(): From 560eea6d75f709905319d7eb1e45adb6ee3efa08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:28:57 -0500 Subject: [PATCH 79/95] build(deps): bump the github-actions group with 1 update (#5478) Bumps the github-actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action). - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/74483a38d39275f33fcff5f35b679b5ca4a26a99...689fdc5193eeb735ecb2e52e819e3382876f93f4) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 63ee9aae5e..199f1bfbac 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -48,6 +48,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5 + uses: github/codeql-action/upload-sarif@689fdc5193eeb735ecb2e52e819e3382876f93f4 # v2.22.6 with: sarif_file: results.sarif From fb91e6f0eba66be08a5ece5ec389137762096702 Mon Sep 17 00:00:00 2001 From: Jesse Natalie Date: Wed, 15 Nov 2023 09:02:00 -0800 Subject: [PATCH 80/95] Flush stdout before changing mode back to text (#5477) --- tools/io.h | 1 + 1 file changed, 1 insertion(+) 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_); From 0df791f97ac51f158d093e560ee7fba236d9fe84 Mon Sep 17 00:00:00 2001 From: ChristianReinbold <32750401+ChristianReinbold@users.noreply.github.com> Date: Thu, 16 Nov 2023 20:36:32 +0100 Subject: [PATCH 81/95] Fix nullptr argument in MarkInsertChain (#5465) Fixes an access violation issue that sporadically occured for me when DXC uses spirv-opt to legalize generated spirv code. --- source/opt/dead_insert_elim_pass.cpp | 3 +- test/opt/dead_insert_elim_test.cpp | 107 +++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 1 deletion(-) 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/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: // From 246e6d4c68151e1e92036783d1578a57bc488782 Mon Sep 17 00:00:00 2001 From: Sajjad Mirza <90873047+sajjadmirzanv@users.noreply.github.com> Date: Fri, 17 Nov 2023 07:22:46 -0800 Subject: [PATCH 82/95] spirv-val: Loosen restriction on base type of DebugTypePointer and DebugTypeQualifier (#5479) * Allow base type for DebugTypePointer and DebugTypeQualifier to be any DebugType --- source/val/validate_extensions.cpp | 22 +++++++++++----------- test/val/val_ext_inst_debug_test.cpp | 18 +++++++++--------- 2 files changed, 20 insertions(+), 20 deletions(-) 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/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) { From 2a238ed24dffd84fe3ed2e60d7aa5c28e2acf45a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 18 Nov 2023 05:06:35 +0000 Subject: [PATCH 83/95] Roll external/spirv-headers/ 38f39dae5..cca08c63c (2 commits) (#5480) * Roll external/re2/ 974f44c8d..7e0c1a9e2 (1 commit) https://github.com/google/re2/compare/974f44c8d452...7e0c1a9e2417 $ git log 974f44c8d..7e0c1a9e2 --date=short --no-merges --format='%ad %ae %s' 2023-11-16 junyer WebAssembly support for threads is... fraught at every level. Created with: roll-dep external/re2 * Roll external/spirv-headers/ 38f39dae5..cca08c63c (2 commits) https://github.com/KhronosGroup/SPIRV-Headers/compare/38f39dae5baa...cca08c63cefa $ git log 38f39dae5..cca08c63c --date=short --no-merges --format='%ad %ae %s' 2023-11-15 viktoria.maksimova Change token IDs for global_variable_fpga_decorations and global_variable_host_access (#389) 2023-11-15 johnkslang It seems d790ced752b5bfc06b6988baadef6eb2d16bdf96 add tabs. (#390) Created with: roll-dep external/spirv-headers --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 3442a17fa0..0b06cffd1c 100644 --- a/DEPS +++ b/DEPS @@ -12,8 +12,8 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '974f44c8d45242e710dc0a85a4defffdb3ce07fc', - 'spirv_headers_revision': '38f39dae5baaa24431b24ac659054ebe972fa1e6', + 're2_revision': '7e0c1a9e2417e70e5f0efc323267ac71d1fa0685', + 'spirv_headers_revision': 'cca08c63cefa129d082abca0302adcb81610b465', } deps = { From 7d2a618bf9f894be1535fdca9f5952fef06adcb0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Nov 2023 15:17:19 -0500 Subject: [PATCH 84/95] build(deps): bump the github-actions group with 1 update (#5484) Bumps the github-actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action). - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/689fdc5193eeb735ecb2e52e819e3382876f93f4...407ffafae6a767df3e0230c3df91b6443ae8df75) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 199f1bfbac..455e6f14c8 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -48,6 +48,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@689fdc5193eeb735ecb2e52e819e3382876f93f4 # v2.22.6 + uses: github/codeql-action/upload-sarif@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8 with: sarif_file: results.sarif From afaf8fda2ad0364655909b56c8b634ce89095bb5 Mon Sep 17 00:00:00 2001 From: Juan Ramos <114601453+juan-lunarg@users.noreply.github.com> Date: Tue, 28 Nov 2023 08:53:56 -0700 Subject: [PATCH 85/95] Fix iOS / Android CMake builds (#5482) * cmake: Simplify usage of option boolean OFF is the default value: https://cmake.org/cmake/help/latest/command/option.html * Fix iOS / Android CMake builds closes #4437 --- CMakeLists.txt | 22 +++++++++++++++------- source/CMakeLists.txt | 6 ------ 2 files changed, 15 insertions(+), 13 deletions(-) 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/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) From ffe64502392e56e2f417f92428bd367017269634 Mon Sep 17 00:00:00 2001 From: Juan Ramos <114601453+juan-lunarg@users.noreply.github.com> Date: Wed, 29 Nov 2023 07:40:44 -0700 Subject: [PATCH 86/95] Add iOS build to CI (#5490) * Add iOS build to CI closes #5488 * ios: Make linker warnings into errors --- .github/workflows/ios.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/ios.yml diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml new file mode 100644 index 0000000000..b46ff1d409 --- /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@8be6cca406b575906541e8e3b885d46f416bba39 # v3.27.7 + - 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 From f4a73dd7a0cadfa9a9ea384b609e0e6a2cb71f5b Mon Sep 17 00:00:00 2001 From: David Neto Date: Wed, 29 Nov 2023 09:43:07 -0500 Subject: [PATCH 87/95] std::system requires include of (#5486) --- tools/reduce/reduce.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/reduce/reduce.cpp b/tools/reduce/reduce.cpp index 37600543a8..fe39e68b8e 100644 --- a/tools/reduce/reduce.cpp +++ b/tools/reduce/reduce.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include #include From 0d87845532579ec3787165cc55635c95180463e0 Mon Sep 17 00:00:00 2001 From: David Neto Date: Thu, 30 Nov 2023 17:05:25 -0500 Subject: [PATCH 88/95] Remove uses of std::system(nullptr) (#5494) Android's bionic library blows up on this, contrary to the standard. If std::system can't find a shell, you already have bigger problems. Don't check specially for that condition. (That's the justification Android uses, and I'm not going to fight it.) --- tools/fuzz/fuzz.cpp | 11 ----------- tools/reduce/reduce.cpp | 12 ------------ 2 files changed, 23 deletions(-) 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/reduce/reduce.cpp b/tools/reduce/reduce.cpp index fe39e68b8e..959f5a2f27 100644 --- a/tools/reduce/reduce.cpp +++ b/tools/reduce/reduce.cpp @@ -30,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) { @@ -283,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; From 2da75e152e28baa99d04dfe737582db7fe9c8842 Mon Sep 17 00:00:00 2001 From: ncesario-lunarg <71668273+ncesario-lunarg@users.noreply.github.com> Date: Mon, 4 Dec 2023 06:48:16 -0700 Subject: [PATCH 89/95] Do not crash when tryingto fold unsupported spec constant (#5496) Remove assertion in FoldWithInstructionFolder; there are cases where folding spec constants is unsupported. Closes #5492. --- ...ld_spec_constant_op_and_composite_pass.cpp | 5 ++-- .../opt/fold_spec_const_op_composite_test.cpp | 25 +++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) 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/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() { From e7a52b70fecf76f18ede365125ac08818c4b6360 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Dec 2023 10:18:57 -0500 Subject: [PATCH 90/95] build(deps): bump the github-actions group with 1 update (#5498) Bumps the github-actions group with 1 update: [lukka/get-cmake](https://github.com/lukka/get-cmake). - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/8be6cca406b575906541e8e3b885d46f416bba39...4865386b66955d11be0abf8c112d0230023e742a) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ios.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index b46ff1d409..68bf59b6ef 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -12,7 +12,7 @@ jobs: os: [ macos-12, macos-13 ] steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: lukka/get-cmake@8be6cca406b575906541e8e3b885d46f416bba39 # v3.27.7 + - 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. From b5d60826e9d2ad130fd9eb140ea633c349159952 Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Mon, 4 Dec 2023 15:43:36 -0700 Subject: [PATCH 91/95] printf: Remove stage specific info (#5495) Remove stage specific debug info that is only needed by GPU-AV. This allows debug printfs to be used in multi-stage shader modules. Fixes #4892 --- include/spirv-tools/instrument.hpp | 70 -------------------------- source/opt/inst_bindless_check_pass.h | 2 +- source/opt/inst_buff_addr_check_pass.h | 5 +- source/opt/inst_debug_printf_pass.cpp | 39 ++++++-------- source/opt/inst_debug_printf_pass.h | 33 +++--------- source/opt/instrument_pass.cpp | 68 +++++++++++++------------ source/opt/instrument_pass.h | 13 +++-- test/opt/inst_debug_printf_test.cpp | 47 ++++------------- 8 files changed, 81 insertions(+), 196 deletions(-) diff --git a/include/spirv-tools/instrument.hpp b/include/spirv-tools/instrument.hpp index ae9278b0fc..0a6e6306ec 100644 --- a/include/spirv-tools/instrument.hpp +++ b/include/spirv-tools/instrument.hpp @@ -73,81 +73,11 @@ 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; - // 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; diff --git a/source/opt/inst_bindless_check_pass.h b/source/opt/inst_bindless_check_pass.h index f99b59d0a5..243cba7671 100644 --- a/source/opt/inst_bindless_check_pass.h +++ b/source/opt/inst_bindless_check_pass.h @@ -29,7 +29,7 @@ namespace opt { class InstBindlessCheckPass : public InstrumentPass { public: InstBindlessCheckPass(uint32_t shader_id) - : InstrumentPass(0, shader_id, true) {} + : InstrumentPass(0, shader_id, true, true) {} ~InstBindlessCheckPass() override = default; diff --git a/source/opt/inst_buff_addr_check_pass.h b/source/opt/inst_buff_addr_check_pass.h index 70076a3712..f07f98a0f2 100644 --- a/source/opt/inst_buff_addr_check_pass.h +++ b/source/opt/inst_buff_addr_check_pass.h @@ -29,9 +29,10 @@ namespace opt { class InstBuffAddrCheckPass : public InstrumentPass { public: // For test harness only - InstBuffAddrCheckPass() : InstrumentPass(0, 23) {} + InstBuffAddrCheckPass() : InstrumentPass(0, 23, false, true) {} // For all other interfaces - InstBuffAddrCheckPass(uint32_t shader_id) : InstrumentPass(0, shader_id) {} + InstBuffAddrCheckPass(uint32_t shader_id) + : InstrumentPass(0, shader_id, false, true) {} ~InstBuffAddrCheckPass() override = default; diff --git a/source/opt/inst_debug_printf_pass.cpp b/source/opt/inst_debug_printf_pass.cpp index a48a28f6b1..abd25e9396 100644 --- a/source/opt/inst_debug_printf_pass.cpp +++ b/source/opt/inst_debug_printf_pass.cpp @@ -138,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( @@ -168,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; @@ -191,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 @@ -301,8 +301,7 @@ uint32_t InstDebugPrintfPass::GetStreamWriteFunctionId(uint32_t param_cnt) { enum { kShaderId = 0, kInstructionIndex = 1, - kStageInfo = 2, - kFirstParam = 3, + kFirstParam = 2, }; // Total param count is common params plus validation-specific // params @@ -312,12 +311,9 @@ uint32_t InstDebugPrintfPass::GetStreamWriteFunctionId(uint32_t param_cnt) { 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); @@ -330,8 +326,8 @@ uint32_t InstDebugPrintfPass::GetStreamWriteFunctionId(uint32_t param_cnt) { 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 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( @@ -382,16 +378,9 @@ uint32_t InstDebugPrintfPass::GetStreamWriteFunctionId(uint32_t param_cnt) { // 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, + GenDebugOutputFieldCode(obuf_curr_sz_id, first_param_offset + i, param_ids[kFirstParam + i], &builder); } // Close write block and gen merge block @@ -416,12 +405,12 @@ uint32_t InstDebugPrintfPass::GetStreamWriteFunctionId(uint32_t param_cnt) { } void InstDebugPrintfPass::GenDebugStreamWrite( - uint32_t shader_id, uint32_t instruction_idx_id, uint32_t stage_info_id, + 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, stage_info_id}; + 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); @@ -455,10 +444,10 @@ 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 3a2078a7dd..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) {} + InstDebugPrintfPass() : InstrumentPass(7, 23, false, false) {} // For all other interfaces InstDebugPrintfPass(uint32_t desc_set, uint32_t shader_id) - : InstrumentPass(desc_set, shader_id) {} + : InstrumentPass(desc_set, shader_id, false, false) {} ~InstDebugPrintfPass() override = default; @@ -52,9 +52,7 @@ class InstDebugPrintfPass : public InstrumentPass { // 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 + // 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. // @@ -83,9 +81,6 @@ class InstDebugPrintfPass : public InstrumentPass { // Record Size // Shader ID // Instruction Index - // Stage - // Stage-specific Word 0 - // Stage-specific Word 1 // ... // Validation Error Code // Validation-specific Word 0 @@ -93,8 +88,8 @@ class InstDebugPrintfPass : public InstrumentPass { // 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 + // 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 @@ -106,18 +101,6 @@ class InstDebugPrintfPass : public InstrumentPass { // 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. @@ -131,7 +114,6 @@ class InstDebugPrintfPass : public InstrumentPass { // 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); @@ -144,7 +126,7 @@ class InstDebugPrintfPass : public InstrumentPass { // 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 @@ -162,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) @@ -175,7 +156,7 @@ 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 diff --git a/source/opt/instrument_pass.cpp b/source/opt/instrument_pass.cpp index 829de491cd..dc33e1464a 100644 --- a/source/opt/instrument_pass.cpp +++ b/source/opt/instrument_pass.cpp @@ -653,44 +653,50 @@ 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; } diff --git a/source/opt/instrument_pass.h b/source/opt/instrument_pass.h index 8b643742dd..e4408c93eb 100644 --- a/source/opt/instrument_pass.h +++ b/source/opt/instrument_pass.h @@ -77,12 +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, - 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), - 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(); @@ -312,7 +313,11 @@ class InstrumentPass : public Pass { // Optimize direct debug input buffer reads. Specifically, move all such // reads with constant args to first block and reuse them. - bool opt_direct_reads_{false}; + 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/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+}} From 6b4f0c9d0b7d02db5ed0b03433ae62c03bbff722 Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Tue, 5 Dec 2023 09:59:51 -0700 Subject: [PATCH 92/95] instrument: Fix handling of gl_InvocationID (#5493) This is an int and needs to be cast to a unit for inclusion in the stage specific data passed to the instrumentation check function. --- source/opt/instrument_pass.cpp | 4 +- test/opt/inst_bindless_check_test.cpp | 253 ++++++++++++++++++++++++++ 2 files changed, 255 insertions(+), 2 deletions(-) diff --git a/source/opt/instrument_pass.cpp b/source/opt/instrument_pass.cpp index dc33e1464a..b6845a5997 100644 --- a/source/opt/instrument_pass.cpp +++ b/source/opt/instrument_pass.cpp @@ -213,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); diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp index 0deec5c6a5..08da367fd5 100644 --- a/test/opt/inst_bindless_check_test.cpp +++ b/test/opt/inst_bindless_check_test.cpp @@ -916,6 +916,259 @@ OpFunctionEnd 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) { // Same source as Simple, but compiled -g and not optimized, especially not // inlined. The OpSource has had the source extracted for the sake of brevity. From d75b3cfbb7dc46ea09dd1a0689753e4ac4cc5401 Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Mon, 11 Dec 2023 15:32:45 +0000 Subject: [PATCH 93/95] Zero initialize local variables (#5501) Certain versions of GCC warn about these variables being potentially uninitialized when used. I believe this is a false-positive, but zero-init'ing them is a safe way to fix this. --- source/opt/optimizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index d00b87c3be..d865cf1d47 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -560,7 +560,7 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { "--switch-descriptorset requires a from:to argument."); return false; } - uint32_t from_set, to_set; + uint32_t from_set = 0, to_set = 0; const char* start = pass_args.data(); const char* end = pass_args.data() + pass_args.size(); From e03c8f5c8ed77f0b1a2408d55bb8f00a7ee9793c Mon Sep 17 00:00:00 2001 From: alan-baker Date: Mon, 11 Dec 2023 11:45:10 -0500 Subject: [PATCH 94/95] Fix broken build (#5505) Fixes #5503 * SPIRV-Headers name change broke the build * Update SPIRV-Headers deps and fix --- DEPS | 2 +- test/enum_set_test.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 0b06cffd1c..a27f4fca18 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': '7e0c1a9e2417e70e5f0efc323267ac71d1fa0685', - 'spirv_headers_revision': 'cca08c63cefa129d082abca0302adcb81610b465', + 'spirv_headers_revision': '1c6bb2743599e6eb6f37b2969acc0aef812e32e3', } deps = { 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, From f0cc85efdbbe3a46eae90e0f915dc1509836d0fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Wed, 20 Dec 2023 13:22:56 +0100 Subject: [PATCH 95/95] Prepare release v2023.6 (#5510) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nathan GauĂ«r --- CHANGES | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGES b/CHANGES index a7929eba34..48aa87664a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,22 @@ 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)