From 631f9bcb5e664c62cb0f41a01354753996824ba9 Mon Sep 17 00:00:00 2001 From: David Neto Date: Wed, 11 Jan 2023 14:58:35 -0500 Subject: [PATCH 001/523] Update README.md: Development occurs on the "main" branch (#5053) Fixes: #5051 --- CHANGES | 2 +- README.md | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 384805c32b..967be16d93 100644 --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,7 @@ Revision history for SPIRV-Tools v2022.5-dev 2022-10-12 - - Start v2022.5-dev + - Renamed "master" to "main" (issue#5051) v2022.4 2022-10-12 - General diff --git a/README.md b/README.md index 6d1d66fa5d..10a8187bf1 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # SPIR-V Tools +NEWS 2023-01-11: Development occurs on the `main` branch. + ## Overview The SPIR-V Tools project provides an API and commands for processing SPIR-V @@ -271,7 +273,7 @@ Contributions via merge request are welcome. Changes should: `clang-format version 5.0.0` for SPIRV-Tools. Settings are defined by the included [.clang-format](.clang-format) file. -We intend to maintain a linear history on the GitHub `master` branch. +We intend to maintain a linear history on the GitHub `main` branch. ### Getting the source From bfd278617c3a7b59c0c4b33cdd0213ddfbb38d02 Mon Sep 17 00:00:00 2001 From: David Neto Date: Wed, 11 Jan 2023 15:24:34 -0500 Subject: [PATCH 002/523] utils: repos use 'main' as main devlopment branch (#5054) roll_deps.h: SPIRV-Headers uses 'main' check_code_format.h: SPIRV-Tools uses 'main' --- utils/check_code_format.sh | 2 +- utils/roll_deps.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/check_code_format.sh b/utils/check_code_format.sh index 7994740226..da5e019859 100755 --- a/utils/check_code_format.sh +++ b/utils/check_code_format.sh @@ -18,7 +18,7 @@ # # This script assumes to be invoked at the project root directory. -BASE_BRANCH=${1:-master} +BASE_BRANCH=${1:-main} FILES_TO_CHECK=$(git diff --name-only ${BASE_BRANCH} | grep -E ".*\.(cpp|cc|c\+\+|cxx|c|h|hpp)$") diff --git a/utils/roll_deps.sh b/utils/roll_deps.sh index 20c061fd86..03bdaceb50 100755 --- a/utils/roll_deps.sh +++ b/utils/roll_deps.sh @@ -27,7 +27,7 @@ googletest_trunk="origin/main" re2_dir="external/re2/" re2_trunk="origin/main" spirv_headers_dir="external/spirv-headers/" -spirv_headers_trunk="origin/master" +spirv_headers_trunk="origin/main" # This script assumes it's parent directory is the repo root. repo_path=$(dirname "$0")/.. From 7e8813bb4cf32fd9c4d696c09d4e68e17a8f57f1 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Wed, 11 Jan 2023 16:58:53 -0500 Subject: [PATCH 003/523] Validate version 5 of clspv reflection (#5050) * Validate version 5 of clspv reflection * Add validation for instructions in versions 2 through 5 * Change the instruction reported for remaining indices on an access chain to the access chain itself for clarity * update spirv-headers --- DEPS | 2 +- source/val/validate_extensions.cpp | 335 ++++++++++++- source/val/validate_memory.cpp | 2 +- test/val/val_ext_inst_test.cpp | 757 ++++++++++++++++++++++++++++- 4 files changed, 1065 insertions(+), 31 deletions(-) diff --git a/DEPS b/DEPS index b16d696431..6530a26873 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v3.13.0.1', 're2_revision': 'd2836d1b1c34c4e330a85a1006201db474bf2c8a', - 'spirv_headers_revision': '34d04647d384e0aed037e7a2662a655fc39841bb', + 'spirv_headers_revision': 'd13b52222c39a7e9a401b44646f0ca3a640fbd47', } deps = { diff --git a/source/val/validate_extensions.cpp b/source/val/validate_extensions.cpp index ebb13cfd42..fa58e0f940 100644 --- a/source/val/validate_extensions.cpp +++ b/source/val/validate_extensions.cpp @@ -39,6 +39,20 @@ namespace spvtools { namespace val { namespace { +std::string ReflectionInstructionName(ValidationState_t& _, + const Instruction* inst) { + spv_ext_inst_desc desc = nullptr; + if (_.grammar().lookupExtInst(SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION, + inst->word(4), &desc) != SPV_SUCCESS || + !desc) { + return std::string("Unknown ExtInst"); + } + std::ostringstream ss; + ss << desc->name; + + return ss.str(); +} + uint32_t GetSizeTBitWidth(const ValidationState_t& _) { if (_.addressing_model() == spv::AddressingModel::Physical32) return 32; @@ -273,12 +287,14 @@ spv_result_t ValidateOperandDebugType( } spv_result_t ValidateClspvReflectionKernel(ValidationState_t& _, - const Instruction* inst) { + const Instruction* inst, + uint32_t version) { + const auto inst_name = ReflectionInstructionName(_, inst); const auto kernel_id = inst->GetOperandAs(4); const auto kernel = _.FindDef(kernel_id); if (kernel->opcode() != spv::Op::OpFunction) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "Kernel does not reference a function"; + << inst_name << " does not reference a function"; } bool found_kernel = false; @@ -290,18 +306,18 @@ spv_result_t ValidateClspvReflectionKernel(ValidationState_t& _, } if (!found_kernel) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "Kernel does not reference an entry-point"; + << inst_name << " does not reference an entry-point"; } const auto* exec_models = _.GetExecutionModels(kernel_id); if (!exec_models || exec_models->empty()) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "Kernel does not reference an entry-point"; + << inst_name << " does not reference an entry-point"; } for (auto exec_model : *exec_models) { if (exec_model != spv::ExecutionModel::GLCompute) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "Kernel must refer only to GLCompute entry-points"; + << inst_name << " must refer only to GLCompute entry-points"; } } @@ -323,6 +339,37 @@ spv_result_t ValidateClspvReflectionKernel(ValidationState_t& _, << "Name must match an entry-point for Kernel"; } + const auto num_operands = inst->operands().size(); + if (version < 5 && num_operands > 6) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Version " << version << " of the " << inst_name + << " instruction can only have 2 additional operands"; + } + + if (num_operands > 6) { + const auto num_args_id = inst->GetOperandAs(6); + if (!IsUint32Constant(_, num_args_id)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "NumArguments must be a 32-bit unsigned integer OpConstant"; + } + } + + if (num_operands > 7) { + const auto flags_id = inst->GetOperandAs(7); + if (!IsUint32Constant(_, flags_id)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Flags must be a 32-bit unsigned integer OpConstant"; + } + } + + if (num_operands > 8) { + const auto atts_id = inst->GetOperandAs(8); + if (_.GetIdOpcode(atts_id) != spv::Op::OpString) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Attributes must be an OpString"; + } + } + return SPV_SUCCESS; } @@ -439,8 +486,8 @@ spv_result_t ValidateClspvReflectionArgumentBuffer(ValidationState_t& _, return SPV_SUCCESS; } -spv_result_t ValidateClspvReflectionArgumentPodBuffer(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; @@ -480,7 +527,7 @@ spv_result_t ValidateClspvReflectionArgumentPodBuffer(ValidationState_t& _, return SPV_SUCCESS; } -spv_result_t ValidateClspvReflectionArgumentPodPushConstant( +spv_result_t ValidateClspvReflectionArgumentPushConstant( ValidationState_t& _, const Instruction* inst) { const auto num_operands = inst->operands().size(); if (auto error = ValidateKernelDecl(_, inst)) { @@ -587,8 +634,8 @@ spv_result_t ValidateClspvReflectionPushConstant(ValidationState_t& _, return SPV_SUCCESS; } -spv_result_t ValidateClspvReflectionConstantData(ValidationState_t& _, - const Instruction* inst) { +spv_result_t ValidateClspvReflectionInitializedData(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"; @@ -650,18 +697,250 @@ spv_result_t ValidateClspvReflectionPropertyRequiredWorkgroupSize( return SPV_SUCCESS; } +spv_result_t ValidateClspvReflectionSubgroupMaxSize(ValidationState_t& _, + const Instruction* inst) { + const auto size_id = inst->GetOperandAs(4); + if (!IsUint32Constant(_, size_id)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Size must be a 32-bit unsigned integer OpConstant"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateClspvReflectionPointerRelocation(ValidationState_t& _, + const Instruction* inst) { + if (!IsUint32Constant(_, inst->GetOperandAs(4))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "ObjectOffset must be a 32-bit unsigned integer OpConstant"; + } + + if (!IsUint32Constant(_, inst->GetOperandAs(5))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "PointerOffset must be a 32-bit unsigned integer OpConstant"; + } + + if (!IsUint32Constant(_, inst->GetOperandAs(6))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "PointerSize must be a 32-bit unsigned integer OpConstant"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateClspvReflectionImageMetadataPushConstant( + ValidationState_t& _, const Instruction* inst) { + if (auto error = ValidateKernelDecl(_, inst)) { + return error; + } + + if (!IsUint32Constant(_, inst->GetOperandAs(5))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Ordinal must be a 32-bit unsigned integer OpConstant"; + } + + if (!IsUint32Constant(_, inst->GetOperandAs(6))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Offset must be a 32-bit unsigned integer OpConstant"; + } + + if (!IsUint32Constant(_, inst->GetOperandAs(7))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Size must be a 32-bit unsigned integer OpConstant"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateClspvReflectionImageMetadataUniform( + ValidationState_t& _, const Instruction* inst) { + if (auto error = ValidateKernelDecl(_, inst)) { + return error; + } + + if (!IsUint32Constant(_, inst->GetOperandAs(5))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Ordinal must be a 32-bit unsigned integer OpConstant"; + } + + if (!IsUint32Constant(_, inst->GetOperandAs(6))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "DescriptorSet must be a 32-bit unsigned integer OpConstant"; + } + + if (!IsUint32Constant(_, inst->GetOperandAs(7))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Binding must be a 32-bit unsigned integer OpConstant"; + } + + if (!IsUint32Constant(_, inst->GetOperandAs(8))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Offset must be a 32-bit unsigned integer OpConstant"; + } + + if (!IsUint32Constant(_, inst->GetOperandAs(9))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Size must be a 32-bit unsigned integer OpConstant"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateClspvReflectionPushConstantData(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"; + } + + if (!IsUint32Constant(_, inst->GetOperandAs(5))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Size must be a 32-bit unsigned integer OpConstant"; + } + + if (_.GetIdOpcode(inst->GetOperandAs(6)) != spv::Op::OpString) { + return _.diag(SPV_ERROR_INVALID_ID, inst) << "Data must be an OpString"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateClspvReflectionPrintfInfo(ValidationState_t& _, + const Instruction* inst) { + if (!IsUint32Constant(_, inst->GetOperandAs(4))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "PrintfID must be a 32-bit unsigned integer OpConstant"; + } + + if (_.GetIdOpcode(inst->GetOperandAs(5)) != spv::Op::OpString) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "FormatString must be an OpString"; + } + + for (size_t i = 6; i < inst->operands().size(); ++i) { + if (!IsUint32Constant(_, inst->GetOperandAs(i))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "ArgumentSizes must be a 32-bit unsigned integer OpConstant"; + } + } + + return SPV_SUCCESS; +} + +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"; + } + + if (!IsUint32Constant(_, inst->GetOperandAs(5))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Binding must be a 32-bit unsigned integer OpConstant"; + } + + if (!IsUint32Constant(_, inst->GetOperandAs(6))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Size must be a 32-bit unsigned integer OpConstant"; + } + + return SPV_SUCCESS; +} + +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"; + } + + if (!IsUint32Constant(_, inst->GetOperandAs(5))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Size must be a 32-bit unsigned integer OpConstant"; + } + + if (!IsUint32Constant(_, inst->GetOperandAs(6))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "BufferSize must be a 32-bit unsigned integer OpConstant"; + } + + return SPV_SUCCESS; +} + spv_result_t ValidateClspvReflectionInstruction(ValidationState_t& _, const Instruction* inst, - uint32_t /*version*/) { + uint32_t version) { if (!_.IsVoidType(inst->type_id())) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Return Type must be OpTypeVoid"; } - auto ext_inst = inst->GetOperandAs(3); + uint32_t required_version = 0; + const auto ext_inst = + inst->GetOperandAs(3); + switch (ext_inst) { + case NonSemanticClspvReflectionKernel: + case NonSemanticClspvReflectionArgumentInfo: + case NonSemanticClspvReflectionArgumentStorageBuffer: + case NonSemanticClspvReflectionArgumentUniform: + case NonSemanticClspvReflectionArgumentPodStorageBuffer: + case NonSemanticClspvReflectionArgumentPodUniform: + case NonSemanticClspvReflectionArgumentPodPushConstant: + case NonSemanticClspvReflectionArgumentSampledImage: + case NonSemanticClspvReflectionArgumentStorageImage: + case NonSemanticClspvReflectionArgumentSampler: + case NonSemanticClspvReflectionArgumentWorkgroup: + case NonSemanticClspvReflectionSpecConstantWorkgroupSize: + case NonSemanticClspvReflectionSpecConstantGlobalOffset: + case NonSemanticClspvReflectionSpecConstantWorkDim: + case NonSemanticClspvReflectionPushConstantGlobalOffset: + case NonSemanticClspvReflectionPushConstantEnqueuedLocalSize: + case NonSemanticClspvReflectionPushConstantGlobalSize: + case NonSemanticClspvReflectionPushConstantRegionOffset: + case NonSemanticClspvReflectionPushConstantNumWorkgroups: + case NonSemanticClspvReflectionPushConstantRegionGroupOffset: + case NonSemanticClspvReflectionConstantDataStorageBuffer: + case NonSemanticClspvReflectionConstantDataUniform: + case NonSemanticClspvReflectionLiteralSampler: + case NonSemanticClspvReflectionPropertyRequiredWorkgroupSize: + required_version = 1; + break; + case NonSemanticClspvReflectionSpecConstantSubgroupMaxSize: + required_version = 2; + break; + case NonSemanticClspvReflectionArgumentPointerPushConstant: + case NonSemanticClspvReflectionArgumentPointerUniform: + case NonSemanticClspvReflectionProgramScopeVariablesStorageBuffer: + case NonSemanticClspvReflectionProgramScopeVariablePointerRelocation: + case NonSemanticClspvReflectionImageArgumentInfoChannelOrderPushConstant: + case NonSemanticClspvReflectionImageArgumentInfoChannelDataTypePushConstant: + case NonSemanticClspvReflectionImageArgumentInfoChannelOrderUniform: + case NonSemanticClspvReflectionImageArgumentInfoChannelDataTypeUniform: + required_version = 3; + break; + case NonSemanticClspvReflectionArgumentStorageTexelBuffer: + case NonSemanticClspvReflectionArgumentUniformTexelBuffer: + required_version = 4; + break; + case NonSemanticClspvReflectionConstantDataPointerPushConstant: + case NonSemanticClspvReflectionProgramScopeVariablePointerPushConstant: + case NonSemanticClspvReflectionPrintfInfo: + case NonSemanticClspvReflectionPrintfBufferStorageBuffer: + case NonSemanticClspvReflectionPrintfBufferPointerPushConstant: + required_version = 5; + break; + default: + break; + } + if (version < required_version) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << ReflectionInstructionName(_, inst) << " requires version " + << required_version << ", but parsed version is " << version; + } + switch (ext_inst) { case NonSemanticClspvReflectionKernel: - return ValidateClspvReflectionKernel(_, inst); + return ValidateClspvReflectionKernel(_, inst, version); case NonSemanticClspvReflectionArgumentInfo: return ValidateClspvReflectionArgumentInfo(_, inst); case NonSemanticClspvReflectionArgumentStorageBuffer: @@ -669,12 +948,16 @@ spv_result_t ValidateClspvReflectionInstruction(ValidationState_t& _, case NonSemanticClspvReflectionArgumentSampledImage: case NonSemanticClspvReflectionArgumentStorageImage: case NonSemanticClspvReflectionArgumentSampler: + case NonSemanticClspvReflectionArgumentStorageTexelBuffer: + case NonSemanticClspvReflectionArgumentUniformTexelBuffer: return ValidateClspvReflectionArgumentBuffer(_, inst); case NonSemanticClspvReflectionArgumentPodStorageBuffer: case NonSemanticClspvReflectionArgumentPodUniform: - return ValidateClspvReflectionArgumentPodBuffer(_, inst); + case NonSemanticClspvReflectionArgumentPointerUniform: + return ValidateClspvReflectionArgumentOffsetBuffer(_, inst); case NonSemanticClspvReflectionArgumentPodPushConstant: - return ValidateClspvReflectionArgumentPodPushConstant(_, inst); + case NonSemanticClspvReflectionArgumentPointerPushConstant: + return ValidateClspvReflectionArgumentPushConstant(_, inst); case NonSemanticClspvReflectionArgumentWorkgroup: return ValidateClspvReflectionArgumentWorkgroup(_, inst); case NonSemanticClspvReflectionSpecConstantWorkgroupSize: @@ -691,11 +974,31 @@ spv_result_t ValidateClspvReflectionInstruction(ValidationState_t& _, return ValidateClspvReflectionPushConstant(_, inst); case NonSemanticClspvReflectionConstantDataStorageBuffer: case NonSemanticClspvReflectionConstantDataUniform: - return ValidateClspvReflectionConstantData(_, inst); + case NonSemanticClspvReflectionProgramScopeVariablesStorageBuffer: + return ValidateClspvReflectionInitializedData(_, inst); case NonSemanticClspvReflectionLiteralSampler: return ValidateClspvReflectionSampler(_, inst); case NonSemanticClspvReflectionPropertyRequiredWorkgroupSize: return ValidateClspvReflectionPropertyRequiredWorkgroupSize(_, inst); + case NonSemanticClspvReflectionSpecConstantSubgroupMaxSize: + return ValidateClspvReflectionSubgroupMaxSize(_, inst); + case NonSemanticClspvReflectionProgramScopeVariablePointerRelocation: + return ValidateClspvReflectionPointerRelocation(_, inst); + case NonSemanticClspvReflectionImageArgumentInfoChannelOrderPushConstant: + case NonSemanticClspvReflectionImageArgumentInfoChannelDataTypePushConstant: + return ValidateClspvReflectionImageMetadataPushConstant(_, inst); + case NonSemanticClspvReflectionImageArgumentInfoChannelOrderUniform: + case NonSemanticClspvReflectionImageArgumentInfoChannelDataTypeUniform: + return ValidateClspvReflectionImageMetadataUniform(_, inst); + case NonSemanticClspvReflectionConstantDataPointerPushConstant: + case NonSemanticClspvReflectionProgramScopeVariablePointerPushConstant: + return ValidateClspvReflectionPushConstantData(_, inst); + case NonSemanticClspvReflectionPrintfInfo: + return ValidateClspvReflectionPrintfInfo(_, inst); + case NonSemanticClspvReflectionPrintfBufferStorageBuffer: + return ValidateClspvReflectionPrintfStorageBuffer(_, inst); + case NonSemanticClspvReflectionPrintfBufferPointerPushConstant: + return ValidateClspvReflectionPrintfPushConstant(_, inst); default: break; } diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index 57fd23d532..5f7358c686 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -1398,7 +1398,7 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, } default: { // Give an error. reached non-composite type while indexes still remain. - return _.diag(SPV_ERROR_INVALID_ID, cur_word_instr) + return _.diag(SPV_ERROR_INVALID_ID, inst) << instr_name << " reached non-composite type while indexes " "still remain to be traversed."; diff --git a/test/val/val_ext_inst_test.cpp b/test/val/val_ext_inst_test.cpp index e685acde5d..8f0bcce14b 100644 --- a/test/val/val_ext_inst_test.cpp +++ b/test/val/val_ext_inst_test.cpp @@ -6239,6 +6239,197 @@ OpFunctionEnd HasSubstr("Name must match an entry-point for Kernel")); } +TEST_F(ValidateClspvReflection, KernelArgumentsVersionGood) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.5" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +%foo_name = OpString "foo" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%int = OpTypeInt 32 0 +%int_1 = OpConstant %int 1 +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +%decl = OpExtInst %void %ext Kernel %foo %foo_name %int_1 +)"; + + CompileSuccessfully(text); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateClspvReflection, KernelArgumentsVersionBad) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.4" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +%foo_name = OpString "foo" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%int = OpTypeInt 32 0 +%int_1 = OpConstant %int 1 +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +%decl = OpExtInst %void %ext Kernel %foo %foo_name %int_1 +)"; + + CompileSuccessfully(text); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Version 4 of the Kernel instruction can only have 2 " + "additional operands")); +} + +TEST_F(ValidateClspvReflection, KernelNumArgumentsNotInt) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.5" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +%foo_name = OpString "foo" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +%decl = OpExtInst %void %ext Kernel %foo %foo_name %float_0 +)"; + + CompileSuccessfully(text); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("NumArguments must be a 32-bit unsigned integer OpConstant")); +} + +TEST_F(ValidateClspvReflection, KernelNumArgumentsNotConstant) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.5" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +%foo_name = OpString "foo" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%null = OpConstantNull %int +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +%decl = OpExtInst %void %ext Kernel %foo %foo_name %null +)"; + + CompileSuccessfully(text); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("NumArguments must be a 32-bit unsigned integer OpConstant")); +} + +TEST_F(ValidateClspvReflection, KernelFlagsNotInt) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.5" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +%foo_name = OpString "foo" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +%decl = OpExtInst %void %ext Kernel %foo %foo_name %int_0 %float_0 +)"; + + CompileSuccessfully(text); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Flags must be a 32-bit unsigned integer OpConstant")); +} + +TEST_F(ValidateClspvReflection, KernelFlagsNotConstant) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.5" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +%foo_name = OpString "foo" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%null = OpConstantNull %int +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +%decl = OpExtInst %void %ext Kernel %foo %foo_name %int_0 %null +)"; + + CompileSuccessfully(text); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Flags must be a 32-bit unsigned integer OpConstant")); +} + +TEST_F(ValidateClspvReflection, KernelAttributesNotString) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.5" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +%foo_name = OpString "foo" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +%decl = OpExtInst %void %ext Kernel %foo %foo_name %int_0 %int_0 %int_0 +)"; + + CompileSuccessfully(text); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Attributes must be an OpString")); +} + using ArgumentBasics = spvtest::ValidateBase>; @@ -6254,7 +6445,11 @@ INSTANTIATE_TEST_SUITE_P( std::make_pair("ArgumentSampledImage", "%int_0 %int_0"), std::make_pair("ArgumentStorageImage", "%int_0 %int_0"), std::make_pair("ArgumentSampler", "%int_0 %int_0"), - std::make_pair("ArgumentWorkgroup", "%int_0 %int_0")})); + std::make_pair("ArgumentWorkgroup", "%int_0 %int_0"), + std::make_pair("ArgumentPointerPushConstant", "%int_0 %int_4"), + std::make_pair("ArgumentPointerUniform", "%int_0 %int_0 %int_0 %int_4"), + std::make_pair("ArgumentStorageTexelBuffer", "%int_0 %int_0"), + std::make_pair("ArgumentUniformTexelBuffer", "%int_0 %int_0")})); TEST_P(ArgumentBasics, KernelNotAnExtendedInstruction) { const std::string ext_inst = std::get<0>(GetParam()); @@ -6262,7 +6457,7 @@ TEST_P(ArgumentBasics, KernelNotAnExtendedInstruction) { const std::string text = R"( OpCapability Shader OpExtension "SPV_KHR_non_semantic_info" -%ext = OpExtInstImport "NonSemantic.ClspvReflection.1" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.5" OpMemoryModel Logical GLSL450 OpEntryPoint GLCompute %foo "foo" OpExecutionMode %foo LocalSize 1 1 1 @@ -6291,8 +6486,8 @@ TEST_P(ArgumentBasics, KernelFromDifferentImport) { const std::string text = R"( OpCapability Shader OpExtension "SPV_KHR_non_semantic_info" -%ext = OpExtInstImport "NonSemantic.ClspvReflection.1" -%ext2 = OpExtInstImport "NonSemantic.ClspvReflection.1" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.5" +%ext2 = OpExtInstImport "NonSemantic.ClspvReflection.5" OpMemoryModel Logical GLSL450 OpEntryPoint GLCompute %foo "foo" OpExecutionMode %foo LocalSize 1 1 1 @@ -6323,7 +6518,7 @@ TEST_P(ArgumentBasics, KernelWrongExtendedInstruction) { const std::string text = R"( OpCapability Shader OpExtension "SPV_KHR_non_semantic_info" -%ext = OpExtInstImport "NonSemantic.ClspvReflection.1" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.5" OpMemoryModel Logical GLSL450 OpEntryPoint GLCompute %foo "foo" OpExecutionMode %foo LocalSize 1 1 1 @@ -6353,7 +6548,7 @@ TEST_P(ArgumentBasics, ArgumentInfo) { const std::string text = R"( OpCapability Shader OpExtension "SPV_KHR_non_semantic_info" -%ext = OpExtInstImport "NonSemantic.ClspvReflection.1" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.5" OpMemoryModel Logical GLSL450 OpEntryPoint GLCompute %foo "foo" OpExecutionMode %foo LocalSize 1 1 1 @@ -6383,7 +6578,7 @@ TEST_P(ArgumentBasics, ArgumentInfoNotAnExtendedInstruction) { const std::string text = R"( OpCapability Shader OpExtension "SPV_KHR_non_semantic_info" -%ext = OpExtInstImport "NonSemantic.ClspvReflection.1" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.5" OpMemoryModel Logical GLSL450 OpEntryPoint GLCompute %foo "foo" OpExecutionMode %foo LocalSize 1 1 1 @@ -6414,8 +6609,8 @@ TEST_P(ArgumentBasics, ArgumentInfoFromDifferentImport) { const std::string text = R"( OpCapability Shader OpExtension "SPV_KHR_non_semantic_info" -%ext = OpExtInstImport "NonSemantic.ClspvReflection.1" -%ext2 = OpExtInstImport "NonSemantic.ClspvReflection.1" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.5" +%ext2 = OpExtInstImport "NonSemantic.ClspvReflection.5" OpMemoryModel Logical GLSL450 OpEntryPoint GLCompute %foo "foo" OpExecutionMode %foo LocalSize 1 1 1 @@ -6659,7 +6854,269 @@ INSTANTIATE_TEST_SUITE_P( std::make_pair( "PropertyRequiredWorkgroupSize %decl %int_1 %int_1 %float_0", "Z"), std::make_pair( - "PropertyRequiredWorkgroupSize %decl %int_1 %int_1 %null", "Z")})); + "PropertyRequiredWorkgroupSize %decl %int_1 %int_1 %null", "Z"), + std::make_pair("SpecConstantSubgroupMaxSize %float_0", "Size"), + std::make_pair("SpecConstantSubgroupMaxSize %null", "Size"), + std::make_pair( + "ArgumentPointerPushConstant %decl %float_0 %int_0 %int_0", + "Ordinal"), + std::make_pair("ArgumentPointerPushConstant %decl %null %int_0 %int_0", + "Ordinal"), + std::make_pair( + "ArgumentPointerPushConstant %decl %int_0 %float_0 %int_0", + "Offset"), + std::make_pair("ArgumentPointerPushConstant %decl %int_0 %null %int_0", + "Offset"), + std::make_pair( + "ArgumentPointerPushConstant %decl %int_0 %int_0 %float_0", "Size"), + std::make_pair("ArgumentPointerPushConstant %decl %int_0 %int_0 %null", + "Size"), + std::make_pair( + "ArgumentPointerUniform %decl %float_0 %int_0 %int_0 %int_0 %int_4", + "Ordinal"), + std::make_pair( + "ArgumentPointerUniform %decl %null %int_0 %int_0 %int_0 %int_4", + "Ordinal"), + std::make_pair( + "ArgumentPointerUniform %decl %int_0 %float_0 %int_0 %int_0 %int_4", + "DescriptorSet"), + std::make_pair( + "ArgumentPointerUniform %decl %int_0 %null %int_0 %int_0 %int_4", + "DescriptorSet"), + std::make_pair( + "ArgumentPointerUniform %decl %int_0 %int_0 %float_0 %int_0 %int_4", + "Binding"), + std::make_pair( + "ArgumentPointerUniform %decl %int_0 %int_0 %null %int_0 %int_4", + "Binding"), + std::make_pair( + "ArgumentPointerUniform %decl %int_0 %int_0 %int_0 %float_0 %int_4", + "Offset"), + std::make_pair( + "ArgumentPointerUniform %decl %int_0 %int_0 %int_0 %null %int_4", + "Offset"), + std::make_pair( + "ArgumentPointerUniform %decl %int_0 %int_0 %int_0 %int_0 %float_0", + "Size"), + std::make_pair( + "ArgumentPointerUniform %decl %int_0 %int_0 %int_0 %int_0 %null", + "Size"), + std::make_pair( + "ProgramScopeVariablesStorageBuffer %float_0 %int_0 %data", + "DescriptorSet"), + std::make_pair("ProgramScopeVariablesStorageBuffer %null %int_0 %data", + "DescriptorSet"), + std::make_pair( + "ProgramScopeVariablesStorageBuffer %int_0 %float_0 %data", + "Binding"), + std::make_pair("ProgramScopeVariablesStorageBuffer %int_0 %null %data", + "Binding"), + std::make_pair( + "ProgramScopeVariablePointerRelocation %float_0 %int_0 %int_4", + "ObjectOffset"), + std::make_pair( + "ProgramScopeVariablePointerRelocation %null %int_0 %int_4", + "ObjectOffset"), + std::make_pair( + "ProgramScopeVariablePointerRelocation %int_0 %float_0 %int_4", + "PointerOffset"), + std::make_pair( + "ProgramScopeVariablePointerRelocation %int_0 %null %int_4", + "PointerOffset"), + std::make_pair( + "ProgramScopeVariablePointerRelocation %int_0 %int_0 %float_0", + "PointerSize"), + std::make_pair( + "ProgramScopeVariablePointerRelocation %int_0 %int_0 %null", + "PointerSize"), + std::make_pair("ImageArgumentInfoChannelOrderPushConstant %decl " + "%float_0 %int_0 %int_4", + "Ordinal"), + std::make_pair("ImageArgumentInfoChannelOrderPushConstant %decl %null " + "%int_0 %int_4", + "Ordinal"), + std::make_pair("ImageArgumentInfoChannelOrderPushConstant %decl %int_0 " + "%float_0 %int_4", + "Offset"), + std::make_pair("ImageArgumentInfoChannelOrderPushConstant %decl %int_0 " + "%null %int_4", + "Offset"), + std::make_pair("ImageArgumentInfoChannelOrderPushConstant %decl %int_0 " + "%int_0 %float_0", + "Size"), + std::make_pair("ImageArgumentInfoChannelOrderPushConstant %decl %int_0 " + "%int_0 %null", + "Size"), + std::make_pair("ImageArgumentInfoChannelDataTypePushConstant %decl " + "%float_0 %int_0 %int_4", + "Ordinal"), + std::make_pair("ImageArgumentInfoChannelDataTypePushConstant %decl " + "%null %int_0 %int_4", + "Ordinal"), + std::make_pair("ImageArgumentInfoChannelDataTypePushConstant %decl " + "%int_0 %float_0 %int_4", + "Offset"), + std::make_pair("ImageArgumentInfoChannelDataTypePushConstant %decl " + "%int_0 %null %int_4", + "Offset"), + std::make_pair("ImageArgumentInfoChannelDataTypePushConstant %decl " + "%int_0 %int_0 %float_0", + "Size"), + std::make_pair("ImageArgumentInfoChannelDataTypePushConstant %decl " + "%int_0 %int_0 %null", + "Size"), + std::make_pair("ImageArgumentInfoChannelOrderUniform %decl %float_0 " + "%int_0 %int_0 %int_0 %int_4", + "Ordinal"), + std::make_pair("ImageArgumentInfoChannelOrderUniform %decl %null " + "%int_0 %int_0 %int_0 %int_4", + "Ordinal"), + std::make_pair("ImageArgumentInfoChannelOrderUniform %decl %int_0 " + "%float_0 %int_0 %int_0 %int_4", + "DescriptorSet"), + std::make_pair("ImageArgumentInfoChannelOrderUniform %decl %int_0 " + "%null %int_0 %int_0 %int_4", + "DescriptorSet"), + std::make_pair("ImageArgumentInfoChannelOrderUniform %decl %int_0 " + "%int_0 %float_0 %int_0 %int_4", + "Binding"), + std::make_pair("ImageArgumentInfoChannelOrderUniform %decl %int_0 " + "%int_0 %null %int_0 %int_4", + "Binding"), + std::make_pair("ImageArgumentInfoChannelOrderUniform %decl %int_0 " + "%int_0 %int_0 %float_0 %int_4", + "Offset"), + std::make_pair("ImageArgumentInfoChannelOrderUniform %decl %int_0 " + "%int_0 %int_0 %null %int_4", + "Offset"), + std::make_pair("ImageArgumentInfoChannelOrderUniform %decl %int_0 " + "%int_0 %int_0 %int_0 %float_0", + "Size"), + std::make_pair("ImageArgumentInfoChannelOrderUniform %decl %int_0 " + "%int_0 %int_0 %int_0 %null", + "Size"), + std::make_pair("ImageArgumentInfoChannelDataTypeUniform %decl %float_0 " + "%int_0 %int_0 %int_0 %int_4", + "Ordinal"), + std::make_pair("ImageArgumentInfoChannelDataTypeUniform %decl %null " + "%int_0 %int_0 %int_0 %int_4", + "Ordinal"), + std::make_pair("ImageArgumentInfoChannelDataTypeUniform %decl %int_0 " + "%float_0 %int_0 %int_0 %int_4", + "DescriptorSet"), + std::make_pair("ImageArgumentInfoChannelDataTypeUniform %decl %int_0 " + "%null %int_0 %int_0 %int_4", + "DescriptorSet"), + std::make_pair("ImageArgumentInfoChannelDataTypeUniform %decl %int_0 " + "%int_0 %float_0 %int_0 %int_4", + "Binding"), + std::make_pair("ImageArgumentInfoChannelDataTypeUniform %decl %int_0 " + "%int_0 %null %int_0 %int_4", + "Binding"), + std::make_pair("ImageArgumentInfoChannelDataTypeUniform %decl %int_0 " + "%int_0 %int_0 %float_0 %int_4", + "Offset"), + std::make_pair("ImageArgumentInfoChannelDataTypeUniform %decl %int_0 " + "%int_0 %int_0 %null %int_4", + "Offset"), + std::make_pair("ImageArgumentInfoChannelDataTypeUniform %decl %int_0 " + "%int_0 %int_0 %int_0 %float_0", + "Size"), + std::make_pair("ImageArgumentInfoChannelDataTypeUniform %decl %int_0 " + "%int_0 %int_0 %int_0 %null", + "Size"), + std::make_pair( + "ArgumentStorageTexelBuffer %decl %float_0 %int_0 %int_0", + "Ordinal"), + std::make_pair("ArgumentStorageTexelBuffer %decl %null %int_0 %int_0", + "Ordinal"), + std::make_pair( + "ArgumentStorageTexelBuffer %decl %int_0 %float_0 %int_0", + "DescriptorSet"), + std::make_pair("ArgumentStorageTexelBuffer %decl %int_0 %null %int_0", + "DescriptorSet"), + std::make_pair( + "ArgumentStorageTexelBuffer %decl %int_0 %int_0 %float_0", + "Binding"), + std::make_pair("ArgumentStorageTexelBuffer %decl %int_0 %int_0 %null", + "Binding"), + std::make_pair( + "ArgumentUniformTexelBuffer %decl %float_0 %int_0 %int_0", + "Ordinal"), + std::make_pair("ArgumentUniformTexelBuffer %decl %null %int_0 %int_0", + "Ordinal"), + std::make_pair( + "ArgumentUniformTexelBuffer %decl %int_0 %float_0 %int_0", + "DescriptorSet"), + std::make_pair("ArgumentUniformTexelBuffer %decl %int_0 %null %int_0", + "DescriptorSet"), + std::make_pair( + "ArgumentUniformTexelBuffer %decl %int_0 %int_0 %float_0", + "Binding"), + std::make_pair("ArgumentUniformTexelBuffer %decl %int_0 %int_0 %null", + "Binding"), + std::make_pair("ConstantDataPointerPushConstant %float_0 %int_4 %data", + "Offset"), + std::make_pair("ConstantDataPointerPushConstant %null %int_4 %data", + "Offset"), + std::make_pair("ConstantDataPointerPushConstant %int_0 %float_0 %data", + "Size"), + std::make_pair("ConstantDataPointerPushConstant %int_0 %null %data", + "Size"), + std::make_pair( + "ProgramScopeVariablePointerPushConstant %float_0 %int_4 %data", + "Offset"), + std::make_pair( + "ProgramScopeVariablePointerPushConstant %null %int_4 %data", + "Offset"), + std::make_pair( + "ProgramScopeVariablePointerPushConstant %int_0 %float_0 %data", + "Size"), + std::make_pair( + "ProgramScopeVariablePointerPushConstant %int_0 %null %data", + "Size"), + std::make_pair("PrintfInfo %float_0 %data %int_0 %int_0 %int_0", + "PrintfID"), + std::make_pair("PrintfInfo %null %data %int_0 %int_0 %int_0", + "PrintfID"), + std::make_pair("PrintfInfo %int_0 %data %float_0 %int_0 %int_0", + "ArgumentSizes"), + std::make_pair("PrintfInfo %int_0 %data %null %int_0 %int_0", + "ArgumentSizes"), + std::make_pair("PrintfInfo %int_0 %data %int_0 %float_0 %int_0", + "ArgumentSizes"), + std::make_pair("PrintfInfo %int_0 %data %int_0 %null %int_0", + "ArgumentSizes"), + std::make_pair("PrintfInfo %int_0 %data %int_0 %int_0 %null", + "ArgumentSizes"), + std::make_pair("PrintfInfo %int_0 %data %int_0 %int_0 %float_0", + "ArgumentSizes"), + std::make_pair("PrintfInfo %int_0 %data %int_0 %float_0", + "ArgumentSizes"), + std::make_pair("PrintfInfo %int_0 %data %int_0 %null", "ArgumentSizes"), + std::make_pair("PrintfBufferStorageBuffer %float_0 %int_0 %int_4", + "DescriptorSet"), + std::make_pair("PrintfBufferStorageBuffer %null %int_0 %int_4", + "DescriptorSet"), + std::make_pair("PrintfBufferStorageBuffer %int_0 %float_0 %int_4", + "Binding"), + std::make_pair("PrintfBufferStorageBuffer %int_0 %null %int_4", + "Binding"), + std::make_pair("PrintfBufferStorageBuffer %int_0 %int_0 %float_0", + "Size"), + std::make_pair("PrintfBufferStorageBuffer %int_0 %int_0 %null", "Size"), + std::make_pair("PrintfBufferPointerPushConstant %float_0 %int_0 %int_4", + "Offset"), + std::make_pair("PrintfBufferPointerPushConstant %null %int_0 %int_4", + "Offset"), + std::make_pair("PrintfBufferPointerPushConstant %int_0 %float_0 %int_4", + "Size"), + std::make_pair("PrintfBufferPointerPushConstant %int_0 %null %int_4", + "Size"), + std::make_pair("PrintfBufferPointerPushConstant %int_0 %int_0 %float_0", + "BufferSize"), + std::make_pair("PrintfBufferPointerPushConstant %int_0 %int_0 %null", + "BufferSize")})); TEST_P(Uint32Constant, Invalid) { const std::string ext_inst = std::get<0>(GetParam()); @@ -6667,7 +7124,7 @@ TEST_P(Uint32Constant, Invalid) { const std::string text = R"( OpCapability Shader OpExtension "SPV_KHR_non_semantic_info" -%ext = OpExtInstImport "NonSemantic.ClspvReflection.1" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.5" OpMemoryModel Logical GLSL450 OpEntryPoint GLCompute %foo "foo" OpExecutionMode %foo LocalSize 1 1 1 @@ -6705,7 +7162,15 @@ INSTANTIATE_TEST_SUITE_P( ::testing::ValuesIn(std::vector>{ std::make_pair("ConstantDataStorageBuffer %int_0 %int_0 %int_0", "Data"), - std::make_pair("ConstantDataUniform %int_0 %int_0 %int_0", "Data")})); + std::make_pair("ConstantDataUniform %int_0 %int_0 %int_0", "Data"), + std::make_pair( + "ProgramScopeVariablesStorageBuffer %int_0 %int_0 %int_0", "Data"), + std::make_pair("ConstantDataPointerPushConstant %int_0 %int_0 %int_0", + "Data"), + std::make_pair( + "ProgramScopeVariablePointerPushConstant %int_0 %int_0 %int_0", + "Data"), + std::make_pair("PrintfInfo %int_0 %int_0", "FormatString")})); TEST_P(StringOperand, Invalid) { const std::string ext_inst = std::get<0>(GetParam()); @@ -6713,7 +7178,7 @@ TEST_P(StringOperand, Invalid) { const std::string text = R"( OpCapability Shader OpExtension "SPV_KHR_non_semantic_info" -%ext = OpExtInstImport "NonSemantic.ClspvReflection.1" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.5" OpMemoryModel Logical GLSL450 OpEntryPoint GLCompute %foo "foo" OpExecutionMode %foo LocalSize 1 1 1 @@ -6741,6 +7206,272 @@ OpFunctionEnd EXPECT_THAT(getDiagnosticString(), HasSubstr(name + " must be an OpString")); } +using VersionCheck = spvtest::ValidateBase>; + +INSTANTIATE_TEST_SUITE_P( + ValidateClspvReflectionVersionCheck, VersionCheck, + ::testing::ValuesIn(std::vector>{ + std::make_pair("ArgumentStorageBuffer %decl %int_0 %int_0 %int_0", 1), + std::make_pair("ArgumentUniform %decl %int_0 %int_0 %int_0", 1), + std::make_pair( + "ArgumentPodStorageBuffer %decl %int_0 %int_0 %int_0 %int_0 %int_0", + 1), + std::make_pair( + "ArgumentPodUniform %decl %int_0 %int_0 %int_0 %int_0 %int_0", 1), + std::make_pair("ArgumentPodPushConstant %decl %int_0 %int_0 %int_0", 1), + std::make_pair("ArgumentSampledImage %decl %int_0 %int_0 %int_0", 1), + std::make_pair("ArgumentStorageImage %decl %int_0 %int_0 %int_0", 1), + std::make_pair("ArgumentSampler %decl %int_0 %int_0 %int_0", 1), + std::make_pair("ArgumentWorkgroup %decl %int_0 %int_0 %int_0", 1), + std::make_pair("SpecConstantWorkgroupSize %int_0 %int_0 %int_0", 1), + std::make_pair("SpecConstantGlobalOffset %int_0 %int_0 %int_0", 1), + std::make_pair("SpecConstantWorkDim %int_0", 1), + std::make_pair("PushConstantGlobalOffset %int_0 %int_0", 1), + std::make_pair("PushConstantEnqueuedLocalSize %int_0 %int_0", 1), + std::make_pair("PushConstantGlobalSize %int_0 %int_0", 1), + std::make_pair("PushConstantRegionOffset %int_0 %int_0", 1), + std::make_pair("PushConstantNumWorkgroups %int_0 %int_0", 1), + std::make_pair("PushConstantRegionGroupOffset %int_0 %int_0", 1), + std::make_pair("ConstantDataStorageBuffer %int_0 %int_0 %data", 1), + std::make_pair("ConstantDataUniform %int_0 %int_0 %data", 1), + std::make_pair("LiteralSampler %int_0 %int_0 %int_0", 1), + std::make_pair( + "PropertyRequiredWorkgroupSize %decl %int_0 %int_0 %int_0", 1), + std::make_pair("SpecConstantSubgroupMaxSize %int_0", 2), + std::make_pair("ArgumentPointerPushConstant %decl %int_0 %int_0 %int_0", + 3), + std::make_pair( + "ArgumentPointerUniform %decl %int_0 %int_0 %int_0 %int_0 %int_0", + 3), + std::make_pair("ProgramScopeVariablesStorageBuffer %int_0 %int_0 %data", + 3), + std::make_pair( + "ProgramScopeVariablePointerRelocation %int_0 %int_0 %int_0", 3), + std::make_pair("ImageArgumentInfoChannelOrderPushConstant %decl %int_0 " + "%int_0 %int_0", + 3), + std::make_pair("ImageArgumentInfoChannelDataTypePushConstant %decl " + "%int_0 %int_0 %int_0", + 3), + std::make_pair("ImageArgumentInfoChannelOrderUniform %decl %int_0 " + "%int_0 %int_0 %int_0 %int_0", + 3), + std::make_pair("ImageArgumentInfoChannelDataTypeUniform %decl %int_0 " + "%int_0 %int_0 %int_0 %int_0", + 3), + std::make_pair("ArgumentStorageTexelBuffer %decl %int_0 %int_0 %int_0", + 4), + std::make_pair("ArgumentUniformTexelBuffer %decl %int_0 %int_0 %int_0", + 4), + std::make_pair("ConstantDataPointerPushConstant %int_0 %int_0 %data", + 5), + std::make_pair( + "ProgramScopeVariablePointerPushConstant %int_0 %int_0 %data", 5), + std::make_pair("PrintfInfo %int_0 %data", 5), + std::make_pair("PrintfBufferStorageBuffer %int_0 %int_0 %int_0", 5), + std::make_pair("PrintfBufferPointerPushConstant %int_0 %int_0 %int_0", + 5)})); + +TEST_P(VersionCheck, V1) { + const std::string ext_inst = std::get<0>(GetParam()); + const uint32_t version = std::get<1>(GetParam()); + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.1" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +%foo_name = OpString "foo" +%data = OpString "1234" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%int_4 = OpConstant %int 4 +%null = OpConstantNull %int +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +%decl = OpExtInst %void %ext Kernel %foo %foo_name +%inst = OpExtInst %void %ext )" + + ext_inst; + + CompileSuccessfully(text); + if (version <= 1) { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires version " + std::to_string(version) + + ", but parsed version is 1")); + } +} + +TEST_P(VersionCheck, V2) { + const std::string ext_inst = std::get<0>(GetParam()); + const uint32_t version = std::get<1>(GetParam()); + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +%foo_name = OpString "foo" +%data = OpString "1234" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%int_4 = OpConstant %int 4 +%null = OpConstantNull %int +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +%decl = OpExtInst %void %ext Kernel %foo %foo_name +%inst = OpExtInst %void %ext )" + + ext_inst; + + CompileSuccessfully(text); + if (version <= 2) { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires version " + std::to_string(version) + + ", but parsed version is 2")); + } +} + +TEST_P(VersionCheck, V3) { + const std::string ext_inst = std::get<0>(GetParam()); + const uint32_t version = std::get<1>(GetParam()); + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.3" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +%foo_name = OpString "foo" +%data = OpString "1234" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%int_4 = OpConstant %int 4 +%null = OpConstantNull %int +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +%decl = OpExtInst %void %ext Kernel %foo %foo_name +%inst = OpExtInst %void %ext )" + + ext_inst; + + CompileSuccessfully(text); + if (version <= 3) { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires version " + std::to_string(version) + + ", but parsed version is 3")); + } +} + +TEST_P(VersionCheck, V4) { + const std::string ext_inst = std::get<0>(GetParam()); + const uint32_t version = std::get<1>(GetParam()); + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.4" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +%foo_name = OpString "foo" +%data = OpString "1234" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%int_4 = OpConstant %int 4 +%null = OpConstantNull %int +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +%decl = OpExtInst %void %ext Kernel %foo %foo_name +%inst = OpExtInst %void %ext )" + + ext_inst; + + CompileSuccessfully(text); + if (version <= 4) { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires version " + std::to_string(version) + + ", but parsed version is 4")); + } +} + +TEST_P(VersionCheck, V5) { + const std::string ext_inst = std::get<0>(GetParam()); + const uint32_t version = std::get<1>(GetParam()); + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%ext = OpExtInstImport "NonSemantic.ClspvReflection.5" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %foo "foo" +OpExecutionMode %foo LocalSize 1 1 1 +%foo_name = OpString "foo" +%data = OpString "1234" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%int_4 = OpConstant %int 4 +%null = OpConstantNull %int +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%void_fn = OpTypeFunction %void +%foo = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +%decl = OpExtInst %void %ext Kernel %foo %foo_name +%inst = OpExtInst %void %ext )" + + ext_inst; + + CompileSuccessfully(text); + if (version <= 5) { + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + } else { + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires version " + std::to_string(version) + + ", but parsed version is 1")); + } +} + } // namespace } // namespace val } // namespace spvtools From ae8d50709fc88cbe66bd42800a4d84f4beb16ae5 Mon Sep 17 00:00:00 2001 From: Rafael Marinheiro Date: Mon, 16 Jan 2023 15:29:02 +0000 Subject: [PATCH 004/523] Add Github Actions to test Bazel builds. (#5043) * Add github action to build/test code using Bazel. * Add a cache for Bazel github actions. --- .github/workflows/bazel.yml | 26 ++++++++++++++++++++++++++ .github/workflows/wasm.yml | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/bazel.yml diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml new file mode 100644 index 0000000000..c101eb66c4 --- /dev/null +++ b/.github/workflows/bazel.yml @@ -0,0 +1,26 @@ +name: Build and Test with Bazel + +on: [push, pull_request] + +jobs: + build: + timeout-minutes: 120 + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v3 + - name: Download dependencies + run: python3 utils/git-sync-deps + - name: Mount Bazel cache + uses: actions/cache@v3 + with: + path: ~/.bazel/cache + key: bazel-cache-${{ runner.os }} + - name: Build All + run: bazel --output_user_root=~/.bazel/cache build //... + - name: Test All + run: bazel --output_user_root=~/.bazel/cache test //... diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 008a8678c5..0fc18062b4 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -1,6 +1,6 @@ name: Wasm Build -on: [ push, pull_request ] +on: [push, pull_request] jobs: build: From ae893db200e5beb569cfa9fe297319341cb0a27e Mon Sep 17 00:00:00 2001 From: Juan Ramos <114601453+juan-lunarg@users.noreply.github.com> Date: Mon, 16 Jan 2023 08:52:31 -0700 Subject: [PATCH 005/523] cmake: Remove old policy code (#5055) --- CMakeLists.txt | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f9bfb4a303..a0f4eb23f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,18 +13,11 @@ # limitations under the License. cmake_minimum_required(VERSION 3.17.2) -if (POLICY CMP0048) - cmake_policy(SET CMP0048 NEW) -endif() -if (POLICY CMP0054) - # Avoid dereferencing variables or interpret keywords that have been - # quoted or bracketed. - # https://cmake.org/cmake/help/v3.1/policy/CMP0054.html - cmake_policy(SET CMP0054 NEW) -endif() -set_property(GLOBAL PROPERTY USE_FOLDERS ON) project(spirv-tools) + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + enable_testing() set(SPIRV_TOOLS "SPIRV-Tools") From 1dad9914410e5ef32606af476a3d90410275df55 Mon Sep 17 00:00:00 2001 From: Juan Ramos <114601453+juan-lunarg@users.noreply.github.com> Date: Mon, 16 Jan 2023 08:55:35 -0700 Subject: [PATCH 006/523] cmake: Modernize install(TARGET) usage (#5056) --- source/CMakeLists.txt | 5 +---- source/diff/CMakeLists.txt | 5 +---- source/fuzz/CMakeLists.txt | 5 +---- source/link/CMakeLists.txt | 5 +---- source/lint/CMakeLists.txt | 5 +---- source/opt/CMakeLists.txt | 5 +---- source/reduce/CMakeLists.txt | 5 +---- tools/CMakeLists.txt | 5 +---- 8 files changed, 8 insertions(+), 32 deletions(-) diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index e85ec9d9ae..acfa0c123b 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -425,10 +425,7 @@ if (ANDROID) endif() if(ENABLE_SPIRV_TOOLS_INSTALL) - install(TARGETS ${SPIRV_TOOLS_TARGETS} EXPORT ${SPIRV_TOOLS}Targets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS ${SPIRV_TOOLS_TARGETS} EXPORT ${SPIRV_TOOLS}Targets) export(EXPORT ${SPIRV_TOOLS}Targets FILE ${SPIRV_TOOLS}Target.cmake) spvtools_config_package_dir(${SPIRV_TOOLS} PACKAGE_DIR) diff --git a/source/diff/CMakeLists.txt b/source/diff/CMakeLists.txt index 1328699ab1..52f18f2d13 100644 --- a/source/diff/CMakeLists.txt +++ b/source/diff/CMakeLists.txt @@ -39,10 +39,7 @@ set_property(TARGET SPIRV-Tools-diff PROPERTY FOLDER "SPIRV-Tools libraries") spvtools_check_symbol_exports(SPIRV-Tools-diff) if(ENABLE_SPIRV_TOOLS_INSTALL) - install(TARGETS SPIRV-Tools-diff EXPORT SPIRV-Tools-diffTargets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS SPIRV-Tools-diff EXPORT SPIRV-Tools-diffTargets) export(EXPORT SPIRV-Tools-diffTargets FILE SPIRV-Tools-diffTargets.cmake) spvtools_config_package_dir(SPIRV-Tools-diff PACKAGE_DIR) diff --git a/source/fuzz/CMakeLists.txt b/source/fuzz/CMakeLists.txt index dd674dd04c..86ee657a1c 100644 --- a/source/fuzz/CMakeLists.txt +++ b/source/fuzz/CMakeLists.txt @@ -470,10 +470,7 @@ if(SPIRV_BUILD_FUZZER) spvtools_check_symbol_exports(SPIRV-Tools-fuzz) if(ENABLE_SPIRV_TOOLS_INSTALL) - install(TARGETS SPIRV-Tools-fuzz EXPORT SPIRV-Tools-fuzzTargets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS SPIRV-Tools-fuzz EXPORT SPIRV-Tools-fuzzTargets) export(EXPORT SPIRV-Tools-fuzzTargets FILE SPIRV-Tools-fuzzTarget.cmake) spvtools_config_package_dir(SPIRV-Tools-fuzz PACKAGE_DIR) diff --git a/source/link/CMakeLists.txt b/source/link/CMakeLists.txt index a452a107df..a35b9a58fd 100644 --- a/source/link/CMakeLists.txt +++ b/source/link/CMakeLists.txt @@ -31,10 +31,7 @@ set_property(TARGET SPIRV-Tools-link PROPERTY FOLDER "SPIRV-Tools libraries") spvtools_check_symbol_exports(SPIRV-Tools-link) if(ENABLE_SPIRV_TOOLS_INSTALL) - install(TARGETS SPIRV-Tools-link EXPORT SPIRV-Tools-linkTargets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS SPIRV-Tools-link EXPORT SPIRV-Tools-linkTargets) export(EXPORT SPIRV-Tools-linkTargets FILE SPIRV-Tools-linkTargets.cmake) spvtools_config_package_dir(SPIRV-Tools-link PACKAGE_DIR) diff --git a/source/lint/CMakeLists.txt b/source/lint/CMakeLists.txt index 1feae3f94d..4704beb1fc 100644 --- a/source/lint/CMakeLists.txt +++ b/source/lint/CMakeLists.txt @@ -46,10 +46,7 @@ set_property(TARGET SPIRV-Tools-lint PROPERTY FOLDER "SPIRV-Tools libraries") spvtools_check_symbol_exports(SPIRV-Tools-lint) if(ENABLE_SPIRV_TOOLS_INSTALL) - install(TARGETS SPIRV-Tools-lint EXPORT SPIRV-Tools-lintTargets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS SPIRV-Tools-lint EXPORT SPIRV-Tools-lintTargets) export(EXPORT SPIRV-Tools-lintTargets FILE SPIRV-Tools-lintTargets.cmake) spvtools_config_package_dir(SPIRV-Tools-lint PACKAGE_DIR) diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt index c34c38d0b8..eea3c47532 100644 --- a/source/opt/CMakeLists.txt +++ b/source/opt/CMakeLists.txt @@ -271,10 +271,7 @@ set_property(TARGET SPIRV-Tools-opt PROPERTY FOLDER "SPIRV-Tools libraries") spvtools_check_symbol_exports(SPIRV-Tools-opt) if(ENABLE_SPIRV_TOOLS_INSTALL) - install(TARGETS SPIRV-Tools-opt EXPORT SPIRV-Tools-optTargets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS SPIRV-Tools-opt EXPORT SPIRV-Tools-optTargets) export(EXPORT SPIRV-Tools-optTargets FILE SPIRV-Tools-optTargets.cmake) spvtools_config_package_dir(SPIRV-Tools-opt PACKAGE_DIR) diff --git a/source/reduce/CMakeLists.txt b/source/reduce/CMakeLists.txt index 6fd8409f69..9ebe4183ef 100644 --- a/source/reduce/CMakeLists.txt +++ b/source/reduce/CMakeLists.txt @@ -101,10 +101,7 @@ set_property(TARGET SPIRV-Tools-reduce PROPERTY FOLDER "SPIRV-Tools libraries") spvtools_check_symbol_exports(SPIRV-Tools-reduce) if(ENABLE_SPIRV_TOOLS_INSTALL) - install(TARGETS SPIRV-Tools-reduce EXPORT SPIRV-Tools-reduceTargets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS SPIRV-Tools-reduce EXPORT SPIRV-Tools-reduceTargets) export(EXPORT SPIRV-Tools-reduceTargets FILE SPIRV-Tools-reduceTarget.cmake) spvtools_config_package_dir(SPIRV-Tools-reduce PACKAGE_DIR) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index ad5f336fec..d272b08e71 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -69,10 +69,7 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES}) endif(SPIRV_BUILD_FUZZER) if(ENABLE_SPIRV_TOOLS_INSTALL) - install(TARGETS ${SPIRV_INSTALL_TARGETS} EXPORT SPIRV-Tools-toolsTargets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS ${SPIRV_INSTALL_TARGETS} EXPORT SPIRV-Tools-toolsTargets) export(EXPORT SPIRV-Tools-toolsTargets FILE SPIRV-Tools-toolsTargets.cmake) spvtools_config_package_dir(SPIRV-Tools-tools PACKAGE_DIR) From 0e6fbba7762c071118b3e84258a358ede31fb609 Mon Sep 17 00:00:00 2001 From: Diego Novillo Date: Mon, 16 Jan 2023 15:21:17 -0500 Subject: [PATCH 007/523] Prepare for v2023.1 release (#5057) * Roll external/effcee/ 35912e1b7..c7b4db79f (1 commit) https://github.com/google/effcee/compare/35912e1b7778...c7b4db79f340 $ git log 35912e1b7..c7b4db79f --date=short --no-merges --format='%ad %ae %s' 2022-12-20 dneto Update Bazel external dependencies Created with: roll-dep external/effcee * Roll external/googletest/ v1.12.0..356fc3012 (117 commits) https://github.com/google/googletest/compare/v1.12.0...356fc3012513 $ git log v1.12.0..356fc3012 --date=short --no-merges --format='%ad %ae %s' 2023-01-12 tomhughes Fix -Wshadow warnings 2023-01-12 dmauro Add an explicit #error that C++ versions less than C++14 are not supported 2023-01-11 dmauro Update GoogleTest dependencies 2023-01-05 tomhughes Fix GTEST_OS_ESP8266 check 2023-01-05 tomhughes IWYU: Add missing std includes 2023-01-04 dmauro Workaround for GCC12 bug illustrated by https://godbolt.org/z/Pe5aE59xG 2023-01-04 tomhughes Fix _MSC_VER check 2022-12-22 absl-team Use a more recent commit of googletest that uses OS constraints from @platforms//os:* instead of from @build_tools//platforms:* 2022-12-20 absl-team Fix a typo in the documentation for "Using Predicates as Matchers". 2022-12-20 dinor Comment that q0_ in primer should remain empty 2022-12-19 absl-team Specify a name for a `Property` in a code example. 2022-12-15 absl-team Shut up a Clang warning. 2022-12-14 absl-team Fix a typo in the gMock sample code for Defining a Custom Matcher Class. 2022-12-12 dmauro Convert feature requests to a form 2022-12-12 absl-team Refactor matrix verification into VerifyMatchMatrix. 2022-12-12 absl-team Introduces a new porting flag (GTEST_HAS_FILE_SYSTEM) to indicate whether a platform supports filesystem operations. 2022-12-08 tomhughes Fall back to the system clock when building with newlib on a system without a monotonic clock. 2022-12-07 dmauro Migrate GoogleTest to a bug report template and add a link to the discussion forum for non-bugs 2022-12-05 dmauro Remove the unused class TestNameIs 2022-11-30 absl-team Make SizeIsMatcher::Impl conform to the contract of MatcherDescriberInterface. 2022-11-29 absl-team Disables `-Wunused-member-function` and `-Wused-but-marked-unused` that trigger via `MOCK_METHOD()` and `EXPECT_THAT()` macros. 2022-11-23 absl-team This commit fixes a minor verb conjugation error in gmock_cook_book.md. 2022-11-20 i Change MakeUnique -> std::make_unique in docs 2022-11-16 absl-team When printing floating-point numbers, print full precision by default. 2022-11-15 absl-team Remove incorrect usage of GTEST_ATTRIBUTE_UNUSED_ on classes. 2022-11-12 m.h1ch4m 2022-11-12 m.h1ch4m fixing gcc.gnu domain redirection 2022-11-11 absl-team Defined a testing::SrcDir() function that returns the name of a directory where ancillary data files can be found. 2022-11-10 i Support kitty TERM 2022-11-08 absl-team Remove incorrect GTEST_ATTRIBUTE_UNUSED_ from InSequence class. 2022-11-07 absl-team RecordProperty serializes ints and 64-bit ints, including size_ts 2022-11-05 absl-team Fix typo in documentation of ConvertGenerator() 2022-11-03 absl-team Add documentation for `--gunit_recreate_environments_when_repeating`. 2022-10-25 dinor Use git commit hash in CMake quickstart 2022-10-24 absl-team Clarify that parameter generator does not evaluate immediately 2022-10-21 i Fix format without expectation name 2022-10-21 i Change messages 2022-10-20 i Allow naming expectations #3970 2022-10-18 absl-team CMake: Add GTEST_HAS_ABSL build option for using Absl 2022-10-18 absl-team Adds Win32 UNC path support to FilePath::IsAbsolutePath() and FilePath::IsRootDirectory() in GoogleTest 2022-10-17 dmauro Fix detection of the no_sanitize("hwaddress") attribute 2022-10-17 dinor Add Windows CI script 2022-10-16 i Add return for GTEST_FAIL_AT 2022-10-14 dmauro Use attribute testing to simplify portable attribute macros 2022-10-14 absl-team Terse printing of std::reference_wrapper hides pointer 2022-10-14 janbruckner Fix table markup in testing.md 2022-10-12 absl-team Workaround for Visual C++ error C2039 with std::tuple_element_t. 2022-10-11 i Fix JSON output format #3884 2022-10-07 ferenc.gm Suggests a release with fixed CMakeLists.txt 2022-10-08 julian.amann Update rules_python, bazel_skylib and platfroms (...) 2022-09-01 absl-team Fixed header guards to match style guide conventions. 2022-08-26 absl-team Consider all TERM values ending in "-256color" to be color supporting. In particular this handles TERM=hterm-256color correctly. 2022-08-22 hardikv Add support of 19-member structs to gmock UnpackStructImpl. 2022-08-19 keithbsmiley bazel: move -std=c++14 to .bazelrc 2022-08-16 dmauro Update README.md to point to the Foundational C++ Support Policy 2022-08-12 dmauro Add --features=external_include_paths to Bazel CI to ignore warnings from dependencies 2022-08-08 dinor gtest_unittest: Call FAIL() in lambda, fix incorrect fatality expectation 2022-08-04 dinor Explicitly instantiate matchee std::string in MatchesRegex 2022-07-31 bmburstein Custom type with Combine(). Fix for #3781 2022-07-28 absl-team Add support of 18-member structs to gmock UnpackStructImpl. 2022-07-25 dinor Add IsEmpty overload for C-style strings 2022-07-21 thegeorg Continuation for #3183 2022-07-20 matdibu gtest-death-test: add 'noreturn' 2022-06-28 dev Set cmake policy CMP0069 2022-07-14 polushin export ThreadLocalValueHolderBase which is required by exported APIs. 2022-07-11 polushin cmake: make PDB output directory match that of a static library. 2022-07-11 polushin cmake: find python in order specified by PATH environment variable. 2022-07-11 dmauro Add envvar BAZEL_CXXOPTS=-std=c++14 to the GitHub Actions CI 2022-07-08 dmauro CMake: raise the default C++ standard to cxx_std_14 2022-07-07 ckennelly Enable heterogeneous lookup for RegisteredTestsMap. 2022-07-01 nikiforov.al cleanup from unique_ptr branch 2022-07-01 dmauro Remove the Bazel provided default cxxopt -std=c++0x and replace it with -std=c++14 when testing with GCC 5. 2022-07-01 57719497+yutotnh fix: some typos in source 2022-07-01 57719497+yutotnh fix: typo in test name 2022-07-01 57719497+yutotnh fix: some typos in comment 2022-06-30 dmauro Remove support for C++11 2022-06-30 dmauro Update version number in CMakeLists.txt Note that this is 1.12.1 as there will be a patch release to fix this 2022-06-29 absl-team Add support of 17-member structs to gmock UnpackStructImpl. 2022-06-27 absl-team Mark internal-only function as having internal linkage. 2022-06-27 93249401+assafpr Update gtest.cc 2022-06-27 93249401+assafpr Update gmock-matchers.h 2022-06-27 93249401+assafpr Update gmock-actions.h 2022-06-27 93249401+assafpr Update gmock-spec-builders_test.cc 2022-06-27 93249401+assafpr Update gtest-death-test.cc 2022-06-27 93249401+assafpr Update gmock-spec-builders.cc 2022-06-27 93249401+assafpr Update advanced.md 2022-06-26 asmodai27 Avoid implicit conversion from int to char 2022-06-26 asmodai27 Avoid implicit conversion from int to char 2022-06-25 julian.arkenau docs: update googletest README for release 1.12.0 2022-06-23 dmauro Update README.md for release 1.12.0 2022-06-22 93249401+assafpr documentation, change mater branch to main 2022-06-22 93249401+assafpr Update faq.md 2022-06-22 93249401+assafpr Update CONTRIBUTING.md 2022-06-22 93249401+assafpr documentation, change mater branch to main 2022-06-22 93249401+assafpr documentation, change mater branch to main 2022-06-22 93249401+assafpr Update gmock_output_test_golden.txt 2022-06-22 93249401+assafpr change link from master to main in documentation 2022-05-31 gpetit Fix for undefined symbol: testing::internal::Random::kMaxRange 2022-05-18 akohlmey set -utf-8 flag only for real MSVC compilers. E.g. not Intel's icx.exe 2022-03-26 perez.cs Fix quickstart-cmake documentation Created with: roll-dep external/googletest * Roll external/re2/ d2836d1b1..954656f47 (13 commits) https://github.com/google/re2/compare/d2836d1b1c34...954656f47fe8 $ git log d2836d1b1..954656f47 --date=short --no-merges --format='%ad %ae %s' 2022-12-07 junyer Restore the "lock counter" option for `Mutex`. 2022-11-29 junyer Avoid "immortal" dynamic memory allocations. 2022-11-23 junyer Drop old compiler versions from the build matrix. 2022-11-22 junyer Control the maximum count permitted by `GlobalReplace()`. 2022-11-20 junyer Specify just the MAJOR.MINOR components to `cmake_minimum_required()`. 2022-11-18 junyer Install `re2.pc` with CMake too. 2022-10-26 junyer Reword some comments in `re2.h`. 2022-10-17 junyer Add the no-op GitHub Actions workflow for Python releases. 2022-10-17 junyer Revert "Add a GitHub Actions workflow for Python releases." 2022-10-17 junyer Add a GitHub Actions workflow for Python releases. 2022-10-17 junyer Revert "Add a GitHub Actions workflow for Python releases." 2022-10-14 junyer Add a GitHub Actions workflow for Python releases. 2022-10-14 junyer Bump versions of actions to address warnings. Created with: roll-dep external/re2 * Update CHANGES * Fix release name * Revert "Roll external/googletest/ v1.12.0..356fc3012 (117 commits)" This reverts commit 45f5de67c6819dd2f3e6729ae0131488a0cd91fa. Rolling back this update to googletest to prevent build failures. Our CI systems are still assuming C++0x support. Post release, SPIRV-Tools will move to require C++17 minimum. --- CHANGES | 28 ++++++++++++++++++++++++++-- DEPS | 4 ++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 967be16d93..98a8d20d12 100644 --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,31 @@ Revision history for SPIRV-Tools -v2022.5-dev 2022-10-12 - - Renamed "master" to "main" (issue#5051) +v2023.1-dev 2023-01-13 + - General + - Renamed "master" to "main" (issue#5051) + - Validate version 5 of clspv reflection (#5050) + - Remove testing support for VS2015 (#5027) + - Fix undef behaviour in hex float parsing (#5025) + - Require C++11 *or later* (#5020) + - Optimizer + - Optimize allocation of spvtools::opt::Instruction::operands_ (#5024) + - spirv-opt: Fix OpCompositeInsert with Null Constant (#5008) + - spirv-opt: Handle null CompositeInsert (#4998) + - Add option to ADCE to remove output variables from interface. (#4994) + - Add support for tesc, tese and geom to EliminateDead*Components (#4990) + - Add pass to eliminate dead output components (#4982) + - spirv-opt: Add const folding for CompositeInsert (#4943) + - Add passes to eliminate dead output stores (#4970) + - Prevent eliminating case constructs in block merging (#4976) + - Validator + - Fix layout validation (#5015) + - Fix use of invalid analysis (#5013) + - Fix infinite loop in validator (#5006) + - Add validation support for SPV_NV_shader_invocation_reorder. (#4979) + - Only validate full layout in Vulkan environments (#4972) + - spirv-val: Label new Vulkan OpPtrAccessChain VUs (#4975) + - spirv-val: Add OpPtrAccessChain Base checks (#4965) + v2022.4 2022-10-12 - General diff --git a/DEPS b/DEPS index 6530a26873..c6e32ed601 100644 --- a/DEPS +++ b/DEPS @@ -3,7 +3,7 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'effcee_revision': '35912e1b7778ec2ddcff7e7188177761539e59e0', + 'effcee_revision': 'c7b4db79f340f7a9981e8a484f6d5785e24242d1', # Pin to the last version of googletest that supports C++11. # Anything later requires C++14 @@ -12,7 +12,7 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', - 're2_revision': 'd2836d1b1c34c4e330a85a1006201db474bf2c8a', + 're2_revision': '954656f47fe8fb505d4818da1e128417a79ea500', 'spirv_headers_revision': 'd13b52222c39a7e9a401b44646f0ca3a640fbd47', } From ba4c9fe53464ca29ee3501ca46cc9a9cd693bbe2 Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Mon, 16 Jan 2023 13:57:37 -0700 Subject: [PATCH 008/523] Instrument: Fix bindless checking for BufferDeviceAddress (#5049) Avoid using OpConstantNull with types that do not allow it. Update existing tests for slight changes in code generation. Add new tests based on the Vulkan Validation layer test case that exposed this problem. --- source/opt/inst_bindless_check_pass.cpp | 30 +- source/opt/inst_buff_addr_check_pass.cpp | 9 +- test/opt/inst_bindless_check_test.cpp | 595 +++++++++++++---------- test/opt/inst_buff_addr_check_test.cpp | 128 +++++ 4 files changed, 478 insertions(+), 284 deletions(-) diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp index ca36dd6062..ad581e14c9 100644 --- a/source/opt/inst_bindless_check_pass.cpp +++ b/source/opt/inst_bindless_check_pass.cpp @@ -536,6 +536,8 @@ void InstBindlessCheckPass::GenCheckCode( new BasicBlock(std::move(valid_label))); builder.SetInsertPoint(&*new_blk_ptr); uint32_t new_ref_id = CloneOriginalReference(ref, &builder); + uint32_t null_id = 0; + uint32_t ref_type_id = ref->ref_inst->type_id(); (void)builder.AddBranch(merge_blk_id); new_blocks->push_back(std::move(new_blk_ptr)); // Gen invalid block @@ -563,10 +565,23 @@ void InstBindlessCheckPass::GenCheckCode( GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx, {error_id, u_index_id, u_length_id}, &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(); + analysis::Type* ref_type = type_mgr->GetType(ref_type_id); + if (ref_type->AsPointer() != nullptr) { + context()->AddCapability(spv::Capability::Int64); + uint32_t null_u64_id = GetNullId(GetUint64Id()); + Instruction* null_ptr_inst = builder.AddUnaryOp( + ref_type_id, spv::Op::OpConvertUToPtr, null_u64_id); + null_id = null_ptr_inst->result_id(); + } else { + null_id = GetNullId(ref_type_id); + } + } // Remember last invalid block id uint32_t last_invalid_blk_id = new_blk_ptr->GetLabelInst()->result_id(); // Gen zero for invalid reference - uint32_t ref_type_id = ref->ref_inst->type_id(); (void)builder.AddBranch(merge_blk_id); new_blocks->push_back(std::move(new_blk_ptr)); // Gen merge block @@ -577,8 +592,7 @@ void InstBindlessCheckPass::GenCheckCode( // reference. if (new_ref_id != 0) { Instruction* phi_inst = builder.AddPhi( - ref_type_id, {new_ref_id, valid_blk_id, GetNullId(ref_type_id), - last_invalid_blk_id}); + ref_type_id, {new_ref_id, valid_blk_id, null_id, last_invalid_blk_id}); context()->ReplaceAllUsesWith(ref->ref_inst->result_id(), phi_inst->result_id()); } @@ -734,15 +748,7 @@ void InstBindlessCheckPass::GenTexBuffCheckCode( if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageArrayed) != 0) return; if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageMS) != 0) return; // Enable ImageQuery Capability if not yet enabled - if (!get_feature_mgr()->HasCapability(spv::Capability::ImageQuery)) { - std::unique_ptr cap_image_query_inst( - new Instruction(context(), spv::Op::OpCapability, 0, 0, - std::initializer_list{ - {SPV_OPERAND_TYPE_CAPABILITY, - {uint32_t(spv::Capability::ImageQuery)}}})); - get_def_use_mgr()->AnalyzeInstDefUse(&*cap_image_query_inst); - context()->AddCapability(std::move(cap_image_query_inst)); - } + context()->AddCapability(spv::Capability::ImageQuery); // Move original block's preceding instructions into first new block std::unique_ptr new_blk_ptr; MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr); diff --git a/source/opt/inst_buff_addr_check_pass.cpp b/source/opt/inst_buff_addr_check_pass.cpp index be361e69be..97d25f3c99 100644 --- a/source/opt/inst_buff_addr_check_pass.cpp +++ b/source/opt/inst_buff_addr_check_pass.cpp @@ -408,14 +408,7 @@ uint32_t InstBuffAddrCheckPass::GenSearchAndTest(Instruction* ref_inst, InstructionBuilder* builder, uint32_t* ref_uptr_id) { // Enable Int64 if necessary - if (!get_feature_mgr()->HasCapability(spv::Capability::Int64)) { - std::unique_ptr cap_int64_inst(new Instruction( - context(), spv::Op::OpCapability, 0, 0, - std::initializer_list{{SPV_OPERAND_TYPE_CAPABILITY, - {uint32_t(spv::Capability::Int64)}}})); - get_def_use_mgr()->AnalyzeInstDefUse(&*cap_int64_inst); - context()->AddCapability(std::move(cap_int64_inst)); - } + context()->AddCapability(spv::Capability::Int64); // Convert reference pointer to uint64 uint32_t ref_ptr_id = ref_inst->GetSingleWordInOperand(0); Instruction* ref_uptr_inst = diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp index 4f4b6681c3..3600d0d228 100644 --- a/test/opt/inst_bindless_check_test.cpp +++ b/test/opt/inst_bindless_check_test.cpp @@ -159,9 +159,9 @@ static const std::string kStreamWrite4Ray = kStreamWrite4Begin + R"( ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint %90 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint %90 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint %90 2 +; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}} @@ -567,14 +567,12 @@ OpDecorate %_entryPointOutput_vColor Location 0 %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output ; CHECK: %bool = OpTypeBool -; CHECK: %48 = OpTypeFunction %void %uint %uint %uint %uint ; 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: %v4uint = OpTypeVector %uint 4 -; CHECK: %103 = OpConstantNull %v4float +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -601,10 +599,10 @@ OpStore %_entryPointOutput_vColor %37 ; CHECK: %46 = OpImageSampleImplicitLod %v4float %45 %30 ; CHECK: OpBranch %41 ; CHECK: %43 = OpLabel -; CHECK: %102 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_56 %uint_0 %32 %uint_128 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_56 %uint_0 %32 %uint_128 ; CHECK: OpBranch %41 ; CHECK: %41 = OpLabel -; CHECK: %104 = OpPhi %v4float %46 %42 %103 %43 +; CHECK: %104 = OpPhi %v4float %46 %42 [[null_v4float]] %43 ; CHECK: OpStore %_entryPointOutput_vColor %104 OpReturn OpFunctionEnd @@ -706,14 +704,14 @@ OpDecorate %_entryPointOutput_vColor Location 0 %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output ; CHECK: %bool = OpTypeBool -; CHECK: %56 = OpTypeFunction %void %uint %uint %uint %uint +; CHECK: {{%\w+}} = OpTypeFunction %void %uint %uint %uint %uint ; 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: %v4uint = OpTypeVector %uint 4 -; CHECK: %111 = OpConstantNull %v4float +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -738,10 +736,10 @@ OpDecorate %_entryPointOutput_vColor Location 0 ; CHECK: %54 = OpImageSampleImplicitLod %v4float %53 %31 ; CHECK: OpBranch %49 ; CHECK: %51 = OpLabel -; CHECK: %110 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_58 %uint_0 %33 %uint_128 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_58 %uint_0 %33 %uint_128 ; CHECK: OpBranch %49 ; CHECK: %49 = OpLabel -; CHECK: %112 = OpPhi %v4float %54 %50 %111 %51 +; CHECK: %112 = OpPhi %v4float %54 %50 [[null_v4float]] %51 %39 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1 %40 = OpLoad %uint %39 %41 = OpAccessChain %_ptr_UniformConstant_17 %g_tColor %40 @@ -763,7 +761,7 @@ OpDecorate %_entryPointOutput_vColor Location 0 ; CHECK: %121 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_64 %uint_0 %40 %uint_128 ; CHECK: OpBranch %114 ; CHECK: %114 = OpLabel -; CHECK: %122 = OpPhi %v4float %119 %115 %111 %116 +; CHECK: %122 = OpPhi %v4float %119 %115 [[null_v4float]] %116 ; CHECK: %45 = OpFAdd %v4float %112 %122 OpStore %_entryPointOutput_vColor %45 OpReturn @@ -835,14 +833,13 @@ OpDecorate %_entryPointOutput_vColor Location 0 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output ; CHECK: uint_0 = OpConstant %uint 0 ; CHECK: bool = OpTypeBool -; CHECK: %86 = OpTypeFunction %void %uint %uint %uint %uint ; 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: %v4uint = OpTypeVector %uint 4 -; CHECK: %141 = OpConstantNull %v4float +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -868,10 +865,10 @@ OpStore %_entryPointOutput_vColor %71 ; CHECK: %84 = OpImageRead %v4float %83 %53 ; CHECK: OpBranch %79 ; CHECK: %81 = OpLabel -; CHECK: %140 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %64 %uint_128 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %64 %uint_128 ; CHECK: OpBranch %79 ; CHECK: %79 = OpLabel -; CHECK: %142 = OpPhi %v4float %84 %80 %141 %81 +; CHECK: %142 = OpPhi %v4float %84 %80 [[null_v4float]] %81 ; CHECK: OpStore %_entryPointOutput_vColor %142 OpReturn OpFunctionEnd @@ -940,14 +937,13 @@ OpDecorate %_entryPointOutput_vColor Location 0 %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output ; CHECK: uint_0 = OpConstant %uint 0 ; CHECK: bool = OpTypeBool -; CHECK: %81 = OpTypeFunction %void %uint %uint %uint %uint ; 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: %v4uint = OpTypeVector %uint 4 -; CHECK: %136 = OpConstantNull %v4float +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -971,10 +967,10 @@ OpStore %_entryPointOutput_vColor %71 ; CHECK: %79 = OpImageSampleImplicitLod %v4float %78 %53 ; CHECK: OpBranch %75 ; CHECK: %77 = OpLabel -; CHECK: %135 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_49 %uint_0 %64 %uint_128 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_49 %uint_0 %64 %uint_128 ; CHECK: OpBranch %75 ; CHECK: %75 = OpLabel -; CHECK: %137 = OpPhi %v4float %79 %76 %136 %77 +; CHECK: %137 = OpPhi %v4float %79 %76 [[null_v4float]] %77 ; CHECK: OpStore %_entryPointOutput_vColor %137 OpReturn OpFunctionEnd @@ -1167,14 +1163,13 @@ OpDecorate %coords2D Location 0 %_ptr_Input_v2float = OpTypePointer Input %v2float %coords2D = OpVariable %_ptr_Input_v2float Input ; CHECK: %bool = OpTypeBool -; CHECK: %54 = OpTypeFunction %void %uint %uint %uint %uint ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint )" + 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: %106 = OpConstantNull %v4float +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -1205,11 +1200,11 @@ OpStore %40 %38 ; CHECK: %51 = OpImageSampleExplicitLod %v4float %50 %40 Lod %41 ; CHECK: OpBranch %47 ; CHECK: %49 = OpLabel -; CHECK: %52 = OpBitcast %uint %37 -; CHECK: %105 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_74 %uint_0 %52 %uint_128 +; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %37 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_74 %uint_0 [[bitcast_result]] %uint_128 ; CHECK: OpBranch %47 ; CHECK: %47 = OpLabel -; CHECK: %107 = OpPhi %v4float %51 %48 %106 %49 +; CHECK: %107 = OpPhi %v4float %51 %48 [[null_v4float]] %49 ; CHECK: %43 = OpAccessChain %_ptr_Output_v4float %_ %int_0 ; CHECK: OpStore %43 %107 OpReturn @@ -1309,7 +1304,6 @@ OpDecorate %uniform_index_buffer Binding 0 %_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float %_ptr_Output_v4float = OpTypePointer Output %v4float ; CHECK: %bool = OpTypeBool -; CHECK: %40 = OpTypeFunction %void %uint %uint %uint %uint ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint )" + kOutputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint @@ -1319,7 +1313,7 @@ OpDecorate %uniform_index_buffer Binding 0 ; CHECK: %_ptr_Input_v3float = OpTypePointer Input %v3float ; CHECK: %gl_TessCoord = OpVariable %_ptr_Input_v3float Input ; CHECK: %v3uint = OpTypeVector %uint 3 -; CHECK: %101 = OpConstantNull %v4float +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -1338,10 +1332,10 @@ OpDecorate %uniform_index_buffer Binding 0 ; CHECK: %38 = OpLoad %v4float %29 ; CHECK: OpBranch %35 ; CHECK: %37 = OpLabel -; CHECK: %100 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_63 %uint_0 %28 %uint_11 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_63 %uint_0 %28 %uint_11 ; CHECK: OpBranch %35 ; CHECK: %35 = OpLabel -; CHECK: %102 = OpPhi %v4float %38 %36 %101 %37 +; CHECK: %102 = OpPhi %v4float %38 %36 [[null_v4float]] %37 %31 = OpAccessChain %_ptr_Output_v4float %_ %int_0 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 @@ -1435,14 +1429,13 @@ OpDecorate %_entryPointOutput_vColor Location 0 %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output ; CHECK: %bool = OpTypeBool -; CHECK: %70 = OpTypeFunction %void %uint %uint %uint %uint ; 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: %v4uint = OpTypeVector %uint 4 -; CHECK: %125 = OpConstantNull %v4float +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -1492,13 +1485,16 @@ OpLine %1 24 0 ; CHECK: OpNoLine ; CHECK: OpBranch %63 ; CHECK: %65 = OpLabel -; CHECK: %124 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_109 %uint_0 %50 %uint_128 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_109 %uint_0 %50 %uint_128 ; CHECK: OpBranch %63 ; CHECK: %63 = OpLabel -; CHECK: %126 = OpPhi %v4float %68 %64 %125 %65 +; CHECK: [[phi_result:%\w+]] = OpPhi %v4float %68 %64 [[null_v4float]] %65 ; CHECK: OpLine %5 24 0 %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]] OpLine %1 25 0 %48 = OpLoad %PS_OUTPUT %ps_output OpReturnValue %48 @@ -1580,13 +1576,11 @@ OpDecorate %_entryPointOutput_vColor Location 0 )" + kInputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %bool = OpTypeBool -; CHECK: %65 = OpTypeFunction %void %uint %uint %uint %uint )" + kOutputGlobals + R"( ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ; CHECK: %v4uint = OpTypeVector %uint 4 -; CHECK: %116 = OpConstantNull %v4float -; CHECK: %119 = OpTypeFunction %uint %uint %uint %uint %uint +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -1624,14 +1618,14 @@ OpStore %_entryPointOutput_vColor %71 ; CHECK: %144 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_59 %uint_1 %32 %uint_0 ; CHECK: OpBranch %138 ; CHECK: %138 = OpLabel -; CHECK: %145 = OpPhi %v4float %143 %139 %116 %140 +; CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float %143 %139 [[null_v4float]] %140 ; CHECK: OpBranch %58 ; CHECK: %60 = OpLabel -; CHECK: %115 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_59 %uint_0 %32 %55 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_59 %uint_0 %32 %55 ; CHECK: OpBranch %58 ; CHECK: %58 = OpLabel -; CHECK: %117 = OpPhi %v4float %145 %138 %116 %60 -; CHECK: OpStore %_entryPointOutput_vColor %117 +; CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float [[phi_result_1]] %138 [[null_v4float]] %60 +; CHECK: OpStore %_entryPointOutput_vColor [[phi_result_2]] OpReturn OpFunctionEnd )"; @@ -1698,12 +1692,11 @@ OpDecorate %_entryPointOutput_vColor Location 0 )" + kInputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %bool = OpTypeBool -; CHECK: %61 = OpTypeFunction %void %uint %uint %uint %uint )" + kOutputGlobals + R"( ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ; CHECK: %v4uint = OpTypeVector %uint 4 -; CHECK: %113 = OpConstantNull %v4float +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -1728,11 +1721,11 @@ OpStore %_entryPointOutput_vColor %24 ; CHECK: %59 = OpImageSampleImplicitLod %v4float %58 %20 ; CHECK: OpBranch %54 ; CHECK: %56 = OpLabel -; CHECK: %112 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_39 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_39 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch %54 ; CHECK: %54 = OpLabel -; CHECK: %114 = OpPhi %v4float %59 %55 %113 %56 -; CHECK: OpStore %_entryPointOutput_vColor %114 +; CHECK: [[phi_result:%\w+]] = OpPhi %v4float %59 %55 [[null_v4float]] %56 +; CHECK: OpStore %_entryPointOutput_vColor [[phi_result]] OpReturn OpFunctionEnd )"; @@ -1932,14 +1925,12 @@ OpDecorate %20 NonUniform )" + kInputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %bool = OpTypeBool -; CHECK: %49 = OpTypeFunction %void %uint %uint %uint %uint )" + kOutputGlobals + R"( ; CHECK: %v4float = OpTypeVector %float 4 ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ; CHECK: %v4uint = OpTypeVector %uint 4 -; CHECK: %101 = OpConstantNull %float -; CHECK: %105 = OpTypeFunction %uint %uint %uint %uint %uint +; CHECK: [[null_float:%\w+]] = OpConstantNull %float )"; // clang-format on @@ -1970,15 +1961,15 @@ OpStore %b %20 ; CHECK: %129 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 %128 %uint_0 ; CHECK: OpBranch %124 ; CHECK: %124 = OpLabel -; CHECK: %130 = OpPhi %float %127 %125 %101 %126 +; CHECK: [[phi_result_1:%\w+]] = OpPhi %float %127 %125 [[null_float]] %126 ; CHECK: OpBranch %43 ; CHECK: %45 = OpLabel -; CHECK: %47 = OpBitcast %uint %7 -; CHECK: %100 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 %47 %40 +; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %7 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result]] %40 ; CHECK: OpBranch %43 ; CHECK: %43 = OpLabel -; CHECK: %102 = OpPhi %float %130 %124 %101 %45 -; CHECK: OpStore %b %102 +; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] %124 [[null_float]] %45 +; CHECK: OpStore %b [[phi_result_2]] OpReturn OpFunctionEnd )"; @@ -2062,14 +2053,12 @@ OpDecorate %20 NonUniform )" + kInputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %bool = OpTypeBool -; CHECK: %49 = OpTypeFunction %void %uint %uint %uint %uint )" + kOutputGlobals + R"( ; CHECK: %v4float = OpTypeVector %float 4 ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ; CHECK: %v4uint = OpTypeVector %uint 4 -; CHECK: %101 = OpConstantNull %float -; CHECK: %105 = OpTypeFunction %uint %uint %uint %uint %uint +; CHECK: [[null_float:%\w+]] = OpConstantNull %float )"; // clang-format on @@ -2087,8 +2076,8 @@ OpStore %b %20 ; CHECK: OpSelectionMerge %43 None ; CHECK: OpBranchConditional %42 %44 %45 ; CHECK: %44 = OpLabel -; CHECK: %103 = OpBitcast %uint %7 -; CHECK: %122 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_3 %103 +; CHECK: [[bitcast_result_1:%\w+]] = OpBitcast %uint %7 +; CHECK: %122 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_3 [[bitcast_result_1]] ; CHECK: %123 = OpULessThan %bool %uint_0 %122 ; CHECK: OpSelectionMerge %124 None ; CHECK: OpBranchConditional %123 %125 %126 @@ -2100,15 +2089,15 @@ OpStore %b %20 ; CHECK: %129 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 %128 %uint_0 ; CHECK: OpBranch %124 ; CHECK: %124 = OpLabel -; CHECK: %130 = OpPhi %float %127 %125 %101 %126 +; CHECK: [[phi_result_1:%\w+]] = OpPhi %float %127 %125 [[null_float]] %126 ; CHECK: OpBranch %43 ; CHECK: %45 = OpLabel -; CHECK: %47 = OpBitcast %uint %7 -; CHECK: %100 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 %47 %40 +; CHECK: [[bitcast_result_2:%\w+]] = OpBitcast %uint %7 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result_2]] %40 ; CHECK: OpBranch %43 ; CHECK: %43 = OpLabel -; CHECK: %102 = OpPhi %float %130 %124 %101 %45 -; CHECK: OpStore %b %102 +; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] %124 [[null_float]] %45 +; CHECK: OpStore %b [[phi_result_2]] OpReturn OpFunctionEnd )"; @@ -2181,14 +2170,12 @@ OpDecorate %20 NonUniform )" + kInputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %bool = OpTypeBool -; CHECK: %49 = OpTypeFunction %void %uint %uint %uint %uint )" + kOutputGlobals + R"( ; CHECK: %v4float = OpTypeVector %float 4 ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ; CHECK: %v4uint = OpTypeVector %uint 4 -; CHECK: %101 = OpConstantNull %float -; CHECK: %105 = OpTypeFunction %uint %uint %uint %uint %uint +; CHECK: [[null_float:%\w+]] = OpConstantNull %float )"; // clang-format on @@ -2219,15 +2206,15 @@ OpStore %b %20 ; CHECK: %129 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 %128 %uint_0 ; CHECK: OpBranch %124 ; CHECK: %124 = OpLabel -; CHECK: %130 = OpPhi %float %127 %125 %101 %126 +; CHECK: [[phi_result_1:%\w+]] = OpPhi %float %127 %125 [[null_float]] %126 ; CHECK: OpBranch %43 ; CHECK: %45 = OpLabel -; CHECK: %47 = OpBitcast %uint %7 -; CHECK: %100 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 %47 %40 +; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %7 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result]] %40 ; CHECK: OpBranch %43 ; CHECK: %43 = OpLabel -; CHECK: %102 = OpPhi %float %130 %124 %101 %45 -; CHECK: OpStore %b %102 +; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] %124 [[null_float]] %45 +; CHECK: OpStore %b [[phi_result_2]] OpReturn OpFunctionEnd )"; @@ -2296,13 +2283,12 @@ OpDecorate %uniformBuffer Binding 3 )" + kInputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %bool = OpTypeBool -; CHECK: %52 = OpTypeFunction %void %uint %uint %uint %uint )" + kOutputGlobals + R"( ; CHECK: %v4float = OpTypeVector %float 4 ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ; CHECK: %v4uint = OpTypeVector %uint 4 -; CHECK: %104 = OpConstantNull %float +; CHECK: [[null_float:%\w+]] = OpConstantNull %float )"; // clang-format on @@ -2322,11 +2308,11 @@ OpStore %b %16 ; CHECK: %50 = OpLoad %float %15 ; CHECK: OpBranch %47 ; CHECK: %49 = OpLabel -; CHECK: %103 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_32 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_32 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch %47 ; CHECK: %47 = OpLabel -; CHECK: %105 = OpPhi %float %50 %48 %104 %49 -; CHECK: OpStore %b %105 +; CHECK: [[phi_result:%\w+]] = OpPhi %float %50 %48 [[null_float]] %49 +; CHECK: OpStore %b [[phi_result]] OpReturn OpFunctionEnd )"; @@ -2523,7 +2509,6 @@ OpDecorate %22 NonUniform %int_0 = OpConstant %int 0 %_ptr_Uniform_float = OpTypePointer Uniform %float ; CHECK: %bool = OpTypeBool -; CHECK: %32 = OpTypeFunction %void %uint %uint %uint %uint ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint )" + kOutputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint @@ -2531,8 +2516,7 @@ OpDecorate %22 NonUniform ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ; CHECK: %v4uint = OpTypeVector %uint 4 -; CHECK: %88 = OpConstantNull %float -; CHECK: %92 = OpTypeFunction %uint %uint %uint %uint %uint +; CHECK: [[null_float:%\w+]] = OpConstantNull %float )" + kInputGlobals; // clang-format on @@ -2562,15 +2546,15 @@ OpStore %b %22 ; CHECK: %119 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_46 %uint_1 %118 %uint_0 ; CHECK: OpBranch %114 ; CHECK: %114 = OpLabel -; CHECK: %120 = OpPhi %float %117 %115 %88 %116 +; CHECK: [[phi_result_1:%\w+]] = OpPhi %float %117 %115 [[null_float]] %116 ; CHECK: OpBranch %26 ; CHECK: %28 = OpLabel -; CHECK: %30 = OpBitcast %uint %7 -; CHECK: %87 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_46 %uint_0 %30 %uint_128 +; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %7 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_46 %uint_0 [[bitcast_result]] %uint_128 ; CHECK: OpBranch %26 ; CHECK: %26 = OpLabel -; CHECK: %89 = OpPhi %float %120 %114 %88 %28 -; CHECK: OpStore %b %89 +; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] %114 [[null_float]] %28 +; CHECK: OpStore %b [[phi_result_2]] OpReturn OpFunctionEnd )"; @@ -2653,19 +2637,16 @@ OpDecorate %images NonWritable %v4float = OpTypeVector %float 4 %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -; CHECK: %34 = OpTypeFunction %uint %uint %uint ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint )" + kInputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %bool = OpTypeBool -; CHECK: %57 = OpTypeFunction %void %uint %uint %uint %uint )" + kOutputGlobals + R"( ; CHECK: %v3uint = OpTypeVector %uint 3 ; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint ; CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input -; CHECK: %112 = OpConstantNull %v4float -; CHECK: %115 = OpTypeFunction %uint %uint %uint %uint %uint -; CHECK: %140 = OpConstantNull %uint +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint )"; // clang-format on @@ -2689,10 +2670,10 @@ OpStore %31 %29 ; CHECK: %137 = OpLoad %uint %25 ; CHECK: OpBranch %134 ; CHECK: %136 = OpLabel -; CHECK: %139 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_47 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_47 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch %134 ; CHECK: %134 = OpLabel -; CHECK: %141 = OpPhi %uint %137 %135 %140 %136 +; CHECK: [[phi_result_1:%\w+]] = OpPhi %uint %137 %135 [[null_uint]] %136 ; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %141 ; CHECK: %28 = OpLoad %13 %27 ; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1 @@ -2701,7 +2682,7 @@ OpStore %31 %29 ; CHECK: OpBranchConditional %50 %52 %53 ; CHECK: %52 = OpLabel ; CHECK: %54 = OpLoad %13 %27 -; CHECK: %142 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_1 %141 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_1 [[phi_result_1]] ; CHECK: %143 = OpULessThan %bool %uint_0 %142 ; CHECK: OpSelectionMerge %144 None ; CHECK: OpBranchConditional %143 %145 %146 @@ -2713,13 +2694,13 @@ OpStore %31 %29 ; CHECK: %149 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_50 %uint_1 %141 %uint_0 ; CHECK: OpBranch %144 ; CHECK: %144 = OpLabel -; CHECK: %150 = OpPhi %v4float %148 %145 %112 %146 +; CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float %148 %145 [[null_v4float]] %146 ; CHECK: OpBranch %51 ; CHECK: %53 = OpLabel -; CHECK: %111 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_50 %uint_0 %141 %48 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_50 %uint_0 %141 %48 ; CHECK: OpBranch %51 ; CHECK: %51 = OpLabel -; CHECK: %113 = OpPhi %v4float %150 %144 %112 %53 +; CHECK: %113 = OpPhi %v4float [[phi_result_2]] %144 [[null_v4float]] %53 ; CHECK: %30 = OpCompositeExtract %float %113 0 ; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 ; CHECK: %151 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 @@ -2774,7 +2755,7 @@ OpExtension "SPV_NV_ray_tracing" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint RayGenerationNV %main "main" -; CHECK: OpEntryPoint RayGenerationNV %main "main" %89 +; CHECK: OpEntryPoint RayGenerationNV %main "main" [[launch_id:%\w+]] OpSource GLSL 460 OpSourceExtension "GL_EXT_nonuniform_qualifier" OpSourceExtension "GL_NV_ray_tracing" @@ -2794,7 +2775,7 @@ OpDecorate %images Binding 1 OpDecorate %images NonWritable ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %89 BuiltIn LaunchIdNV +; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 @@ -2821,14 +2802,9 @@ OpDecorate %images NonWritable )" + kInputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %bool = OpTypeBool -; CHECK: %57 = OpTypeFunction %void %uint %uint %uint %uint )" + kOutputGlobals + R"( -; CHECK: %v3uint = OpTypeVector %uint 3 -; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint -; CHECK: %89 = OpVariable %_ptr_Input_v3uint Input -; CHECK: %113 = OpConstantNull %v4float -; CHECK: %116 = OpTypeFunction %uint %uint %uint %uint %uint -; CHECK: %141 = OpConstantNull %uint +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint )"; // clang-format on @@ -2852,10 +2828,10 @@ OpStore %31 %29 ; CHECK: %138 = OpLoad %uint %25 ; CHECK: OpBranch %135 ; CHECK: %137 = OpLabel -; CHECK: %140 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch %135 ; CHECK: %135 = OpLabel -; CHECK: %142 = OpPhi %uint %138 %136 %141 %137 +; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137 ; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 ; CHECK: %28 = OpLoad %13 %27 ; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1 @@ -2876,13 +2852,13 @@ OpStore %31 %29 ; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0 ; CHECK: OpBranch %145 ; CHECK: %145 = OpLabel -; CHECK: %151 = OpPhi %v4float %149 %146 %113 %147 +; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147 ; CHECK: OpBranch %51 ; CHECK: %53 = OpLabel -; CHECK: %112 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 ; CHECK: OpBranch %51 ; CHECK: %51 = OpLabel -; CHECK: %114 = OpPhi %v4float %151 %145 %113 %53 +; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53 ; CHECK: %30 = OpCompositeExtract %float %114 0 ; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 ; CHECK: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 @@ -2936,7 +2912,7 @@ OpExtension "SPV_NV_ray_tracing" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint IntersectionNV %main "main" -; CHECK: OpEntryPoint IntersectionNV %main "main" %89 +; CHECK: OpEntryPoint IntersectionNV %main "main" [[launch_id:%\w+]] OpSource GLSL 460 OpSourceExtension "GL_EXT_nonuniform_qualifier" OpSourceExtension "GL_NV_ray_tracing" @@ -2956,7 +2932,7 @@ OpDecorate %images Binding 1 OpDecorate %images NonWritable ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %89 BuiltIn LaunchIdNV +; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 @@ -2984,12 +2960,9 @@ OpDecorate %images NonWritable ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %bool = OpTypeBool )" + kOutputGlobals + R"( -; CHECK: %v3uint = OpTypeVector %uint 3 -; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint -; CHECK: %89 = OpVariable %_ptr_Input_v3uint Input -; CHECK: %113 = OpConstantNull %v4float -; CHECK: %116 = OpTypeFunction %uint %uint %uint %uint %uint -; CHECK: %141 = OpConstantNull %uint +; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint )"; // clang-format on @@ -3013,10 +2986,10 @@ OpStore %31 %29 ; CHECK: %138 = OpLoad %uint %25 ; CHECK: OpBranch %135 ; CHECK: %137 = OpLabel -; CHECK: %140 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch %135 ; CHECK: %135 = OpLabel -; CHECK: %142 = OpPhi %uint %138 %136 %141 %137 +; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137 ; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 ; CHECK: %28 = OpLoad %13 %27 ; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1 @@ -3037,13 +3010,13 @@ OpStore %31 %29 ; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0 ; CHECK: OpBranch %145 ; CHECK: %145 = OpLabel -; CHECK: %151 = OpPhi %v4float %149 %146 %113 %147 +; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147 ; CHECK: OpBranch %51 ; CHECK: %53 = OpLabel -; CHECK: %112 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 ; CHECK: OpBranch %51 ; CHECK: %51 = OpLabel -; CHECK: %114 = OpPhi %v4float %151 %145 %113 %53 +; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53 ; CHECK: %30 = OpCompositeExtract %float %114 0 ; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 ; CHECK: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 @@ -3097,7 +3070,7 @@ OpExtension "SPV_NV_ray_tracing" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint AnyHitNV %main "main" -; CHECK: OpEntryPoint AnyHitNV %main "main" %89 +; CHECK: OpEntryPoint AnyHitNV %main "main" [[launch_id:%\w+]] OpSource GLSL 460 OpSourceExtension "GL_EXT_nonuniform_qualifier" OpSourceExtension "GL_NV_ray_tracing" @@ -3117,7 +3090,7 @@ OpDecorate %images Binding 1 OpDecorate %images NonWritable ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %89 BuiltIn LaunchIdNV +; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 @@ -3144,14 +3117,10 @@ OpDecorate %images NonWritable )" + kInputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %bool = OpTypeBool -; CHECK: %57 = OpTypeFunction %void %uint %uint %uint %uint )" + kOutputGlobals + R"( -; CHECK: %v3uint = OpTypeVector %uint 3 -; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint -; CHECK: %89 = OpVariable %_ptr_Input_v3uint Input -; CHECK: %113 = OpConstantNull %v4float -; CHECK: %116 = OpTypeFunction %uint %uint %uint %uint %uint -; CHECK: %141 = OpConstantNull %uint +; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint )"; // clang-format on @@ -3175,10 +3144,10 @@ OpStore %31 %29 ; CHECK: %138 = OpLoad %uint %25 ; CHECK: OpBranch %135 ; CHECK: %137 = OpLabel -; CHECK: %140 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch %135 ; CHECK: %135 = OpLabel -; CHECK: %142 = OpPhi %uint %138 %136 %141 %137 +; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137 ; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 ; CHECK: %28 = OpLoad %13 %27 ; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1 @@ -3199,13 +3168,13 @@ OpStore %31 %29 ; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0 ; CHECK: OpBranch %145 ; CHECK: %145 = OpLabel -; CHECK: %151 = OpPhi %v4float %149 %146 %113 %147 +; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147 ; CHECK: OpBranch %51 ; CHECK: %53 = OpLabel -; CHECK: %112 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 ; CHECK: OpBranch %51 ; CHECK: %51 = OpLabel -; CHECK: %114 = OpPhi %v4float %151 %145 %113 %53 +; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53 ; CHECK: %30 = OpCompositeExtract %float %114 0 ; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 ; CHECK: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 @@ -3259,7 +3228,7 @@ OpExtension "SPV_NV_ray_tracing" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint ClosestHitNV %main "main" -; CHECK: OpEntryPoint ClosestHitNV %main "main" %89 +; CHECK: OpEntryPoint ClosestHitNV %main "main" [[launch_id:%\w+]] OpSource GLSL 460 OpSourceExtension "GL_EXT_nonuniform_qualifier" OpSourceExtension "GL_NV_ray_tracing" @@ -3279,7 +3248,7 @@ OpDecorate %images Binding 1 OpDecorate %images NonWritable ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %89 BuiltIn LaunchIdNV +; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 @@ -3306,14 +3275,10 @@ OpDecorate %images NonWritable )" + kInputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %bool = OpTypeBool -; CHECK: %57 = OpTypeFunction %void %uint %uint %uint %uint )" + kOutputGlobals + R"( -; CHECK: %v3uint = OpTypeVector %uint 3 -; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint -; CHECK: %89 = OpVariable %_ptr_Input_v3uint Input -; CHECK: %113 = OpConstantNull %v4float -; CHECK: %116 = OpTypeFunction %uint %uint %uint %uint %uint -; CHECK: %141 = OpConstantNull %uint +; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint )"; // clang-format on @@ -3337,10 +3302,10 @@ OpStore %31 %29 ; CHECK: %138 = OpLoad %uint %25 ; CHECK: OpBranch %135 ; CHECK: %137 = OpLabel -; CHECK: %140 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch %135 ; CHECK: %135 = OpLabel -; CHECK: %142 = OpPhi %uint %138 %136 %141 %137 +; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137 ; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 ; CHECK: %28 = OpLoad %13 %27 ; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1 @@ -3361,13 +3326,13 @@ OpStore %31 %29 ; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0 ; CHECK: OpBranch %145 ; CHECK: %145 = OpLabel -; CHECK: %151 = OpPhi %v4float %149 %146 %113 %147 +; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147 ; CHECK: OpBranch %51 ; CHECK: %53 = OpLabel -; CHECK: %112 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 ; CHECK: OpBranch %51 ; CHECK: %51 = OpLabel -; CHECK: %114 = OpPhi %v4float %151 %145 %113 %53 +; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53 ; CHECK: %30 = OpCompositeExtract %float %114 0 ; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 ; CHECK: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 @@ -3421,7 +3386,7 @@ OpExtension "SPV_NV_ray_tracing" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint MissNV %main "main" -; CHECK: OpEntryPoint MissNV %main "main" %89 +; CHECK: OpEntryPoint MissNV %main "main" [[launch_id:%\w+]] OpSource GLSL 460 OpSourceExtension "GL_EXT_nonuniform_qualifier" OpSourceExtension "GL_NV_ray_tracing" @@ -3441,7 +3406,7 @@ OpDecorate %images Binding 1 OpDecorate %images NonWritable ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %89 BuiltIn LaunchIdNV +; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 @@ -3468,14 +3433,10 @@ OpDecorate %images NonWritable )" + kInputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %bool = OpTypeBool -; CHECK: %57 = OpTypeFunction %void %uint %uint %uint %uint )" + kOutputGlobals + R"( -; CHECK: %v3uint = OpTypeVector %uint 3 -; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint -; CHECK: %89 = OpVariable %_ptr_Input_v3uint Input -; CHECK: %113 = OpConstantNull %v4float -; CHECK: %116 = OpTypeFunction %uint %uint %uint %uint %uint -; CHECK: %141 = OpConstantNull %uint +; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint )"; // clang-format on @@ -3499,10 +3460,10 @@ OpStore %31 %29 ; CHECK: %138 = OpLoad %uint %25 ; CHECK: OpBranch %135 ; CHECK: %137 = OpLabel -; CHECK: %140 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch %135 ; CHECK: %135 = OpLabel -; CHECK: %142 = OpPhi %uint %138 %136 %141 %137 +; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137 ; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 ; CHECK: %28 = OpLoad %13 %27 ; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1 @@ -3523,13 +3484,13 @@ OpStore %31 %29 ; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0 ; CHECK: OpBranch %145 ; CHECK: %145 = OpLabel -; CHECK: %151 = OpPhi %v4float %149 %146 %113 %147 +; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147 ; CHECK: OpBranch %51 ; CHECK: %53 = OpLabel -; CHECK: %112 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 ; CHECK: OpBranch %51 ; CHECK: %51 = OpLabel -; CHECK: %114 = OpPhi %v4float %151 %145 %113 %53 +; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53 ; CHECK: %30 = OpCompositeExtract %float %114 0 ; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 ; CHECK: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 @@ -3583,7 +3544,7 @@ OpExtension "SPV_NV_ray_tracing" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint CallableNV %main "main" -; CHECK: OpEntryPoint CallableNV %main "main" %89 +; CHECK: OpEntryPoint CallableNV %main "main" [[launch_id:%\w+]] OpSource GLSL 460 OpSourceExtension "GL_EXT_nonuniform_qualifier" OpSourceExtension "GL_NV_ray_tracing" @@ -3603,7 +3564,7 @@ OpDecorate %images Binding 1 OpDecorate %images NonWritable ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + kOutputDecorations + R"( -; CHECK: OpDecorate %89 BuiltIn LaunchIdNV +; CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 @@ -3630,14 +3591,9 @@ OpDecorate %images NonWritable )" + kInputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %bool = OpTypeBool -; CHECK: %57 = OpTypeFunction %void %uint %uint %uint %uint )" + kOutputGlobals + R"( -; CHECK: %v3uint = OpTypeVector %uint 3 -; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint -; CHECK: %89 = OpVariable %_ptr_Input_v3uint Input -; CHECK: %113 = OpConstantNull %v4float -; CHECK: %116 = OpTypeFunction %uint %uint %uint %uint %uint -; CHECK: %141 = OpConstantNull %uint +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint )"; // clang-format on @@ -3661,10 +3617,10 @@ OpStore %31 %29 ; CHECK: %138 = OpLoad %uint %25 ; CHECK: OpBranch %135 ; CHECK: %137 = OpLabel -; CHECK: %140 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch %135 ; CHECK: %135 = OpLabel -; CHECK: %142 = OpPhi %uint %138 %136 %141 %137 +; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137 ; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 ; CHECK: %28 = OpLoad %13 %27 ; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1 @@ -3685,13 +3641,13 @@ OpStore %31 %29 ; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0 ; CHECK: OpBranch %145 ; CHECK: %145 = OpLabel -; CHECK: %151 = OpPhi %v4float %149 %146 %113 %147 +; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147 ; CHECK: OpBranch %51 ; CHECK: %53 = OpLabel -; CHECK: %112 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 ; CHECK: OpBranch %51 ; CHECK: %51 = OpLabel -; CHECK: %114 = OpPhi %v4float %151 %145 %113 %53 +; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53 ; CHECK: %30 = OpCompositeExtract %float %114 0 ; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 ; CHECK: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 @@ -3822,17 +3778,11 @@ OpDecorate %outColor Location 0 %outColor = OpVariable %_ptr_Output_v4float Output %float_0 = OpConstant %float 0 ; CHECK: %bool = OpTypeBool -; CHECK: %68 = OpTypeFunction %void %uint %uint %uint %uint ; 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: %v4uint = OpTypeVector %uint 4 -; CHECK: %122 = OpConstantNull %v4float -; CHECK: %126 = OpTypeFunction %uint %uint %uint %uint %uint +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )" + kInputGlobals + R"( -; CHECK: %165 = OpConstantNull %v2float +; CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float )"; // clang-format on @@ -3870,10 +3820,10 @@ OpStore %x %36 ; CHECK: %162 = OpLoad %v2float %47 ; CHECK: OpBranch %159 ; CHECK: %161 = OpLabel -; CHECK: %164 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_87 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_87 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch %159 ; CHECK: %159 = OpLabel -; CHECK: %166 = OpPhi %v2float %162 %160 %165 %161 +; CHECK: %166 = OpPhi %v2float %162 %160 [[null_v2float]] %161 ; CHECK: %49 = OpFMul %v2float %42 %166 ; CHECK: %167 = OpSampledImage %27 %39 %40 ; CHECK: %168 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_2 %uint_0 @@ -3889,7 +3839,7 @@ OpStore %x %36 ; CHECK: %177 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_89 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch %170 ; CHECK: %170 = OpLabel -; CHECK: %178 = OpPhi %v4float %175 %171 %122 %172 +; CHECK: %178 = OpPhi %v4float %175 %171 [[null_v4float]] %172 ; CHECK: %51 = OpCompositeExtract %float %178 0 OpStore %y %51 %54 = OpLoad %float %x @@ -4017,12 +3967,11 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint )" + kInputGlobals + R"( ;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint - ;CHECK: %148 = OpTypeFunction %void %uint %uint %uint %uint %uint )" + kOutputGlobals + R"( ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 - ;CHECK: %202 = OpConstantNull %v2float + ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float %MainPs = OpFunction %void None %3 %5 = OpLabel ;CHECK: %140 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_1 %uint_0 @@ -4048,10 +3997,10 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: %146 = OpLoad %v2float %86 ;CHECK: OpBranch %143 ;CHECK: %145 = OpLabel - ;CHECK: %201 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_71 %uint_4 %uint_0 %119 %140 + ;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_71 %uint_4 %uint_0 %119 %140 ;CHECK: OpBranch %143 ;CHECK: %143 = OpLabel - ;CHECK: %203 = OpPhi %v2float %146 %144 %202 %145 + ;CHECK: %203 = OpPhi %v2float %146 %144 [[null_v2float]] %145 OpBranch %91 %88 = OpLabel %89 = OpAccessChain %_ptr_Uniform_v2float %__0 %int_1 @@ -4068,7 +4017,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: %211 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_75 %uint_4 %uint_0 %204 %140 ;CHECK: OpBranch %206 ;CHECK: %206 = OpLabel - ;CHECK: %212 = OpPhi %v2float %209 %207 %202 %208 + ;CHECK: %212 = OpPhi %v2float %209 %207 [[null_v2float]] %208 OpBranch %91 %91 = OpLabel %115 = OpPhi %v2float %87 %85 %90 %88 @@ -4210,12 +4159,11 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { )" + kInputGlobals + R"( ;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ;CHECK: %bool = OpTypeBool -;CHECK: %132 = OpTypeFunction %void %uint %uint %uint %uint %uint )" + kOutputGlobals + R"( ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 -;CHECK: %185 = OpConstantNull %v2float +;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float %MainPs = OpFunction %void None %3 %5 = OpLabel ;CHECK: %123 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_2 %uint_0 @@ -4240,10 +4188,10 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { ;CHECK: %130 = OpLoad %v2float %81 ;CHECK: OpBranch %127 ;CHECK: %129 = OpLabel -;CHECK: %184 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_78 %uint_4 %uint_0 %101 %123 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_78 %uint_4 %uint_0 %101 %123 ;CHECK: OpBranch %127 ;CHECK: %127 = OpLabel -;CHECK: %186 = OpPhi %v2float %130 %128 %185 %129 +;CHECK: %186 = OpPhi %v2float %130 %128 [[null_v2float]] %129 %86 = OpFAdd %v2float %66 %82 ;CHECK-NOT: %86 = OpFAdd %v2float %66 %82 ;CHECK: %86 = OpFAdd %v2float %66 %186 @@ -4353,13 +4301,12 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { )" + kInputGlobals + R"( ;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ;CHECK: %bool = OpTypeBool -;CHECK: %135 = OpTypeFunction %void %uint %uint %uint %uint %uint )" + kOutputGlobals + R"( ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 -;CHECK: %189 = OpConstantNull %v2float -;CHECK: %201 = OpConstantNull %v4float +;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float %MainPs = OpFunction %void None %3 %5 = OpLabel ;CHECK: %126 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_2 %uint_0 @@ -4387,10 +4334,10 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: %133 = OpLoad %v2float %81 ;CHECK: OpBranch %130 ;CHECK: %132 = OpLabel -;CHECK: %188 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_78 %uint_4 %uint_0 %101 %126 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_78 %uint_4 %uint_0 %101 %126 ;CHECK: OpBranch %130 ;CHECK: %130 = OpLabel -;CHECK: %190 = OpPhi %v2float %133 %131 %189 %132 +;CHECK: %190 = OpPhi %v2float %133 %131 [[null_v2float]] %132 ;CHECK: %86 = OpFAdd %v2float %66 %190 %87 = OpLoad %46 %g_tColor %88 = OpLoad %50 %g_sAniso @@ -4408,10 +4355,10 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: %198 = OpImageSampleImplicitLod %v4float %197 %86 ;CHECK: OpBranch %193 ;CHECK: %195 = OpLabel -;CHECK: %200 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_83 %uint_1 %uint_0 %uint_0 %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_83 %uint_1 %uint_0 %uint_0 %uint_0 ;CHECK: OpBranch %193 ;CHECK: %193 = OpLabel -;CHECK: %202 = OpPhi %v4float %198 %194 %201 %195 +;CHECK: %202 = OpPhi %v4float %198 %194 [[null_v4float]] %195 ;CHECK: OpStore %_entryPointOutput_vColor %202 OpReturn OpFunctionEnd @@ -4490,15 +4437,12 @@ TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output ;CHECK: %bool = OpTypeBool -;CHECK: %51 = OpTypeFunction %void %uint %uint %uint %uint ;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: %v4uint = OpTypeVector %uint 4 -;CHECK: %106 = OpConstantNull %v4float -;CHECK: %111 = OpTypeFunction %uint %uint %uint %uint %uint +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )" + kInputGlobals + R"( %MainPs = OpFunction %void None %10 %30 = OpLabel @@ -4539,14 +4483,14 @@ TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { ;CHECK: %140 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_60 %uint_1 %139 %uint_0 ;CHECK: OpBranch %133 ;CHECK: %133 = OpLabel -;CHECK: %141 = OpPhi %v4float %138 %134 %106 %135 +;CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float %138 %134 [[null_v4float]] %135 ;CHECK: OpBranch %44 ;CHECK: %46 = OpLabel -;CHECK: %105 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_60 %uint_0 %41 %uint_128 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_60 %uint_0 %41 %uint_128 ;CHECK: OpBranch %44 ;CHECK: %44 = OpLabel -;CHECK: %107 = OpPhi %v4float %141 %133 %106 %46 -;CHECK: OpStore %_entryPointOutput_vColor %107 +;CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float [[phi_result_1]] %133 [[null_v4float]] %46 +;CHECK: OpStore %_entryPointOutput_vColor [[phi_result_2]] OpReturn OpFunctionEnd )" + kStreamWrite4Frag + kDirectRead4; @@ -4681,12 +4625,10 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { )" + kInputGlobals + R"( ;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ;CHECK: %bool = OpTypeBool -;CHECK: %88 = OpTypeFunction %void %uint %uint %uint %uint %uint )" + kOutputGlobals + R"( ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input -;CHECK: %v4uint = OpTypeVector %uint 4 -;CHECK: %142 = OpConstantNull %v2float +;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float %MainPs = OpFunction %void None %14 %37 = OpLabel ;CHECK: %79 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_0 %uint_0 @@ -4714,10 +4656,10 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { ;CHECK: %86 = OpLoad %v2float %41 ;CHECK: OpBranch %83 ;CHECK: %85 = OpLabel -;CHECK: %141 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_81 %uint_4 %uint_0 %58 %79 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_81 %uint_4 %uint_0 %58 %79 ;CHECK: OpBranch %83 ;CHECK: %83 = OpLabel -;CHECK: %143 = OpPhi %v2float %86 %84 %142 %85 +;CHECK: %143 = OpPhi %v2float %86 %84 [[null_v2float]] %85 ;CHECK: %43 = OpFAdd %v2float %38 %143 %44 = OpLoad %30 %g_tColor %45 = OpLoad %32 %g_sAniso @@ -4808,23 +4750,16 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { %v4float = OpTypeVector %float 4 %_ptr_Input_v4float = OpTypePointer Input %v4float %a_position = OpVariable %_ptr_Input_v4float Input -;CHECK; %37 = OpTypeFunction %uint %uint %uint %uint -;CHECK;%_runtimearr_uint = OpTypeRuntimeArray %uint +;CHECK: %37 = OpTypeFunction %uint %uint %uint %uint +;CHECK:%_runtimearr_uint = OpTypeRuntimeArray %uint )" + kInputGlobals + R"( -;CHECK;%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -;CHECK; %bool = OpTypeBool -;CHECK; %63 = OpTypeFunction %void %uint %uint %uint %uint %uint +;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint +;CHECK: %bool = OpTypeBool )" + 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 -;CHECK; %uint_5 = OpConstant %uint 5 -;CHECK; %uint_7 = OpConstant %uint 7 -;CHECK; %uint_8 = OpConstant %uint 8 -;CHECK; %uint_9 = OpConstant %uint 9 -;CHECK; %uint_10 = OpConstant %uint 10 -;CHECK; %uint_45 = OpConstant %uint 45 -;CHECK; %115 = OpConstantNull %float +;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 ;CHECK: %55 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_0 %uint_0 @@ -4847,10 +4782,10 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;CHECK: %61 = OpLoad %float %20 ;CHECK: OpBranch %58 ;CHECK: %60 = OpLabel -;CHECK: %114 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_45 %uint_4 %uint_0 %35 %55 +;CHECK: {{\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_45 %uint_4 %uint_0 %35 %55 ;CHECK: OpBranch %58 ;CHECK: %58 = OpLabel -;CHECK: %116 = OpPhi %float %61 %59 %115 %60 +;CHECK: %116 = OpPhi %float %61 %59 [[null_float]] %60 OpStore %v_vtxResult %21 ;CHECK-NOT: OpStore %v_vtxResult %21 ;CHECK: OpStore %v_vtxResult %116 @@ -4943,12 +4878,11 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { )" + kInputGlobals + R"( ;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ;CHECK: %bool = OpTypeBool -;CHECK: %63 = OpTypeFunction %void %uint %uint %uint %uint %uint )" + 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 -;CHECK: %114 = OpConstantNull %float +;CHECK: [[null_float:%\w+]] = OpConstantNull %float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: %55 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_0 %uint_0 @@ -4971,10 +4905,10 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { ;CHECK: %61 = OpLoad %float %20 ;CHECK: OpBranch %58 ;CHECK: %60 = OpLabel -;CHECK: %113 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_45 %uint_4 %uint_0 %35 %55 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_45 %uint_4 %uint_0 %35 %55 ;CHECK: OpBranch %58 ;CHECK: %58 = OpLabel -;CHECK: %115 = OpPhi %float %61 %59 %114 %60 +;CHECK: %115 = OpPhi %float %61 %59 [[null_float]] %60 OpStore %v_vtxResult %21 ;CHECK-NOT: OpStore %v_vtxResult %21 ;CHECK: OpStore %v_vtxResult %115 @@ -5074,12 +5008,11 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { )" + kInputGlobals + R"( ;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ;CHECK: %bool = OpTypeBool -;CHECK: %72 = OpTypeFunction %void %uint %uint %uint %uint %uint )" + 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 -;CHECK: %124 = OpConstantNull %v2float +;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: %64 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_0 %uint_0 @@ -5106,10 +5039,10 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { ;CHECK: %70 = OpLoad %v2float %25 ;CHECK: OpBranch %67 ;CHECK: %69 = OpLabel -;CHECK: %123 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_51 %uint_4 %uint_0 %43 %64 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_51 %uint_4 %uint_0 %43 %64 ;CHECK: OpBranch %67 ;CHECK: %67 = OpLabel -;CHECK: %125 = OpPhi %v2float %70 %68 %124 %69 +;CHECK: %125 = OpPhi %v2float %70 %68 [[null_v2float]] %69 ;CHECK: OpStore %v_vtxResult %125 OpReturn OpFunctionEnd @@ -5172,14 +5105,12 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { %ii = OpVariable %_ptr_Input_int Input ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %bool = OpTypeBool -;CHECK: %35 = OpTypeFunction %void %uint %uint %uint %uint %uint ;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: %v4uint = OpTypeVector %uint 4 -;CHECK: %93 = OpConstantNull %v4float +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: OpBranch %21 @@ -5204,10 +5135,10 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { ;CHECK: %33 = OpImageRead %v4float %32 %17 ;CHECK: OpBranch %29 ;CHECK: %31 = OpLabel -;CHECK: %92 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_33 %uint_7 %uint_0 %23 %25 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_33 %uint_7 %uint_0 %23 %25 ;CHECK: OpBranch %29 ;CHECK: %29 = OpLabel -;CHECK: %94 = OpPhi %v4float %33 %30 %93 %31 +;CHECK: %94 = OpPhi %v4float %33 %30 [[null_v4float]] %31 ;CHECK: OpStore %x %94 OpReturn OpFunctionEnd @@ -5365,14 +5296,12 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { %ii = OpVariable %_ptr_Input_int Input ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %bool = OpTypeBool -;CHECK: %35 = OpTypeFunction %void %uint %uint %uint %uint %uint ;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: %v4uint = OpTypeVector %uint 4 -;CHECK: %94 = OpConstantNull %v4float +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: OpBranch %21 @@ -5397,10 +5326,10 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %33 = OpImageFetch %v4float %32 %17 ;CHECK: OpBranch %29 ;CHECK: %31 = OpLabel -;CHECK: %93 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_32 %uint_6 %uint_0 %23 %25 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_32 %uint_6 %uint_0 %23 %25 ;CHECK: OpBranch %29 ;CHECK: %29 = OpLabel -;CHECK: %95 = OpPhi %v4float %33 %30 %94 %31 +;CHECK: %95 = OpPhi %v4float %33 %30 [[null_v4float]] %31 ;CHECK: OpStore %x %95 OpReturn OpFunctionEnd @@ -5464,14 +5393,12 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { %ii = OpVariable %_ptr_Input_int Input ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %bool = OpTypeBool -;CHECK: %38 = OpTypeFunction %void %uint %uint %uint %uint %uint ;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: %v4uint = OpTypeVector %uint 4 -;CHECK: %97 = OpConstantNull %v4float +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: OpBranch %23 @@ -5498,10 +5425,10 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %36 = OpImageFetch %v4float %35 %18 ;CHECK: OpBranch %31 ;CHECK: %33 = OpLabel -;CHECK: %96 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_34 %uint_6 %uint_0 %25 %27 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_34 %uint_6 %uint_0 %25 %27 ;CHECK: OpBranch %31 ;CHECK: %31 = OpLabel -;CHECK: %98 = OpPhi %v4float %36 %32 %97 %33 +;CHECK: %98 = OpPhi %v4float %36 %32 [[null_v4float]] %33 ;CHECK: OpStore %x %98 OpReturn OpFunctionEnd @@ -5572,14 +5499,12 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { %ii = OpVariable %_ptr_Input_int Input ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %bool = OpTypeBool -;CHECK: %44 = OpTypeFunction %void %uint %uint %uint %uint %uint ;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: %v4uint = OpTypeVector %uint 4 -;CHECK: %103 = OpConstantNull %v4float +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float %main = OpFunction %void None %3 %5 = OpLabel ;CHECK: OpBranch %28 @@ -5609,10 +5534,10 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %42 = OpImageFetch %v4float %41 %23 ;CHECK: OpBranch %36 ;CHECK: %38 = OpLabel -;CHECK: %102 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_42 %uint_6 %uint_0 %30 %32 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_42 %uint_6 %uint_0 %30 %32 ;CHECK: OpBranch %36 ;CHECK: %36 = OpLabel -;CHECK: %104 = OpPhi %v4float %42 %37 %103 %38 +;CHECK: %104 = OpPhi %v4float %42 %37 [[null_v4float]] %38 ;CHECK: OpStore %x %104 OpReturn OpFunctionEnd @@ -5625,6 +5550,148 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { false, true, true, true); } +TEST_F(InstBindlessTest, DeviceBufferAddressOOB) { + // #version 450 + // #extension GL_EXT_buffer_reference : enable + // layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct; + // layout(set = 0, binding = 0) uniform ufoo { + // bufStruct data; + // int nWrites; + // } u_info; + // layout(buffer_reference, std140) buffer bufStruct { + // int a[4]; + // }; + // void main() { + // for (int i=0; i < u_info.nWrites; ++i) { + // u_info.data.a[i] = 0xdeadca71; + // } + // } + + // clang-format off + const std::string text = R"( +OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +;CHECK: OpCapability Int64 +%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 +OpSource GLSL 450 +OpSourceExtension "GL_EXT_buffer_reference" +OpName %main "main" +OpName %i "i" +OpName %ufoo "ufoo" +OpMemberName %ufoo 0 "data" +OpMemberName %ufoo 1 "nWrites" +OpName %bufStruct "bufStruct" +OpMemberName %bufStruct 0 "a" +OpName %u_info "u_info" +OpMemberDecorate %ufoo 0 Offset 0 +OpMemberDecorate %ufoo 1 Offset 8 +OpDecorate %ufoo Block +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 +%3 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int +%int_0 = OpConstant %int 0 +OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer +%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %int +%uint = OpTypeInt 32 0 +%uint_4 = OpConstant %uint 4 +%_arr_int_uint_4 = OpTypeArray %int %uint_4 +%bufStruct = OpTypeStruct %_arr_int_uint_4 +%_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct +%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo +%u_info = OpVariable %_ptr_Uniform_ufoo Uniform +%int_1 = OpConstant %int 1 +%_ptr_Uniform_int = OpTypePointer Uniform %int +%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 +%5 = OpLabel +%i = OpVariable %_ptr_Function_int Function +;CHECK: OpBranch %137 +;CHECK: %137 = OpLabel +;CHECK: 65 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_0 %uint_0 +;CHECK: OpBranch %40 +;CHECK: 40 = OpLabel +;CHECK: OpBranch %39 +;CHECK: 39 = OpLabel +OpStore %i %int_0 +OpBranch %10 +%10 = OpLabel +OpLoopMerge %12 %13 None +OpBranch %14 +%14 = OpLabel +%15 = OpLoad %int %i +%26 = OpAccessChain %_ptr_Uniform_int %u_info %int_1 +%27 = OpLoad %int %26 +%29 = OpSLessThan %bool %15 %27 +;CHECK-NOT: %27 = OpLoad %int %26 +;CHECK-NOT: %29 = OpSLessThan %bool %15 %27 +;CHECK: 43 = OpIAdd %uint %uint_8 %uint_3 +;CHECK: 66 = OpULessThan %bool %43 %65 +;CHECK: OpSelectionMerge %67 None +;CHECK: OpBranchConditional %66 %68 %69 +;CHECK: 68 = OpLabel +;CHECK: 70 = OpLoad %int %26 +;CHECK: OpBranch %67 +;CHECK: 69 = OpLabel +;CHECK: 122 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_54 %uint_4 %uint_0 %43 %65 +;CHECK: OpBranch %67 +;CHECK: 67 = OpLabel +;CHECK: 124 = OpPhi %int %70 %68 %123 %69 +;CHECK: 29 = OpSLessThan %bool %15 %124 +OpBranchConditional %29 %11 %12 +%11 = OpLabel +%31 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 +%32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 +;CHECK-NOT: %32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 +;CHECK: 125 = OpIAdd %uint %uint_0 %uint_7 +;CHECK: 126 = OpULessThan %bool %125 %65 +;CHECK: OpSelectionMerge %127 None +;CHECK: OpBranchConditional %126 %128 %129 +;CHECK: 128 = OpLabel +;CHECK: 130 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 +;CHECK: OpBranch %127 +;CHECK: 129 = OpLabel +;CHECK: 132 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_59 %uint_4 %uint_0 %125 %65 +;CHECK: 135 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_bufStruct %134 +;CHECK: OpBranch %127 +;CHECK: 127 = OpLabel +;CHECK: 136 = OpPhi %_ptr_PhysicalStorageBuffer_bufStruct %130 %128 %135 %129 +%33 = OpLoad %int %i +%36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %32 %int_0 %33 +;CHECK-NOT: %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %32 %int_0 %33 +;CHECK: %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %136 %int_0 %33 +OpStore %36 %int_n559035791 Aligned 16 +OpBranch %13 +%13 = OpLabel +%37 = OpLoad %int %i +%38 = OpIAdd %int %37 %int_1 +OpStore %i %38 +OpBranch %10 +%12 = OpLabel +OpReturn +OpFunctionEnd)" + + kDirectRead3 + kStreamWrite5Vert; + // clang-format on + + SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(text, true, 7u, 23u, false, true, + true, true, true); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Compute shader diff --git a/test/opt/inst_buff_addr_check_test.cpp b/test/opt/inst_buff_addr_check_test.cpp index 7886ba7ea9..b08f7b0b42 100644 --- a/test/opt/inst_buff_addr_check_test.cpp +++ b/test/opt/inst_buff_addr_check_test.cpp @@ -120,6 +120,22 @@ static const std::string kStreamWrite4Compute = kStreamWrite4Begin + R"( )" + kStreamWrite4End; // clang-format on +// clang-format off +static const std::string kStreamWrite4Vert = kStreamWrite4Begin + R"( +; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 +; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} +; CHECK: OpStore {{%\w+}} %uint_0 +; CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex +; 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+}} = OpLoad %uint %gl_InstanceIndex +; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 +; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} +; CHECK: OpStore {{%\w+}} {{%\w+}} +)" + kStreamWrite4End; +// clang-format on + static const std::string kInputDecorations = R"( ; CHECK: OpDecorate [[input_buffer_type:%inst_buff_addr_InputBuffer]] Block ; CHECK: OpMemberDecorate [[input_buffer_type]] 0 Offset 0 @@ -552,6 +568,118 @@ OpFunctionEnd defs + decorates + globals + main_func + output_funcs, true); } +TEST_F(InstBuffAddrTest, DeviceBufferAddressOOB) { + // #version 450 + // #extension GL_EXT_buffer_reference : enable + // layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct; + // layout(set = 0, binding = 0) uniform ufoo { + // bufStruct data; + // int nWrites; + // } u_info; + // layout(buffer_reference, std140) buffer bufStruct { + // int a[4]; + // }; + // void main() { + // for (int i=0; i < u_info.nWrites; ++i) { + // u_info.data.a[i] = 0xdeadca71; + // } + // } + + // clang-format off + const std::string text = R"( +OpCapability Shader +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 %inst_buff_addr_output_buffer %gl_VertexIndex %gl_InstanceIndex +OpSource GLSL 450 +OpSourceExtension "GL_EXT_buffer_reference" +OpName %main "main" +OpName %i "i" +OpName %ufoo "ufoo" +OpMemberName %ufoo 0 "data" +OpMemberName %ufoo 1 "nWrites" +OpName %bufStruct "bufStruct" +OpMemberName %bufStruct 0 "a" +OpName %u_info "u_info" +OpMemberDecorate %ufoo 0 Offset 0 +OpMemberDecorate %ufoo 1 Offset 8 +OpDecorate %ufoo Block +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 +%3 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int +%int_0 = OpConstant %int 0 +OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer +%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %int +%uint = OpTypeInt 32 0 +%uint_4 = OpConstant %uint 4 +%_arr_int_uint_4 = OpTypeArray %int %uint_4 +%bufStruct = OpTypeStruct %_arr_int_uint_4 +%_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct +%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo +%u_info = OpVariable %_ptr_Uniform_ufoo Uniform +%int_1 = OpConstant %int 1 +%_ptr_Uniform_int = OpTypePointer Uniform %int +%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 +%5 = OpLabel +%i = OpVariable %_ptr_Function_int Function +OpStore %i %int_0 +OpBranch %10 +%10 = OpLabel +OpLoopMerge %12 %13 None +OpBranch %14 +%14 = OpLabel +%15 = OpLoad %int %i +%26 = OpAccessChain %_ptr_Uniform_int %u_info %int_1 +%27 = OpLoad %int %26 +%29 = OpSLessThan %bool %15 %27 +OpBranchConditional %29 %11 %12 +%11 = OpLabel +%31 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 +%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: 134 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_62 %uint_2 %80 %83 +;CHECK: OpBranch %77 +;CHECK: 77 = OpLabel +OpBranch %13 +%13 = OpLabel +%37 = OpLoad %int %i +%38 = OpIAdd %int %37 %int_1 +OpStore %i %38 +OpBranch %10 +%12 = OpLabel +OpReturn +OpFunctionEnd)" + kSearchAndTest + kStreamWrite4Vert; + // clang-format on + + SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(text, true, 7, 23); +} + } // namespace } // namespace opt } // namespace spvtools From 30e51ceaab2d9f4b419e7602f740bf395f5ed636 Mon Sep 17 00:00:00 2001 From: Diego Novillo Date: Tue, 17 Jan 2023 10:49:14 -0500 Subject: [PATCH 009/523] Add #5049 to release v2023.1. (#5058) --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 98a8d20d12..39a878c20f 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,8 @@ v2023.1-dev 2023-01-13 - Remove testing support for VS2015 (#5027) - Fix undef behaviour in hex float parsing (#5025) - Require C++11 *or later* (#5020) + - Instrument + - Instrument: Fix bindless checking for BufferDeviceAddress (#5049) - Optimizer - Optimize allocation of spvtools::opt::Instruction::operands_ (#5024) - spirv-opt: Fix OpCompositeInsert with Null Constant (#5008) From 0fc5526f2b01a0cc89192c10cf8bef77f1007a62 Mon Sep 17 00:00:00 2001 From: Diego Novillo Date: Tue, 17 Jan 2023 17:52:57 -0500 Subject: [PATCH 010/523] Finalize v2023.1 release (#5062) * Finalize SPIRV-Tools v2023.1 * Start SPIRV-Tools v2023.2 --- CHANGES | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 39a878c20f..f24da418e8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ Revision history for SPIRV-Tools -v2023.1-dev 2023-01-13 +v2023.2-dev 2023-01-17 + - Start v2023.2-dev + +v2023.1 2023-01-17 - General - Renamed "master" to "main" (issue#5051) - Validate version 5 of clspv reflection (#5050) From b184efe2d4c497a55436946db8367f8f0b0c887b Mon Sep 17 00:00:00 2001 From: Diego Novillo Date: Wed, 18 Jan 2023 09:22:18 -0500 Subject: [PATCH 011/523] Revert "Finalize v2023.1 release (#5062)" (#5064) This reverts commit 0fc5526f2b01a0cc89192c10cf8bef77f1007a62. --- CHANGES | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index f24da418e8..39a878c20f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,9 +1,6 @@ Revision history for SPIRV-Tools -v2023.2-dev 2023-01-17 - - Start v2023.2-dev - -v2023.1 2023-01-17 +v2023.1-dev 2023-01-13 - General - Renamed "master" to "main" (issue#5051) - Validate version 5 of clspv reflection (#5050) From 63de608daeb7e91fbea6d7477a50debe7cac57ce Mon Sep 17 00:00:00 2001 From: Diego Novillo Date: Wed, 18 Jan 2023 09:55:50 -0500 Subject: [PATCH 012/523] Finalize v2023.1 release. (#5065) --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 39a878c20f..6658e0e130 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,6 @@ Revision history for SPIRV-Tools -v2023.1-dev 2023-01-13 +v2023.1 2023-01-17 - General - Renamed "master" to "main" (issue#5051) - Validate version 5 of clspv reflection (#5050) From f36a8d47f738cc612c7dd89f145a15465ab437cd Mon Sep 17 00:00:00 2001 From: Diego Novillo Date: Wed, 18 Jan 2023 09:59:38 -0500 Subject: [PATCH 013/523] Start v2023.2 release. (#5066) --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index 6658e0e130..f24da418e8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,8 @@ Revision history for SPIRV-Tools +v2023.2-dev 2023-01-17 + - Start v2023.2-dev + v2023.1 2023-01-17 - General - Renamed "master" to "main" (issue#5051) From 4683eab649ca84568fa2debfa94931a23b9f1c07 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 18 Jan 2023 18:19:39 +0000 Subject: [PATCH 014/523] Create a github action to update DEPS (#5061) Adding a github action to open a PR when the DEPS can be updated. It will run once a day or it can be manually triggered. I updated roll_deps.sh so that it will not return an error if there were no new commits for a repository. --- .github/workflows/autoroll.yml | 48 ++++++++++++++++++++++++++++++++++ utils/roll_deps.sh | 36 +++++++++++++++---------- 2 files changed, 70 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/autoroll.yml diff --git a/.github/workflows/autoroll.yml b/.github/workflows/autoroll.yml new file mode 100644 index 0000000000..bcb6144734 --- /dev/null +++ b/.github/workflows/autoroll.yml @@ -0,0 +1,48 @@ +name: Update dependencies + +on: + schedule: + - cron: '0 2 * * *' + workflow_dispatch: + +jobs: + update-dependencies: + name: Update dependencies + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + # Checkout the depot tools they are needed by roll_deps.sh + - name: Checkout depot tools + run: git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git + + - name: Update PATH + run: echo "./depot_tools" >> $GITHUB_PATH + + - name: Download dependencies + run: python3 utils/git-sync-deps + + - name: Setup git user information + run: | + git config user.name "GitHub Actions bot" + git config user.email "<>" + git checkout -b roll_deps + + - name: Update dependencies + run: | + utils/roll_deps.sh + if [[ `git diff HEAD..origin/main --name-only | wc -l` == 0 ]]; then + echo "changed=false" >> $GITHUB_OUTPUT + else + echo "changed=true" >> $GITHUB_OUTPUT + fi + id: update_dependencies + + - name: Push changes and create PR + if: steps.update_dependencies.outputs.changed == 'true' + run: | + git push --force --set-upstream origin roll_deps + gh pr create --base main -f -r s-perron + env: + GITHUB_TOKEN: ${{ github.token }} diff --git a/utils/roll_deps.sh b/utils/roll_deps.sh index 03bdaceb50..bf6d6930ea 100755 --- a/utils/roll_deps.sh +++ b/utils/roll_deps.sh @@ -20,14 +20,23 @@ set -eo pipefail -effcee_dir="external/effcee/" -effcee_trunk="origin/main" -googletest_dir="external/googletest/" -googletest_trunk="origin/main" -re2_dir="external/re2/" -re2_trunk="origin/main" -spirv_headers_dir="external/spirv-headers/" -spirv_headers_trunk="origin/main" +function ExitIfIsInterestingError() { + local return_code=$1 + if [[ ${return_code} -ne 0 && ${return_code} -ne 2 ]]; then + exit ${return_code} + fi + return 0 +} + + +# We are not rolling google test for now. The latest version requires C++14. +dependencies=("external/effcee/" +# "external/googletest/") + "external/re2/" + "external/spirv-headers/") + + +branch="origin/main" # This script assumes it's parent directory is the repo root. repo_path=$(dirname "$0")/.. @@ -44,10 +53,9 @@ echo "*** Ignore messages about running 'git cl upload' ***" old_head=$(git rev-parse HEAD) set +e -roll-dep --ignore-dirty-tree --roll-to="${effcee_trunk}" "${effcee_dir}" -roll-dep --ignore-dirty-tree --roll-to="${googletest_trunk}" "${googletest_dir}" -roll-dep --ignore-dirty-tree --roll-to="${re2_trunk}" "${re2_dir}" -roll-dep --ignore-dirty-tree --roll-to="${spirv_headers_trunk}" "${spirv_headers_dir}" - -git rebase --interactive "${old_head}" +for dep in ${dependencies[@]}; do + echo "Rolling $dep" + roll-dep --ignore-dirty-tree --roll-to="${branch}" "${dep}" + ExitIfIsInterestingError $? +done From 1e85dca570f62fe1a42886ecdab1672a10db2ad1 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 18 Jan 2023 20:11:25 +0000 Subject: [PATCH 015/523] Add VS2019 kokoro configs (#5059) We added new builds that will test spirv-tools with VS2019, but we need to add the configurations for them. --- README.md | 4 +++- kokoro/scripts/windows/build.bat | 3 +++ kokoro/windows-msvc-2019-debug/build.bat | 23 ++++++++++++++++++ kokoro/windows-msvc-2019-debug/continuous.cfg | 22 +++++++++++++++++ kokoro/windows-msvc-2019-debug/presubmit.cfg | 16 +++++++++++++ kokoro/windows-msvc-2019-release/build.bat | 24 +++++++++++++++++++ .../windows-msvc-2019-release/continuous.cfg | 22 +++++++++++++++++ .../windows-msvc-2019-release/presubmit.cfg | 16 +++++++++++++ 8 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 kokoro/windows-msvc-2019-debug/build.bat create mode 100644 kokoro/windows-msvc-2019-debug/continuous.cfg create mode 100644 kokoro/windows-msvc-2019-debug/presubmit.cfg create mode 100644 kokoro/windows-msvc-2019-release/build.bat create mode 100644 kokoro/windows-msvc-2019-release/continuous.cfg create mode 100644 kokoro/windows-msvc-2019-release/presubmit.cfg diff --git a/README.md b/README.md index 10a8187bf1..57827c9ef2 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ headers, and XML registry. Linux[![Linux Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_linux_clang_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_clang_release.html) MacOS[![MacOS Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_macos_clang_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_macos_clang_release.html) -Windows[![Windows Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_windows_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_windows_vs2017_release.html) +Windows[![Windows Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_windows_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_windows_vs2019_release.html) [More downloads](docs/downloads.md) @@ -435,6 +435,8 @@ On MacOS On Windows - Visual Studio 2017 +- Visual Studio 2019 +- Visual Studio 2022 Other compilers or later versions may work, but they are not tested. diff --git a/kokoro/scripts/windows/build.bat b/kokoro/scripts/windows/build.bat index 89e1f01848..bb14da3dc9 100644 --- a/kokoro/scripts/windows/build.bat +++ b/kokoro/scripts/windows/build.bat @@ -30,6 +30,9 @@ set PATH=C:\python36;"C:\Program Files\cmake-3.23.1-windows-x86_64\bin";%PATH% if %VS_VERSION% == 2017 ( call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 echo "Using VS 2017..." +) else if %VS_VERSION% == 2019 ( + call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 + echo "Using VS 2019..." ) cd %SRC% diff --git a/kokoro/windows-msvc-2019-debug/build.bat b/kokoro/windows-msvc-2019-debug/build.bat new file mode 100644 index 0000000000..7ad94c19f5 --- /dev/null +++ b/kokoro/windows-msvc-2019-debug/build.bat @@ -0,0 +1,23 @@ +:: Copyright (c) 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. +:: +:: Windows Build Script. + +@echo on + +:: Find out the directory of the common build script. +set SCRIPT_DIR=%~dp0 + +:: Call with correct parameter +call %SCRIPT_DIR%\..\scripts\windows\build.bat Debug 2019 diff --git a/kokoro/windows-msvc-2019-debug/continuous.cfg b/kokoro/windows-msvc-2019-debug/continuous.cfg new file mode 100644 index 0000000000..e3a7863d34 --- /dev/null +++ b/kokoro/windows-msvc-2019-debug/continuous.cfg @@ -0,0 +1,22 @@ +# Copyright (c) 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. + +# Continuous build configuration. +build_file: "SPIRV-Tools/kokoro/windows-msvc-2019-debug/build.bat" + +action { + define_artifacts { + regex: "install.zip" + } +} diff --git a/kokoro/windows-msvc-2019-debug/presubmit.cfg b/kokoro/windows-msvc-2019-debug/presubmit.cfg new file mode 100644 index 0000000000..0ed359407b --- /dev/null +++ b/kokoro/windows-msvc-2019-debug/presubmit.cfg @@ -0,0 +1,16 @@ +# Copyright (c) 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. + +# Presubmit build configuration. +build_file: "SPIRV-Tools/kokoro/windows-msvc-2019-debug/build.bat" diff --git a/kokoro/windows-msvc-2019-release/build.bat b/kokoro/windows-msvc-2019-release/build.bat new file mode 100644 index 0000000000..8212924549 --- /dev/null +++ b/kokoro/windows-msvc-2019-release/build.bat @@ -0,0 +1,24 @@ +:: Copyright (c) 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. +:: +:: Windows Build Script. + +@echo on + +:: Find out the directory of the common build script. +set SCRIPT_DIR=%~dp0 + +:: Call with correct parameter +call %SCRIPT_DIR%\..\scripts\windows\build.bat RelWithDebInfo 2019 + diff --git a/kokoro/windows-msvc-2019-release/continuous.cfg b/kokoro/windows-msvc-2019-release/continuous.cfg new file mode 100644 index 0000000000..624ccbde6e --- /dev/null +++ b/kokoro/windows-msvc-2019-release/continuous.cfg @@ -0,0 +1,22 @@ +# Copyright (c) 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. + +# Continuous build configuration. +build_file: "SPIRV-Tools/kokoro/windows-msvc-2019-release/build.bat" + +action { + define_artifacts { + regex: "install.zip" + } +} diff --git a/kokoro/windows-msvc-2019-release/presubmit.cfg b/kokoro/windows-msvc-2019-release/presubmit.cfg new file mode 100644 index 0000000000..4c578e0069 --- /dev/null +++ b/kokoro/windows-msvc-2019-release/presubmit.cfg @@ -0,0 +1,16 @@ +# Copyright (c) 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. + +# Presubmit build configuration. +build_file: "SPIRV-Tools/kokoro/windows-msvc-2019-release/build.bat" From bebca22e2d4d40bd2d2c603699cc3606332a5325 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 19 Jan 2023 00:49:07 +0000 Subject: [PATCH 016/523] Rename bot in autoroll.yml (#5072) The current bot is having trouble with the CLA. I checked with the Khronos admin, and this was his reply: > We already safe list *[bot] which should account for all GitHub bots. If you have manually named the GitHub Actions bot to GitHub Actions bot, it should be renamed to GitHub Actions[bot]. This should resolve the issue. Trying that to see if it works. --- .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 bcb6144734..4b2818e07a 100644 --- a/.github/workflows/autoroll.yml +++ b/.github/workflows/autoroll.yml @@ -25,7 +25,7 @@ jobs: - name: Setup git user information run: | - git config user.name "GitHub Actions bot" + git config user.name "GitHub Actions[bot]" git config user.email "<>" git checkout -b roll_deps From bb1c885956e6f779d51ec4bb4ec9b2f572ca8ed0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 19 Jan 2023 01:41:29 +0000 Subject: [PATCH 017/523] Roll external/spirv-headers/ d13b52222..aa331ab0f (5 commits) (#5074) https://github.com/KhronosGroup/SPIRV-Headers/compare/d13b52222c39...aa331ab0ffcb $ git log d13b52222..aa331ab0f --date=short --no-merges --format='%ad %ae %s' 2023-01-17 ben.ashbaugh decouple SPV_KHR_shader_clock from the Shader capability 2023-01-04 brox.chen remove MMHostInterfaceAlignment and added parameters 2022-12-09 brox.chen added extension name 2022-11-30 brox.chen added SPRIV_INTEL_argument_interfaces 2022-10-16 qingyuanz NonSemantic.DebugBreak 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 c6e32ed601..2ec69b98cb 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v3.13.0.1', 're2_revision': '954656f47fe8fb505d4818da1e128417a79ea500', - 'spirv_headers_revision': 'd13b52222c39a7e9a401b44646f0ca3a640fbd47', + 'spirv_headers_revision': 'aa331ab0ffcb3a67021caa1a0c1c9017712f2f31', } deps = { From b6498eac1e03f3fefb1c7b09c77a4f375437011c Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 19 Jan 2023 10:38:48 +0000 Subject: [PATCH 018/523] Limit when the github action bazel builds run (#5071) The bazel build are set up to run any time there is a push to any branch. This cause the same workflow to be run twice when a PR is updated. I'm changing the workflow to trigger on there is a push to "main", for the continuous test, and leaving the pull_request trigger for the presubmit test. --- .github/workflows/bazel.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index c101eb66c4..03f3bf51fc 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -1,6 +1,10 @@ name: Build and Test with Bazel -on: [push, pull_request] +on: + push: + branches: + - 'main' + pull_request: jobs: build: From c51e2afe001f4c8380c096e4416f3511798d859a Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 19 Jan 2023 15:25:25 +0000 Subject: [PATCH 019/523] Add kokoro:run label to autoroll PRs (#5077) --- .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 4b2818e07a..a33034b38d 100644 --- a/.github/workflows/autoroll.yml +++ b/.github/workflows/autoroll.yml @@ -43,6 +43,6 @@ jobs: if: steps.update_dependencies.outputs.changed == 'true' run: | git push --force --set-upstream origin roll_deps - gh pr create --base main -f -r s-perron + gh pr create --label 'kokoro:run' --base main -f -r s-perron env: GITHUB_TOKEN: ${{ github.token }} From cdc4e528f3dbe7e38fa3438544918757b098235c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Fri, 20 Jan 2023 15:17:34 +0100 Subject: [PATCH 020/523] build: move from c++11 to c++17 (#4983) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * build: move from c++11 to c++17 Moving from cpp 11 to cpp 17 will allow us to use modern features like filesystem support, optional, any, execution policies and improved templates. Signed-off-by: Nathan Gauër --- CMakeLists.txt | 12 ++++++------ README.md | 6 ++++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0f4eb23f7..1c7b071af3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,13 +25,14 @@ include(GNUInstallDirs) set(CMAKE_POSITION_INDEPENDENT_CODE ON) -# Require at least C++11 +# Require at least C++17 if(NOT CMAKE_CXX_STANDARD) - set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD 17) endif() -if(${CMAKE_CXX_STANDARD} LESS 11) - message(FATAL_ERROR "SPIRV-Tools requires C++11 or later, but is configured for C++${CMAKE_CXX_STANDARD})") +if(${CMAKE_CXX_STANDARD} LESS 17) + message(FATAL_ERROR "SPIRV-Tools requires C++17 or later, but is configured for C++${CMAKE_CXX_STANDARD})") endif() +set(CMAKE_CXX_EXTENSIONS OFF) option(ENABLE_RTTI "Enables RTTI" OFF) @@ -189,10 +190,9 @@ function(spvtools_default_compile_options TARGET) target_compile_options(${TARGET} PRIVATE ${SPIRV_WARNINGS}) if (${COMPILER_IS_LIKE_GNU}) - target_compile_options(${TARGET} PRIVATE -std=c++11 -fno-exceptions) target_compile_options(${TARGET} PRIVATE -Wall -Wextra -Wno-long-long -Wshadow -Wundef -Wconversion - -Wno-sign-conversion) + -Wno-sign-conversion -fno-exceptions) if(NOT ENABLE_RTTI) add_compile_options(-fno-rtti) diff --git a/README.md b/README.md index 57827c9ef2..baa44e7077 100644 --- a/README.md +++ b/README.md @@ -438,7 +438,9 @@ On Windows - Visual Studio 2019 - Visual Studio 2022 -Other compilers or later versions may work, but they are not tested. +Note: Visual Studio 2017 has incomplete c++17 support. We might stop +testing it soon. Other compilers or later versions may work, but they are not +tested. ### CMake options @@ -499,7 +501,7 @@ The script requires Chromium's ### Usage -The internals of the library use C++11 features, and are exposed via both a C +The internals of the library use C++17 features, and are exposed via both a C and C++ API. In order to use the library from an application, the include path should point From 8fbb53dae4961316229bf465d3bf07c5725667c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 23 Jan 2023 15:22:40 +0100 Subject: [PATCH 021/523] kokoro: fix dubious ownership (#5078) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kokoro clones repos with a different user used to run the build steps, meaning if some git command must be run at build time, they will fail because of this dubious ownership issue. Running some git commands makes only sense with history, so changing checkout depth so we can run them and get the true result. This is a known Kororo issue. Fixing this is required to generate the version file using git history. Signed-off-by: Nathan Gauër --- .github/workflows/bazel.yml | 1 + .github/workflows/wasm.yml | 3 ++- kokoro/check-format/build.sh | 5 +++++ kokoro/macos-clang-debug/build.sh | 1 - kokoro/macos-clang-release-bazel/build.sh | 5 +++++ kokoro/macos-clang-release/build.sh | 1 - kokoro/scripts/linux/build-docker.sh | 5 +++++ kokoro/scripts/macos/build.sh | 5 +++++ source/wasm/build.sh | 5 +++++ 9 files changed, 28 insertions(+), 3 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 03f3bf51fc..7706c03b8c 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -17,6 +17,7 @@ jobs: steps: - uses: actions/checkout@v3 + fetch-depth: '0' - name: Download dependencies run: python3 utils/git-sync-deps - name: Mount Bazel cache diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 0fc18062b4..1439f2110f 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -7,7 +7,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + fetch-depth: '0' - name: Build web run: docker-compose -f source/wasm/docker-compose.yml --project-directory . up - name: Run tests diff --git a/kokoro/check-format/build.sh b/kokoro/check-format/build.sh index 8a5df9a835..96603e4476 100644 --- a/kokoro/check-format/build.sh +++ b/kokoro/check-format/build.sh @@ -23,6 +23,11 @@ set -x BUILD_ROOT=$PWD SRC=$PWD/github/SPIRV-Tools +# This is required to run any git command in the docker since owner will +# have changed between the clone environment, and the docker container. +# Marking the root of the repo as safe for ownership changes. +git config --global --add safe.directory $SRC + # Get clang-format-5.0.0. # Once kokoro upgrades the Ubuntu VMs, we can use 'apt-get install clang-format' curl -L http://releases.llvm.org/5.0.0/clang+llvm-5.0.0-linux-x86_64-ubuntu14.04.tar.xz -o clang-llvm.tar.xz diff --git a/kokoro/macos-clang-debug/build.sh b/kokoro/macos-clang-debug/build.sh index 8d9a062f62..fca76fc624 100644 --- a/kokoro/macos-clang-debug/build.sh +++ b/kokoro/macos-clang-debug/build.sh @@ -22,4 +22,3 @@ set -x SCRIPT_DIR=`dirname "$BASH_SOURCE"` source $SCRIPT_DIR/../scripts/macos/build.sh Debug - diff --git a/kokoro/macos-clang-release-bazel/build.sh b/kokoro/macos-clang-release-bazel/build.sh index c62611abdd..50ad42bc81 100644 --- a/kokoro/macos-clang-release-bazel/build.sh +++ b/kokoro/macos-clang-release-bazel/build.sh @@ -24,6 +24,11 @@ CC=clang CXX=clang++ SRC=$PWD/github/SPIRV-Tools +# This is required to run any git command in the docker since owner will +# have changed between the clone environment, and the docker container. +# Marking the root of the repo as safe for ownership changes. +git config --global --add safe.directory $SRC + cd $SRC git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers git clone https://github.com/google/googletest external/googletest diff --git a/kokoro/macos-clang-release/build.sh b/kokoro/macos-clang-release/build.sh index ccc8b16aa0..b1460a9716 100644 --- a/kokoro/macos-clang-release/build.sh +++ b/kokoro/macos-clang-release/build.sh @@ -22,4 +22,3 @@ set -x SCRIPT_DIR=`dirname "$BASH_SOURCE"` source $SCRIPT_DIR/../scripts/macos/build.sh RelWithDebInfo - diff --git a/kokoro/scripts/linux/build-docker.sh b/kokoro/scripts/linux/build-docker.sh index 7d62ee3660..52fbb9e4bb 100755 --- a/kokoro/scripts/linux/build-docker.sh +++ b/kokoro/scripts/linux/build-docker.sh @@ -20,6 +20,11 @@ set -e # Display commands being run. set -x +# This is required to run any git command in the docker since owner will +# have changed between the clone environment, and the docker container. +# Marking the root of the repo as safe for ownership changes. +git config --global --add safe.directory $ROOT_DIR + . /bin/using.sh # Declare the bash `using` function for configuring toolchains. if [ $COMPILER = "clang" ]; then diff --git a/kokoro/scripts/macos/build.sh b/kokoro/scripts/macos/build.sh index 1d346e7618..8381f87de0 100644 --- a/kokoro/scripts/macos/build.sh +++ b/kokoro/scripts/macos/build.sh @@ -24,6 +24,11 @@ BUILD_ROOT=$PWD SRC=$PWD/github/SPIRV-Tools BUILD_TYPE=$1 +# This is required to run any git command in the docker since owner will +# have changed between the clone environment, and the docker container. +# Marking the root of the repo as safe for ownership changes. +git config --global --add safe.directory $SRC + # Get NINJA. wget -q https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-mac.zip unzip -q ninja-mac.zip diff --git a/source/wasm/build.sh b/source/wasm/build.sh index f02ae525c3..4f7b701c8a 100755 --- a/source/wasm/build.sh +++ b/source/wasm/build.sh @@ -16,6 +16,11 @@ set -e +# This is required to run any git command in the docker since owner will +# have changed between the clone environment, and the docker container. +# Marking the root of the repo as safe for ownership changes. +git config --global --add safe.directory /app + NUM_CORES=$(nproc) echo "Detected $NUM_CORES cores for building" From f0b900ed9a172f48e3b93528fe94d08c48de3069 Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Mon, 23 Jan 2023 23:30:45 +0900 Subject: [PATCH 022/523] spirv-val: Initial SPV_EXT_mesh_shader builtins (#5080) --- source/val/validate_builtins.cpp | 236 ++++++++++++++++++++++- source/val/validation_state.cpp | 24 +++ test/val/val_builtins_test.cpp | 314 +++++++++++++++++++++++++++++++ 3 files changed, 571 insertions(+), 3 deletions(-) diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp index c07dcaddd2..f359882efd 100644 --- a/source/val/validate_builtins.cpp +++ b/source/val/validate_builtins.cpp @@ -120,13 +120,15 @@ typedef enum VUIDError_ { VUIDErrorMax, } VUIDError; -const static uint32_t NumVUIDBuiltins = 36; +const static uint32_t NumVUIDBuiltins = 40; typedef struct { spv::BuiltIn builtIn; uint32_t vuid[VUIDErrorMax]; // execution mode, storage class, type VUIDs } BuiltinVUIDMapping; +// Many built-ins have the same checks (Storage Class, Type, etc) +// This table provides a nice LUT for the VUIDs std::array builtinVUIDInfo = {{ // clang-format off {spv::BuiltIn::SubgroupEqMask, {0, 4370, 4371}}, @@ -165,8 +167,12 @@ std::array builtinVUIDInfo = {{ {spv::BuiltIn::CullMaskKHR, {6735, 6736, 6737}}, {spv::BuiltIn::BaryCoordKHR, {4154, 4155, 4156}}, {spv::BuiltIn::BaryCoordNoPerspKHR, {4160, 4161, 4162}}, - // clang-format off -} }; + {spv::BuiltIn::PrimitivePointIndicesEXT, {7041, 7043, 7044}}, + {spv::BuiltIn::PrimitiveLineIndicesEXT, {7047, 7049, 7050}}, + {spv::BuiltIn::PrimitiveTriangleIndicesEXT, {7053, 7055, 7056}}, + {spv::BuiltIn::CullPrimitiveEXT, {7034, 7035, 7036}}, + // clang-format on +}}; uint32_t GetVUIDForBuiltin(spv::BuiltIn builtIn, VUIDError type) { uint32_t vuid = 0; @@ -358,6 +364,9 @@ class BuiltInsValidator { spv_result_t ValidateRayTracingBuiltinsAtDefinition( const Decoration& decoration, const Instruction& inst); + spv_result_t ValidateMeshShadingEXTBuiltinsAtDefinition( + const Decoration& decoration, const Instruction& inst); + // The following section contains functions which are called when id defined // by |referenced_inst| is // 1. referenced by |referenced_from_inst| @@ -548,6 +557,11 @@ class BuiltInsValidator { const Instruction& referenced_inst, const Instruction& referenced_from_inst); + spv_result_t ValidateMeshShadingEXTBuiltinsAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + // Validates that |built_in_inst| is not (even indirectly) referenced from // within a function which can be called with |execution_model|. // @@ -570,6 +584,9 @@ class BuiltInsValidator { spv_result_t ValidateBool( const Decoration& decoration, const Instruction& inst, const std::function& diag); + spv_result_t ValidateBoolArr( + const Decoration& decoration, const Instruction& inst, + const std::function& diag); spv_result_t ValidateI( const Decoration& decoration, const Instruction& inst, const std::function& diag); @@ -583,6 +600,10 @@ class BuiltInsValidator { spv_result_t ValidateI32Arr( const Decoration& decoration, const Instruction& inst, const std::function& diag); + spv_result_t ValidateArrayedI32Vec( + const Decoration& decoration, const Instruction& inst, + uint32_t num_components, + const std::function& diag); spv_result_t ValidateOptionalArrayedI32( const Decoration& decoration, const Instruction& inst, const std::function& diag); @@ -765,6 +786,29 @@ spv_result_t BuiltInsValidator::ValidateBool( return SPV_SUCCESS; } +spv_result_t BuiltInsValidator::ValidateBoolArr( + const Decoration& decoration, const Instruction& inst, + const std::function& diag) { + uint32_t underlying_type = 0; + if (spv_result_t error = + GetUnderlyingType(_, decoration, inst, &underlying_type)) { + return error; + } + + const Instruction* const type_inst = _.FindDef(underlying_type); + if (type_inst->opcode() != spv::Op::OpTypeArray) { + return diag(GetDefinitionDesc(decoration, inst) + " is not an array."); + } + + const uint32_t component_type = type_inst->word(2); + if (!_.IsBoolScalarType(component_type)) { + return diag(GetDefinitionDesc(decoration, inst) + + " components are not boolean scalar."); + } + + return SPV_SUCCESS; +} + spv_result_t BuiltInsValidator::ValidateI( const Decoration& decoration, const Instruction& inst, const std::function& diag) { @@ -911,6 +955,45 @@ spv_result_t BuiltInsValidator::ValidateI32Vec( return SPV_SUCCESS; } +spv_result_t BuiltInsValidator::ValidateArrayedI32Vec( + const Decoration& decoration, const Instruction& inst, + uint32_t num_components, + const std::function& diag) { + uint32_t underlying_type = 0; + if (spv_result_t error = + GetUnderlyingType(_, decoration, inst, &underlying_type)) { + return error; + } + + const Instruction* const type_inst = _.FindDef(underlying_type); + if (type_inst->opcode() != spv::Op::OpTypeArray) { + return diag(GetDefinitionDesc(decoration, inst) + " is not an array."); + } + + const uint32_t component_type = type_inst->word(2); + if (!_.IsIntVectorType(component_type)) { + return diag(GetDefinitionDesc(decoration, inst) + " is not an int vector."); + } + + const uint32_t actual_num_components = _.GetDimension(component_type); + if (_.GetDimension(component_type) != num_components) { + std::ostringstream ss; + ss << GetDefinitionDesc(decoration, inst) << " has " + << actual_num_components << " components."; + return diag(ss.str()); + } + + const uint32_t bit_width = _.GetBitWidth(component_type); + if (bit_width != 32) { + std::ostringstream ss; + ss << GetDefinitionDesc(decoration, inst) + << " has components with bit width " << bit_width << "."; + return diag(ss.str()); + } + + return SPV_SUCCESS; +} + spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32Vec( const Decoration& decoration, const Instruction& inst, uint32_t num_components, @@ -4110,6 +4193,147 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference( return SPV_SUCCESS; } +spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition( + const Decoration& decoration, const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); + switch (builtin) { + case spv::BuiltIn::PrimitivePointIndicesEXT: { + if (spv_result_t error = ValidateI32Arr( + decoration, inst, + [this, &inst, &decoration, + &vuid](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " variable needs to be a 32-bit int array." + << message; + })) { + return error; + } + break; + } + case spv::BuiltIn::PrimitiveLineIndicesEXT: { + if (spv_result_t error = ValidateArrayedI32Vec( + decoration, inst, 2, + [this, &inst, &decoration, + &vuid](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " variable needs to be a 2-component 32-bit int " + "array." + << message; + })) { + return error; + } + break; + } + case spv::BuiltIn::PrimitiveTriangleIndicesEXT: { + if (spv_result_t error = ValidateArrayedI32Vec( + decoration, inst, 3, + [this, &inst, &decoration, + &vuid](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " variable needs to be a 3-component 32-bit int " + "array." + << message; + })) { + return error; + } + break; + } + case spv::BuiltIn::CullPrimitiveEXT: { + if (spv_result_t error = ValidateBoolArr( + decoration, inst, + [this, &inst, &decoration, + &vuid](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " variable needs to be a boolean array." << message; + })) { + return error; + } + break; + } + default: + break; + } + } + // Seed at reference checks with this built-in. + return ValidateMeshShadingEXTBuiltinsAtReference(decoration, inst, inst, + inst); +} + +spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::StorageClass storage_class = + GetStorageClass(referenced_from_inst); + if (storage_class != spv::StorageClass::Max && + storage_class != spv::StorageClass::Output) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be only used for variables with Output storage class. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst) + << " " << GetStorageClassDesc(referenced_from_inst); + } + + for (const spv::ExecutionModel execution_model : execution_models_) { + if (execution_model != spv::ExecutionModel::MeshEXT) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + decoration.params()[0]) + << " to be used only with MeshEXT execution model. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst, execution_model); + } + } + } + + if (function_id_ == 0) { + // Propagate this rule to all dependant ids in the global scope. + id_to_at_reference_checks_[referenced_from_inst.id()].push_back( + std::bind(&BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference, + this, decoration, built_in_inst, referenced_from_inst, + std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( const Decoration& decoration, const Instruction& inst) { const spv::BuiltIn label = spv::BuiltIn(decoration.params()[0]); @@ -4285,6 +4509,12 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case spv::BuiltIn::CullMaskKHR: { return ValidateRayTracingBuiltinsAtDefinition(decoration, inst); } + case spv::BuiltIn::PrimitivePointIndicesEXT: + case spv::BuiltIn::PrimitiveLineIndicesEXT: + case spv::BuiltIn::PrimitiveTriangleIndicesEXT: + case spv::BuiltIn::CullPrimitiveEXT: { + return ValidateMeshShadingEXTBuiltinsAtDefinition(decoration, inst); + } case spv::BuiltIn::PrimitiveShadingRateKHR: { return ValidatePrimitiveShadingRateAtDefinition(decoration, inst); } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index c95eec366b..40abcfb0a3 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -2165,6 +2165,30 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-Uniform-06925); case 6997: return VUID_WRAP(VUID-StandaloneSpirv-SubgroupVoteKHR-06997); + case 7034: + return VUID_WRAP(VUID-CullPrimitiveEXT-CullPrimitiveEXT-07034); + case 7035: + return VUID_WRAP(VUID-CullPrimitiveEXT-CullPrimitiveEXT-07035); + case 7036: + return VUID_WRAP(VUID-CullPrimitiveEXT-CullPrimitiveEXT-07036); + case 7041: + return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07041); + case 7043: + return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07043); + case 7044: + return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07044); + case 7047: + return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07047); + case 7049: + return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07049); + case 7050: + return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07050); + case 7053: + return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07053); + case 7055: + return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07055); + case 7056: + return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07056); case 7102: return VUID_WRAP(VUID-StandaloneSpirv-MeshEXT-07102); case 7320: diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp index 4f9fc97631..94fb794e06 100644 --- a/test/val/val_builtins_test.cpp +++ b/test/val/val_builtins_test.cpp @@ -4261,6 +4261,320 @@ INSTANTIATE_TEST_SUITE_P( Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 3-component 32-bit float vector")))); +std::string GenerateMeshShadingCode(const std::string& built_in, + const std::string& execution_mode, + const std::string& body, + const std::string& declarations = "") { + std::ostringstream ss; + ss << R"( +OpCapability MeshShadingEXT +OpExtension "SPV_EXT_mesh_shader" +OpMemoryModel Logical GLSL450 +OpEntryPoint MeshEXT %main "main" %var +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main OutputVertices 1 +OpExecutionMode %main OutputPrimitivesEXT 16 +)"; + ss << "OpExecutionMode %main " << execution_mode << "\n"; + ss << "OpDecorate %var BuiltIn " << built_in << "\n"; + + ss << R"( +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%int = OpTypeInt 32 1 +%uint = OpTypeInt 32 0 +%v2uint = OpTypeVector %uint 2 +%v3uint = OpTypeVector %uint 3 + +%int_0 = OpConstant %int 0 +%uint_16 = OpConstant %uint 16 +)"; + + ss << declarations; + + ss << R"( +%main = OpFunction %void None %func +%main_entry = OpLabel +)"; + + ss << body; + + ss << R"( +OpReturn +OpFunctionEnd)"; + return ss.str(); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTSuccess) { + const std::string declarations = R"( +%array = OpTypeArray %v3uint %uint_16 +%array_ptr = OpTypePointer Output %array +%var = OpVariable %array_ptr Output +%ptr = OpTypePointer Output %v3uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT", + "OutputTrianglesEXT", body, declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2)); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTStorageClass) { + const std::string declarations = R"( +%array = OpTypeArray %v3uint %uint_16 +%array_ptr = OpTypePointer Input %array +%var = OpVariable %array_ptr Input +%ptr = OpTypePointer Input %v3uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT", + "OutputTrianglesEXT", body, declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-PrimitiveTriangleIndicesEXT-" + "PrimitiveTriangleIndicesEXT-07055")); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTVectorSize) { + const std::string declarations = R"( +%array = OpTypeArray %v2uint %uint_16 +%array_ptr = OpTypePointer Output %array +%var = OpVariable %array_ptr Output +%ptr = OpTypePointer Output %v2uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT", + "OutputTrianglesEXT", body, declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-PrimitiveTriangleIndicesEXT-" + "PrimitiveTriangleIndicesEXT-07056")); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTNonArray) { + const std::string declarations = R"( +%ptr = OpTypePointer Output %v3uint +%var = OpVariable %ptr Output +)"; + const std::string body = R"( +%load = OpLoad %v3uint %var +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT", + "OutputTrianglesEXT", body, declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-PrimitiveTriangleIndicesEXT-" + "PrimitiveTriangleIndicesEXT-07056")); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTSuccess) { + const std::string declarations = R"( +%array = OpTypeArray %v2uint %uint_16 +%array_ptr = OpTypePointer Output %array +%var = OpVariable %array_ptr Output +%ptr = OpTypePointer Output %v2uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitiveLineIndicesEXT", "OutputLinesEXT", body, + declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2)); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTStorageClass) { + const std::string declarations = R"( +%array = OpTypeArray %v2uint %uint_16 +%array_ptr = OpTypePointer Input %array +%var = OpVariable %array_ptr Input +%ptr = OpTypePointer Input %v2uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitiveLineIndicesEXT", "OutputLinesEXT", body, + declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT( + getDiagnosticString(), + AnyVUID("VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07049")); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTType) { + const std::string declarations = R"( +%array = OpTypeArray %v3uint %uint_16 +%array_ptr = OpTypePointer Input %array +%var = OpVariable %array_ptr Input +%ptr = OpTypePointer Input %v3uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitiveLineIndicesEXT", "OutputLinesEXT", body, + declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT( + getDiagnosticString(), + AnyVUID("VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07050")); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTSuccess) { + const std::string declarations = R"( +%array = OpTypeArray %uint %uint_16 +%array_ptr = OpTypePointer Output %array +%var = OpVariable %array_ptr Output +%ptr = OpTypePointer Output %uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitivePointIndicesEXT", "OutputPoints", body, + declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2)); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTStorageClass) { + const std::string declarations = R"( +%array = OpTypeArray %uint %uint_16 +%array_ptr = OpTypePointer Input %array +%var = OpVariable %array_ptr Input +%ptr = OpTypePointer Input %uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitivePointIndicesEXT", "OutputPoints", body, + declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT( + getDiagnosticString(), + AnyVUID("VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07043")); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTType) { + const std::string declarations = R"( +%array = OpTypeArray %v3uint %uint_16 +%array_ptr = OpTypePointer Output %array +%var = OpVariable %array_ptr Output +%ptr = OpTypePointer Output %v3uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitivePointIndicesEXT", "OutputPoints", body, + declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT( + getDiagnosticString(), + AnyVUID("VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07044")); +} + +TEST_F(ValidateBuiltIns, VulkanCullPrimitiveEXTSuccess) { + const std::string declarations = R"( +%array = OpTypeArray %bool %uint_16 +%array_ptr = OpTypePointer Output %array +%var = OpVariable %array_ptr Output +%ptr = OpTypePointer Output %bool +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("CullPrimitiveEXT", "OutputPoints", body, + declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2)); +} + +TEST_F(ValidateBuiltIns, VulkanCullPrimitiveEXTStorageClass) { + const std::string declarations = R"( +%array = OpTypeArray %bool %uint_16 +%array_ptr = OpTypePointer Input %array +%var = OpVariable %array_ptr Input +%ptr = OpTypePointer Input %bool +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("CullPrimitiveEXT", "OutputPoints", body, + declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-CullPrimitiveEXT-CullPrimitiveEXT-07035")); +} + +TEST_F(ValidateBuiltIns, VulkanCullPrimitiveEXTType) { + const std::string declarations = R"( +%array = OpTypeArray %v3uint %uint_16 +%array_ptr = OpTypePointer Output %array +%var = OpVariable %array_ptr Output +%ptr = OpTypePointer Output %v3uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("CullPrimitiveEXT", "OutputPoints", body, + declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-CullPrimitiveEXT-CullPrimitiveEXT-07036")); +} } // namespace } // namespace val } // namespace spvtools From fe087cd5f0e6286ae79fb0046433f228e3279b73 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Mon, 23 Jan 2023 14:36:33 +0000 Subject: [PATCH 023/523] Revert "kokoro: fix dubious ownership (#5078)" (#5081) This reverts commit 8fbb53dae4961316229bf465d3bf07c5725667c0. --- .github/workflows/bazel.yml | 1 - .github/workflows/wasm.yml | 3 +-- kokoro/check-format/build.sh | 5 ----- kokoro/macos-clang-debug/build.sh | 1 + kokoro/macos-clang-release-bazel/build.sh | 5 ----- kokoro/macos-clang-release/build.sh | 1 + kokoro/scripts/linux/build-docker.sh | 5 ----- kokoro/scripts/macos/build.sh | 5 ----- source/wasm/build.sh | 5 ----- 9 files changed, 3 insertions(+), 28 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 7706c03b8c..03f3bf51fc 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -17,7 +17,6 @@ jobs: steps: - uses: actions/checkout@v3 - fetch-depth: '0' - name: Download dependencies run: python3 utils/git-sync-deps - name: Mount Bazel cache diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 1439f2110f..0fc18062b4 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -7,8 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - fetch-depth: '0' + - uses: actions/checkout@v2 - name: Build web run: docker-compose -f source/wasm/docker-compose.yml --project-directory . up - name: Run tests diff --git a/kokoro/check-format/build.sh b/kokoro/check-format/build.sh index 96603e4476..8a5df9a835 100644 --- a/kokoro/check-format/build.sh +++ b/kokoro/check-format/build.sh @@ -23,11 +23,6 @@ set -x BUILD_ROOT=$PWD SRC=$PWD/github/SPIRV-Tools -# This is required to run any git command in the docker since owner will -# have changed between the clone environment, and the docker container. -# Marking the root of the repo as safe for ownership changes. -git config --global --add safe.directory $SRC - # Get clang-format-5.0.0. # Once kokoro upgrades the Ubuntu VMs, we can use 'apt-get install clang-format' curl -L http://releases.llvm.org/5.0.0/clang+llvm-5.0.0-linux-x86_64-ubuntu14.04.tar.xz -o clang-llvm.tar.xz diff --git a/kokoro/macos-clang-debug/build.sh b/kokoro/macos-clang-debug/build.sh index fca76fc624..8d9a062f62 100644 --- a/kokoro/macos-clang-debug/build.sh +++ b/kokoro/macos-clang-debug/build.sh @@ -22,3 +22,4 @@ set -x SCRIPT_DIR=`dirname "$BASH_SOURCE"` source $SCRIPT_DIR/../scripts/macos/build.sh Debug + diff --git a/kokoro/macos-clang-release-bazel/build.sh b/kokoro/macos-clang-release-bazel/build.sh index 50ad42bc81..c62611abdd 100644 --- a/kokoro/macos-clang-release-bazel/build.sh +++ b/kokoro/macos-clang-release-bazel/build.sh @@ -24,11 +24,6 @@ CC=clang CXX=clang++ SRC=$PWD/github/SPIRV-Tools -# This is required to run any git command in the docker since owner will -# have changed between the clone environment, and the docker container. -# Marking the root of the repo as safe for ownership changes. -git config --global --add safe.directory $SRC - cd $SRC git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers git clone https://github.com/google/googletest external/googletest diff --git a/kokoro/macos-clang-release/build.sh b/kokoro/macos-clang-release/build.sh index b1460a9716..ccc8b16aa0 100644 --- a/kokoro/macos-clang-release/build.sh +++ b/kokoro/macos-clang-release/build.sh @@ -22,3 +22,4 @@ set -x SCRIPT_DIR=`dirname "$BASH_SOURCE"` source $SCRIPT_DIR/../scripts/macos/build.sh RelWithDebInfo + diff --git a/kokoro/scripts/linux/build-docker.sh b/kokoro/scripts/linux/build-docker.sh index 52fbb9e4bb..7d62ee3660 100755 --- a/kokoro/scripts/linux/build-docker.sh +++ b/kokoro/scripts/linux/build-docker.sh @@ -20,11 +20,6 @@ set -e # Display commands being run. set -x -# This is required to run any git command in the docker since owner will -# have changed between the clone environment, and the docker container. -# Marking the root of the repo as safe for ownership changes. -git config --global --add safe.directory $ROOT_DIR - . /bin/using.sh # Declare the bash `using` function for configuring toolchains. if [ $COMPILER = "clang" ]; then diff --git a/kokoro/scripts/macos/build.sh b/kokoro/scripts/macos/build.sh index 8381f87de0..1d346e7618 100644 --- a/kokoro/scripts/macos/build.sh +++ b/kokoro/scripts/macos/build.sh @@ -24,11 +24,6 @@ BUILD_ROOT=$PWD SRC=$PWD/github/SPIRV-Tools BUILD_TYPE=$1 -# This is required to run any git command in the docker since owner will -# have changed between the clone environment, and the docker container. -# Marking the root of the repo as safe for ownership changes. -git config --global --add safe.directory $SRC - # Get NINJA. wget -q https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-mac.zip unzip -q ninja-mac.zip diff --git a/source/wasm/build.sh b/source/wasm/build.sh index 4f7b701c8a..f02ae525c3 100755 --- a/source/wasm/build.sh +++ b/source/wasm/build.sh @@ -16,11 +16,6 @@ set -e -# This is required to run any git command in the docker since owner will -# have changed between the clone environment, and the docker container. -# Marking the root of the repo as safe for ownership changes. -git config --global --add safe.directory /app - NUM_CORES=$(nproc) echo "Detected $NUM_CORES cores for building" From 7f9184a5b2123aa820ff877c2548fad127e08486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 23 Jan 2023 16:32:39 +0100 Subject: [PATCH 024/523] kokoro: fix dubious ownership (#5082) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kokoro clones repos with a different user used to run the build steps, meaning if some git command must be run at build time, they will fail because of this dubious ownership issue. Running some git commands makes only sense with history, so changing checkout depth so we can run them and get the true result. This is a known Kororo issue. Fixing this is required to generate the version file using git history. Signed-off-by: Nathan Gauër Signed-off-by: Nathan Gauër --- .github/workflows/bazel.yml | 4 +++- .github/workflows/wasm.yml | 4 +++- kokoro/check-format/build.sh | 5 +++++ kokoro/macos-clang-debug/build.sh | 1 - kokoro/macos-clang-release-bazel/build.sh | 5 +++++ kokoro/macos-clang-release/build.sh | 1 - kokoro/scripts/linux/build-docker.sh | 5 +++++ kokoro/scripts/macos/build.sh | 5 +++++ source/wasm/build.sh | 5 +++++ 9 files changed, 31 insertions(+), 4 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 03f3bf51fc..77ef657568 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -1,6 +1,6 @@ name: Build and Test with Bazel -on: +on: push: branches: - 'main' @@ -17,6 +17,8 @@ jobs: steps: - uses: actions/checkout@v3 + with: + fetch-depth: '0' - name: Download dependencies run: python3 utils/git-sync-deps - name: Mount Bazel cache diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 0fc18062b4..fa8951a16e 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -7,7 +7,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 + with: + fetch-depth: '0' - name: Build web run: docker-compose -f source/wasm/docker-compose.yml --project-directory . up - name: Run tests diff --git a/kokoro/check-format/build.sh b/kokoro/check-format/build.sh index 8a5df9a835..96603e4476 100644 --- a/kokoro/check-format/build.sh +++ b/kokoro/check-format/build.sh @@ -23,6 +23,11 @@ set -x BUILD_ROOT=$PWD SRC=$PWD/github/SPIRV-Tools +# This is required to run any git command in the docker since owner will +# have changed between the clone environment, and the docker container. +# Marking the root of the repo as safe for ownership changes. +git config --global --add safe.directory $SRC + # Get clang-format-5.0.0. # Once kokoro upgrades the Ubuntu VMs, we can use 'apt-get install clang-format' curl -L http://releases.llvm.org/5.0.0/clang+llvm-5.0.0-linux-x86_64-ubuntu14.04.tar.xz -o clang-llvm.tar.xz diff --git a/kokoro/macos-clang-debug/build.sh b/kokoro/macos-clang-debug/build.sh index 8d9a062f62..fca76fc624 100644 --- a/kokoro/macos-clang-debug/build.sh +++ b/kokoro/macos-clang-debug/build.sh @@ -22,4 +22,3 @@ set -x SCRIPT_DIR=`dirname "$BASH_SOURCE"` source $SCRIPT_DIR/../scripts/macos/build.sh Debug - diff --git a/kokoro/macos-clang-release-bazel/build.sh b/kokoro/macos-clang-release-bazel/build.sh index c62611abdd..50ad42bc81 100644 --- a/kokoro/macos-clang-release-bazel/build.sh +++ b/kokoro/macos-clang-release-bazel/build.sh @@ -24,6 +24,11 @@ CC=clang CXX=clang++ SRC=$PWD/github/SPIRV-Tools +# This is required to run any git command in the docker since owner will +# have changed between the clone environment, and the docker container. +# Marking the root of the repo as safe for ownership changes. +git config --global --add safe.directory $SRC + cd $SRC git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers git clone https://github.com/google/googletest external/googletest diff --git a/kokoro/macos-clang-release/build.sh b/kokoro/macos-clang-release/build.sh index ccc8b16aa0..b1460a9716 100644 --- a/kokoro/macos-clang-release/build.sh +++ b/kokoro/macos-clang-release/build.sh @@ -22,4 +22,3 @@ set -x SCRIPT_DIR=`dirname "$BASH_SOURCE"` source $SCRIPT_DIR/../scripts/macos/build.sh RelWithDebInfo - diff --git a/kokoro/scripts/linux/build-docker.sh b/kokoro/scripts/linux/build-docker.sh index 7d62ee3660..52fbb9e4bb 100755 --- a/kokoro/scripts/linux/build-docker.sh +++ b/kokoro/scripts/linux/build-docker.sh @@ -20,6 +20,11 @@ set -e # Display commands being run. set -x +# This is required to run any git command in the docker since owner will +# have changed between the clone environment, and the docker container. +# Marking the root of the repo as safe for ownership changes. +git config --global --add safe.directory $ROOT_DIR + . /bin/using.sh # Declare the bash `using` function for configuring toolchains. if [ $COMPILER = "clang" ]; then diff --git a/kokoro/scripts/macos/build.sh b/kokoro/scripts/macos/build.sh index 1d346e7618..8381f87de0 100644 --- a/kokoro/scripts/macos/build.sh +++ b/kokoro/scripts/macos/build.sh @@ -24,6 +24,11 @@ BUILD_ROOT=$PWD SRC=$PWD/github/SPIRV-Tools BUILD_TYPE=$1 +# This is required to run any git command in the docker since owner will +# have changed between the clone environment, and the docker container. +# Marking the root of the repo as safe for ownership changes. +git config --global --add safe.directory $SRC + # Get NINJA. wget -q https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-mac.zip unzip -q ninja-mac.zip diff --git a/source/wasm/build.sh b/source/wasm/build.sh index f02ae525c3..4f7b701c8a 100755 --- a/source/wasm/build.sh +++ b/source/wasm/build.sh @@ -16,6 +16,11 @@ set -e +# This is required to run any git command in the docker since owner will +# have changed between the clone environment, and the docker container. +# Marking the root of the repo as safe for ownership changes. +git config --global --add safe.directory /app + NUM_CORES=$(nproc) echo "Detected $NUM_CORES cores for building" From af15e5adeabfa629b1e2b6f88d31f853f64a2daa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 24 Jan 2023 15:26:28 +0000 Subject: [PATCH 025/523] Roll external/re2/ 954656f47..ba541565b (1 commit) (#5083) https://github.com/google/re2/compare/954656f47fe8...ba541565b4fb $ git log 954656f47..ba541565b --date=short --no-merges --format='%ad %ae %s' 2023-01-23 junyer Introduce `bitmap256.cc` for `FindNextSetBit()`. 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 2ec69b98cb..ab26203aa7 100644 --- a/DEPS +++ b/DEPS @@ -12,7 +12,7 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', - 're2_revision': '954656f47fe8fb505d4818da1e128417a79ea500', + 're2_revision': 'ba541565b4fbe1684d4b98695ec0b6d6c13ba98b', 'spirv_headers_revision': 'aa331ab0ffcb3a67021caa1a0c1c9017712f2f31', } From 57fb3c7a3f12cd61a26c7ae92fa1d345830307d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Petit?= Date: Tue, 24 Jan 2023 17:27:30 +0000 Subject: [PATCH 026/523] Align git-sync-deps and CMake to use external/spirv-headers by default (#4963) This should help with avoiding mistakes such as the one that happened under #4958. Signed-off-by: Kevin Petit Change-Id: I922f02e25c507f3412e0e7a99f525fb617b2d426 Signed-off-by: Kevin Petit --- external/CMakeLists.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 179a4012f9..676ee979ea 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -30,11 +30,7 @@ if (DEFINED SPIRV-Headers_SOURCE_DIR) # This allows flexible position of the SPIRV-Headers repo. set(SPIRV_HEADER_DIR ${SPIRV-Headers_SOURCE_DIR}) else() - if (IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Headers) - set(SPIRV_HEADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Headers) - else() - set(SPIRV_HEADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/spirv-headers) - endif() + set(SPIRV_HEADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/spirv-headers) endif() if (IS_DIRECTORY ${SPIRV_HEADER_DIR}) From 5db6c38e656582c546eee04a4db34f4ca909706f Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Tue, 24 Jan 2023 19:51:39 +0000 Subject: [PATCH 027/523] Revert "spirv-val: Initial SPV_EXT_mesh_shader builtins (#5080)" (#5084) This reverts commit f0b900ed9a172f48e3b93528fe94d08c48de3069. --- source/val/validate_builtins.cpp | 236 +---------------------- source/val/validation_state.cpp | 24 --- test/val/val_builtins_test.cpp | 314 ------------------------------- 3 files changed, 3 insertions(+), 571 deletions(-) diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp index f359882efd..c07dcaddd2 100644 --- a/source/val/validate_builtins.cpp +++ b/source/val/validate_builtins.cpp @@ -120,15 +120,13 @@ typedef enum VUIDError_ { VUIDErrorMax, } VUIDError; -const static uint32_t NumVUIDBuiltins = 40; +const static uint32_t NumVUIDBuiltins = 36; typedef struct { spv::BuiltIn builtIn; uint32_t vuid[VUIDErrorMax]; // execution mode, storage class, type VUIDs } BuiltinVUIDMapping; -// Many built-ins have the same checks (Storage Class, Type, etc) -// This table provides a nice LUT for the VUIDs std::array builtinVUIDInfo = {{ // clang-format off {spv::BuiltIn::SubgroupEqMask, {0, 4370, 4371}}, @@ -167,12 +165,8 @@ std::array builtinVUIDInfo = {{ {spv::BuiltIn::CullMaskKHR, {6735, 6736, 6737}}, {spv::BuiltIn::BaryCoordKHR, {4154, 4155, 4156}}, {spv::BuiltIn::BaryCoordNoPerspKHR, {4160, 4161, 4162}}, - {spv::BuiltIn::PrimitivePointIndicesEXT, {7041, 7043, 7044}}, - {spv::BuiltIn::PrimitiveLineIndicesEXT, {7047, 7049, 7050}}, - {spv::BuiltIn::PrimitiveTriangleIndicesEXT, {7053, 7055, 7056}}, - {spv::BuiltIn::CullPrimitiveEXT, {7034, 7035, 7036}}, - // clang-format on -}}; + // clang-format off +} }; uint32_t GetVUIDForBuiltin(spv::BuiltIn builtIn, VUIDError type) { uint32_t vuid = 0; @@ -364,9 +358,6 @@ class BuiltInsValidator { spv_result_t ValidateRayTracingBuiltinsAtDefinition( const Decoration& decoration, const Instruction& inst); - spv_result_t ValidateMeshShadingEXTBuiltinsAtDefinition( - const Decoration& decoration, const Instruction& inst); - // The following section contains functions which are called when id defined // by |referenced_inst| is // 1. referenced by |referenced_from_inst| @@ -557,11 +548,6 @@ class BuiltInsValidator { const Instruction& referenced_inst, const Instruction& referenced_from_inst); - spv_result_t ValidateMeshShadingEXTBuiltinsAtReference( - const Decoration& decoration, const Instruction& built_in_inst, - const Instruction& referenced_inst, - const Instruction& referenced_from_inst); - // Validates that |built_in_inst| is not (even indirectly) referenced from // within a function which can be called with |execution_model|. // @@ -584,9 +570,6 @@ class BuiltInsValidator { spv_result_t ValidateBool( const Decoration& decoration, const Instruction& inst, const std::function& diag); - spv_result_t ValidateBoolArr( - const Decoration& decoration, const Instruction& inst, - const std::function& diag); spv_result_t ValidateI( const Decoration& decoration, const Instruction& inst, const std::function& diag); @@ -600,10 +583,6 @@ class BuiltInsValidator { spv_result_t ValidateI32Arr( const Decoration& decoration, const Instruction& inst, const std::function& diag); - spv_result_t ValidateArrayedI32Vec( - const Decoration& decoration, const Instruction& inst, - uint32_t num_components, - const std::function& diag); spv_result_t ValidateOptionalArrayedI32( const Decoration& decoration, const Instruction& inst, const std::function& diag); @@ -786,29 +765,6 @@ spv_result_t BuiltInsValidator::ValidateBool( return SPV_SUCCESS; } -spv_result_t BuiltInsValidator::ValidateBoolArr( - const Decoration& decoration, const Instruction& inst, - const std::function& diag) { - uint32_t underlying_type = 0; - if (spv_result_t error = - GetUnderlyingType(_, decoration, inst, &underlying_type)) { - return error; - } - - const Instruction* const type_inst = _.FindDef(underlying_type); - if (type_inst->opcode() != spv::Op::OpTypeArray) { - return diag(GetDefinitionDesc(decoration, inst) + " is not an array."); - } - - const uint32_t component_type = type_inst->word(2); - if (!_.IsBoolScalarType(component_type)) { - return diag(GetDefinitionDesc(decoration, inst) + - " components are not boolean scalar."); - } - - return SPV_SUCCESS; -} - spv_result_t BuiltInsValidator::ValidateI( const Decoration& decoration, const Instruction& inst, const std::function& diag) { @@ -955,45 +911,6 @@ spv_result_t BuiltInsValidator::ValidateI32Vec( return SPV_SUCCESS; } -spv_result_t BuiltInsValidator::ValidateArrayedI32Vec( - const Decoration& decoration, const Instruction& inst, - uint32_t num_components, - const std::function& diag) { - uint32_t underlying_type = 0; - if (spv_result_t error = - GetUnderlyingType(_, decoration, inst, &underlying_type)) { - return error; - } - - const Instruction* const type_inst = _.FindDef(underlying_type); - if (type_inst->opcode() != spv::Op::OpTypeArray) { - return diag(GetDefinitionDesc(decoration, inst) + " is not an array."); - } - - const uint32_t component_type = type_inst->word(2); - if (!_.IsIntVectorType(component_type)) { - return diag(GetDefinitionDesc(decoration, inst) + " is not an int vector."); - } - - const uint32_t actual_num_components = _.GetDimension(component_type); - if (_.GetDimension(component_type) != num_components) { - std::ostringstream ss; - ss << GetDefinitionDesc(decoration, inst) << " has " - << actual_num_components << " components."; - return diag(ss.str()); - } - - const uint32_t bit_width = _.GetBitWidth(component_type); - if (bit_width != 32) { - std::ostringstream ss; - ss << GetDefinitionDesc(decoration, inst) - << " has components with bit width " << bit_width << "."; - return diag(ss.str()); - } - - return SPV_SUCCESS; -} - spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32Vec( const Decoration& decoration, const Instruction& inst, uint32_t num_components, @@ -4193,147 +4110,6 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference( return SPV_SUCCESS; } -spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition( - const Decoration& decoration, const Instruction& inst) { - if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); - uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); - switch (builtin) { - case spv::BuiltIn::PrimitivePointIndicesEXT: { - if (spv_result_t error = ValidateI32Arr( - decoration, inst, - [this, &inst, &decoration, - &vuid](const std::string& message) -> spv_result_t { - return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << _.VkErrorID(vuid) << "According to the " - << spvLogStringForEnv(_.context()->target_env) - << " spec BuiltIn " - << _.grammar().lookupOperandName( - SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) - << " variable needs to be a 32-bit int array." - << message; - })) { - return error; - } - break; - } - case spv::BuiltIn::PrimitiveLineIndicesEXT: { - if (spv_result_t error = ValidateArrayedI32Vec( - decoration, inst, 2, - [this, &inst, &decoration, - &vuid](const std::string& message) -> spv_result_t { - return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << _.VkErrorID(vuid) << "According to the " - << spvLogStringForEnv(_.context()->target_env) - << " spec BuiltIn " - << _.grammar().lookupOperandName( - SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) - << " variable needs to be a 2-component 32-bit int " - "array." - << message; - })) { - return error; - } - break; - } - case spv::BuiltIn::PrimitiveTriangleIndicesEXT: { - if (spv_result_t error = ValidateArrayedI32Vec( - decoration, inst, 3, - [this, &inst, &decoration, - &vuid](const std::string& message) -> spv_result_t { - return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << _.VkErrorID(vuid) << "According to the " - << spvLogStringForEnv(_.context()->target_env) - << " spec BuiltIn " - << _.grammar().lookupOperandName( - SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) - << " variable needs to be a 3-component 32-bit int " - "array." - << message; - })) { - return error; - } - break; - } - case spv::BuiltIn::CullPrimitiveEXT: { - if (spv_result_t error = ValidateBoolArr( - decoration, inst, - [this, &inst, &decoration, - &vuid](const std::string& message) -> spv_result_t { - return _.diag(SPV_ERROR_INVALID_DATA, &inst) - << _.VkErrorID(vuid) << "According to the " - << spvLogStringForEnv(_.context()->target_env) - << " spec BuiltIn " - << _.grammar().lookupOperandName( - SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) - << " variable needs to be a boolean array." << message; - })) { - return error; - } - break; - } - default: - break; - } - } - // Seed at reference checks with this built-in. - return ValidateMeshShadingEXTBuiltinsAtReference(decoration, inst, inst, - inst); -} - -spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference( - const Decoration& decoration, const Instruction& built_in_inst, - const Instruction& referenced_inst, - const Instruction& referenced_from_inst) { - if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); - const spv::StorageClass storage_class = - GetStorageClass(referenced_from_inst); - if (storage_class != spv::StorageClass::Max && - storage_class != spv::StorageClass::Output) { - uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass); - return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) - << " spec allows BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) - << " to be only used for variables with Output storage class. " - << GetReferenceDesc(decoration, built_in_inst, referenced_inst, - referenced_from_inst) - << " " << GetStorageClassDesc(referenced_from_inst); - } - - for (const spv::ExecutionModel execution_model : execution_models_) { - if (execution_model != spv::ExecutionModel::MeshEXT) { - uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel); - return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) - << _.VkErrorID(vuid) - << spvLogStringForEnv(_.context()->target_env) - << " spec allows BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) - << " to be used only with MeshEXT execution model. " - << GetReferenceDesc(decoration, built_in_inst, referenced_inst, - referenced_from_inst, execution_model); - } - } - } - - if (function_id_ == 0) { - // Propagate this rule to all dependant ids in the global scope. - id_to_at_reference_checks_[referenced_from_inst.id()].push_back( - std::bind(&BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference, - this, decoration, built_in_inst, referenced_from_inst, - std::placeholders::_1)); - } - - return SPV_SUCCESS; -} - spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( const Decoration& decoration, const Instruction& inst) { const spv::BuiltIn label = spv::BuiltIn(decoration.params()[0]); @@ -4509,12 +4285,6 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case spv::BuiltIn::CullMaskKHR: { return ValidateRayTracingBuiltinsAtDefinition(decoration, inst); } - case spv::BuiltIn::PrimitivePointIndicesEXT: - case spv::BuiltIn::PrimitiveLineIndicesEXT: - case spv::BuiltIn::PrimitiveTriangleIndicesEXT: - case spv::BuiltIn::CullPrimitiveEXT: { - return ValidateMeshShadingEXTBuiltinsAtDefinition(decoration, inst); - } case spv::BuiltIn::PrimitiveShadingRateKHR: { return ValidatePrimitiveShadingRateAtDefinition(decoration, inst); } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 40abcfb0a3..c95eec366b 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -2165,30 +2165,6 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-Uniform-06925); case 6997: return VUID_WRAP(VUID-StandaloneSpirv-SubgroupVoteKHR-06997); - case 7034: - return VUID_WRAP(VUID-CullPrimitiveEXT-CullPrimitiveEXT-07034); - case 7035: - return VUID_WRAP(VUID-CullPrimitiveEXT-CullPrimitiveEXT-07035); - case 7036: - return VUID_WRAP(VUID-CullPrimitiveEXT-CullPrimitiveEXT-07036); - case 7041: - return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07041); - case 7043: - return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07043); - case 7044: - return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07044); - case 7047: - return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07047); - case 7049: - return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07049); - case 7050: - return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07050); - case 7053: - return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07053); - case 7055: - return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07055); - case 7056: - return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07056); case 7102: return VUID_WRAP(VUID-StandaloneSpirv-MeshEXT-07102); case 7320: diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp index 94fb794e06..4f9fc97631 100644 --- a/test/val/val_builtins_test.cpp +++ b/test/val/val_builtins_test.cpp @@ -4261,320 +4261,6 @@ INSTANTIATE_TEST_SUITE_P( Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 3-component 32-bit float vector")))); -std::string GenerateMeshShadingCode(const std::string& built_in, - const std::string& execution_mode, - const std::string& body, - const std::string& declarations = "") { - std::ostringstream ss; - ss << R"( -OpCapability MeshShadingEXT -OpExtension "SPV_EXT_mesh_shader" -OpMemoryModel Logical GLSL450 -OpEntryPoint MeshEXT %main "main" %var -OpExecutionMode %main LocalSize 1 1 1 -OpExecutionMode %main OutputVertices 1 -OpExecutionMode %main OutputPrimitivesEXT 16 -)"; - ss << "OpExecutionMode %main " << execution_mode << "\n"; - ss << "OpDecorate %var BuiltIn " << built_in << "\n"; - - ss << R"( -%void = OpTypeVoid -%func = OpTypeFunction %void -%bool = OpTypeBool -%int = OpTypeInt 32 1 -%uint = OpTypeInt 32 0 -%v2uint = OpTypeVector %uint 2 -%v3uint = OpTypeVector %uint 3 - -%int_0 = OpConstant %int 0 -%uint_16 = OpConstant %uint 16 -)"; - - ss << declarations; - - ss << R"( -%main = OpFunction %void None %func -%main_entry = OpLabel -)"; - - ss << body; - - ss << R"( -OpReturn -OpFunctionEnd)"; - return ss.str(); -} - -TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTSuccess) { - const std::string declarations = R"( -%array = OpTypeArray %v3uint %uint_16 -%array_ptr = OpTypePointer Output %array -%var = OpVariable %array_ptr Output -%ptr = OpTypePointer Output %v3uint -)"; - const std::string body = R"( -%access = OpAccessChain %ptr %var %int_0 -)"; - - CompileSuccessfully( - GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT", - "OutputTrianglesEXT", body, declarations) - .c_str(), - SPV_ENV_VULKAN_1_2); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2)); -} - -TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTStorageClass) { - const std::string declarations = R"( -%array = OpTypeArray %v3uint %uint_16 -%array_ptr = OpTypePointer Input %array -%var = OpVariable %array_ptr Input -%ptr = OpTypePointer Input %v3uint -)"; - const std::string body = R"( -%access = OpAccessChain %ptr %var %int_0 -)"; - - CompileSuccessfully( - GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT", - "OutputTrianglesEXT", body, declarations) - .c_str(), - SPV_ENV_VULKAN_1_2); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); - EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-PrimitiveTriangleIndicesEXT-" - "PrimitiveTriangleIndicesEXT-07055")); -} - -TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTVectorSize) { - const std::string declarations = R"( -%array = OpTypeArray %v2uint %uint_16 -%array_ptr = OpTypePointer Output %array -%var = OpVariable %array_ptr Output -%ptr = OpTypePointer Output %v2uint -)"; - const std::string body = R"( -%access = OpAccessChain %ptr %var %int_0 -)"; - - CompileSuccessfully( - GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT", - "OutputTrianglesEXT", body, declarations) - .c_str(), - SPV_ENV_VULKAN_1_2); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); - EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-PrimitiveTriangleIndicesEXT-" - "PrimitiveTriangleIndicesEXT-07056")); -} - -TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTNonArray) { - const std::string declarations = R"( -%ptr = OpTypePointer Output %v3uint -%var = OpVariable %ptr Output -)"; - const std::string body = R"( -%load = OpLoad %v3uint %var -)"; - - CompileSuccessfully( - GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT", - "OutputTrianglesEXT", body, declarations) - .c_str(), - SPV_ENV_VULKAN_1_2); - ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); - EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-PrimitiveTriangleIndicesEXT-" - "PrimitiveTriangleIndicesEXT-07056")); -} - -TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTSuccess) { - const std::string declarations = R"( -%array = OpTypeArray %v2uint %uint_16 -%array_ptr = OpTypePointer Output %array -%var = OpVariable %array_ptr Output -%ptr = OpTypePointer Output %v2uint -)"; - const std::string body = R"( -%access = OpAccessChain %ptr %var %int_0 -)"; - - CompileSuccessfully( - GenerateMeshShadingCode("PrimitiveLineIndicesEXT", "OutputLinesEXT", body, - declarations) - .c_str(), - SPV_ENV_VULKAN_1_2); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2)); -} - -TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTStorageClass) { - const std::string declarations = R"( -%array = OpTypeArray %v2uint %uint_16 -%array_ptr = OpTypePointer Input %array -%var = OpVariable %array_ptr Input -%ptr = OpTypePointer Input %v2uint -)"; - const std::string body = R"( -%access = OpAccessChain %ptr %var %int_0 -)"; - - CompileSuccessfully( - GenerateMeshShadingCode("PrimitiveLineIndicesEXT", "OutputLinesEXT", body, - declarations) - .c_str(), - SPV_ENV_VULKAN_1_2); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); - EXPECT_THAT( - getDiagnosticString(), - AnyVUID("VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07049")); -} - -TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTType) { - const std::string declarations = R"( -%array = OpTypeArray %v3uint %uint_16 -%array_ptr = OpTypePointer Input %array -%var = OpVariable %array_ptr Input -%ptr = OpTypePointer Input %v3uint -)"; - const std::string body = R"( -%access = OpAccessChain %ptr %var %int_0 -)"; - - CompileSuccessfully( - GenerateMeshShadingCode("PrimitiveLineIndicesEXT", "OutputLinesEXT", body, - declarations) - .c_str(), - SPV_ENV_VULKAN_1_2); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); - EXPECT_THAT( - getDiagnosticString(), - AnyVUID("VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07050")); -} - -TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTSuccess) { - const std::string declarations = R"( -%array = OpTypeArray %uint %uint_16 -%array_ptr = OpTypePointer Output %array -%var = OpVariable %array_ptr Output -%ptr = OpTypePointer Output %uint -)"; - const std::string body = R"( -%access = OpAccessChain %ptr %var %int_0 -)"; - - CompileSuccessfully( - GenerateMeshShadingCode("PrimitivePointIndicesEXT", "OutputPoints", body, - declarations) - .c_str(), - SPV_ENV_VULKAN_1_2); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2)); -} - -TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTStorageClass) { - const std::string declarations = R"( -%array = OpTypeArray %uint %uint_16 -%array_ptr = OpTypePointer Input %array -%var = OpVariable %array_ptr Input -%ptr = OpTypePointer Input %uint -)"; - const std::string body = R"( -%access = OpAccessChain %ptr %var %int_0 -)"; - - CompileSuccessfully( - GenerateMeshShadingCode("PrimitivePointIndicesEXT", "OutputPoints", body, - declarations) - .c_str(), - SPV_ENV_VULKAN_1_2); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); - EXPECT_THAT( - getDiagnosticString(), - AnyVUID("VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07043")); -} - -TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTType) { - const std::string declarations = R"( -%array = OpTypeArray %v3uint %uint_16 -%array_ptr = OpTypePointer Output %array -%var = OpVariable %array_ptr Output -%ptr = OpTypePointer Output %v3uint -)"; - const std::string body = R"( -%access = OpAccessChain %ptr %var %int_0 -)"; - - CompileSuccessfully( - GenerateMeshShadingCode("PrimitivePointIndicesEXT", "OutputPoints", body, - declarations) - .c_str(), - SPV_ENV_VULKAN_1_2); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); - EXPECT_THAT( - getDiagnosticString(), - AnyVUID("VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07044")); -} - -TEST_F(ValidateBuiltIns, VulkanCullPrimitiveEXTSuccess) { - const std::string declarations = R"( -%array = OpTypeArray %bool %uint_16 -%array_ptr = OpTypePointer Output %array -%var = OpVariable %array_ptr Output -%ptr = OpTypePointer Output %bool -)"; - const std::string body = R"( -%access = OpAccessChain %ptr %var %int_0 -)"; - - CompileSuccessfully( - GenerateMeshShadingCode("CullPrimitiveEXT", "OutputPoints", body, - declarations) - .c_str(), - SPV_ENV_VULKAN_1_2); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2)); -} - -TEST_F(ValidateBuiltIns, VulkanCullPrimitiveEXTStorageClass) { - const std::string declarations = R"( -%array = OpTypeArray %bool %uint_16 -%array_ptr = OpTypePointer Input %array -%var = OpVariable %array_ptr Input -%ptr = OpTypePointer Input %bool -)"; - const std::string body = R"( -%access = OpAccessChain %ptr %var %int_0 -)"; - - CompileSuccessfully( - GenerateMeshShadingCode("CullPrimitiveEXT", "OutputPoints", body, - declarations) - .c_str(), - SPV_ENV_VULKAN_1_2); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); - EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-CullPrimitiveEXT-CullPrimitiveEXT-07035")); -} - -TEST_F(ValidateBuiltIns, VulkanCullPrimitiveEXTType) { - const std::string declarations = R"( -%array = OpTypeArray %v3uint %uint_16 -%array_ptr = OpTypePointer Output %array -%var = OpVariable %array_ptr Output -%ptr = OpTypePointer Output %v3uint -)"; - const std::string body = R"( -%access = OpAccessChain %ptr %var %int_0 -)"; - - CompileSuccessfully( - GenerateMeshShadingCode("CullPrimitiveEXT", "OutputPoints", body, - declarations) - .c_str(), - SPV_ENV_VULKAN_1_2); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); - EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-CullPrimitiveEXT-CullPrimitiveEXT-07036")); -} } // namespace } // namespace val } // namespace spvtools From 96c5dac559fe3bd842187c057421748306cfb883 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 27 Jan 2023 02:27:32 +0000 Subject: [PATCH 028/523] Roll external/re2/ ba541565b..8afcf7fcc (1 commit) (#5085) https://github.com/google/re2/compare/ba541565b4fb...8afcf7fcc481 $ git log ba541565b..8afcf7fcc --date=short --no-merges --format='%ad %ae %s' 2023-01-25 junyer Improve support for the optional ICU dependency. 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 ab26203aa7..f1866ea2f3 100644 --- a/DEPS +++ b/DEPS @@ -12,7 +12,7 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', - 're2_revision': 'ba541565b4fbe1684d4b98695ec0b6d6c13ba98b', + 're2_revision': '8afcf7fcc481692197e33612446d69e8f5777c54', 'spirv_headers_revision': 'aa331ab0ffcb3a67021caa1a0c1c9017712f2f31', } From 64ba112ffb1fed55f1514e209db8ddbafbd7b9ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Fri, 27 Jan 2023 15:36:09 +0100 Subject: [PATCH 029/523] build: refactorize update_build_version (#5079) This commit prepares the next change to stop parsing the CHANGES file to determine version, but to use tags instead. --- utils/update_build_version.py | 120 +++++++++++++++++++--------------- 1 file changed, 69 insertions(+), 51 deletions(-) diff --git a/utils/update_build_version.py b/utils/update_build_version.py index 2a1ca60051..b1c7b21478 100755 --- a/utils/update_build_version.py +++ b/utils/update_build_version.py @@ -35,9 +35,13 @@ import os.path import re import subprocess +import logging import sys import time +# Format of the output generated by this script. Example: +# "v2023.1", "SPIRV-Tools v2023.1 0fc5526f2b01a0cc89192c10cf8bef77f1007a62, 2023-01-18T14:51:49" +OUTPUT_FORMAT = '"{version_tag}", "SPIRV-Tools {version_tag} {description}"\n' def mkdir_p(directory): """Make the directory, and all its ancestors as required. Any of the @@ -55,7 +59,6 @@ def mkdir_p(directory): else: raise - def command_output(cmd, directory): """Runs a command in a directory and returns its standard output stream. @@ -63,23 +66,29 @@ def command_output(cmd, directory): Raises a RuntimeError if the command fails to launch or otherwise fails. """ - p = subprocess.Popen(cmd, - cwd=directory, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - (stdout, _) = p.communicate() - if p.returncode != 0: - raise RuntimeError('Failed to run %s in %s' % (cmd, directory)) - return stdout - + try: + p = subprocess.Popen(cmd, + cwd=directory, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + (stdout, stderr) = p.communicate() + if p.returncode != 0: + logging.error('Failed to run "{}" in "{}": {}'.format(cmd, directory, stderr.decode())) + except Exception as e: + logging.error('Failed to run "{}" in "{}": {}'.format(cmd, directory, str(e))) + return False, None + return p.returncode == 0, stdout def deduce_software_version(changes_file): - """Returns a software version number parsed from the given CHANGES file. + """Returns a tuple (success, software version number) parsed from the + given CHANGES file. - The CHANGES file describes most recent versions first. + Success is set to True if the software version could be deduced. + Software version is undefined if success if False. + Function expects the CHANGES file to describes most recent versions first. """ - # Match the first well-formed version-and-date line. + # Match the first well-formed version-and-date line # Allow trailing whitespace in the checked-out source code has # unexpected carriage returns on a linefeed-only system such as # Linux. @@ -88,60 +97,69 @@ def deduce_software_version(changes_file): for line in f.readlines(): match = pattern.match(line) if match: - return match.group(1) - raise Exception('No version number found in {}'.format(changes_file)) + return True, match.group(1) + return False, None -def describe(directory): +def describe(repo_path): """Returns a string describing the current Git HEAD version as descriptively as possible. Runs 'git describe', or alternately 'git rev-parse HEAD', in directory. If successful, returns the output; otherwise returns 'unknown hash, '.""" - try: - # 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 command_output(['git', 'describe'], directory).rstrip().decode() - except: - try: - return command_output( - ['git', 'rev-parse', 'HEAD'], directory).rstrip().decode() - except: - # This is the fallback case where git gives us no information, - # e.g. because the source tree might not be in a git tree. - # In this case, usually use a timestamp. However, to ensure - # reproducible builds, allow the builder to override the wall - # clock time with environment variable SOURCE_DATE_EPOCH - # containing a (presumably) fixed timestamp. - timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) - formatted = datetime.datetime.utcfromtimestamp(timestamp).isoformat() - return 'unknown hash, {}'.format(formatted) + 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. + # In this case, usually use a timestamp. However, to ensure + # reproducible builds, allow the builder to override the wall + # clock time with environment variable SOURCE_DATE_EPOCH + # containing a (presumably) fixed timestamp. + timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) + iso_date = datetime.datetime.utcfromtimestamp(timestamp).isoformat() + return "unknown hash, {}".format(iso_date) def main(): + FORMAT = '%(asctime)s %(message)s' + logging.basicConfig(format="[%(asctime)s][%(levelname)-8s] %(message)s", datefmt="%H:%M:%S") if len(sys.argv) != 3: - print('usage: {} '.format(sys.argv[0])) + logging.error("usage: {} ".format(sys.argv[0])) sys.exit(1) - output_file = sys.argv[2] - mkdir_p(os.path.dirname(output_file)) + changes_file_path = os.path.realpath(sys.argv[1]) + output_file_path = sys.argv[2] + + success, version = deduce_software_version(changes_file_path) + if not success: + logging.error("Could not deduce latest release version from {}.".format(changes_file_path)) + sys.exit(1) + + repo_path = os.path.dirname(changes_file_path) + description = describe(repo_path) + content = OUTPUT_FORMAT.format(version_tag=version, description=description) - software_version = deduce_software_version(sys.argv[1]) - directory = os.path.dirname(sys.argv[1]) - new_content = '"{}", "SPIRV-Tools {} {}"\n'.format( - software_version, software_version, - describe(directory).replace('"', '\\"')) + # Escape file content. + content.replace('"', '\\"') - if os.path.isfile(output_file): - with open(output_file, 'r') as f: - if new_content == f.read(): - return + if os.path.isfile(output_file_path): + with open(output_file_path, 'r') as f: + if content == f.read(): + return - with open(output_file, 'w') as f: - f.write(new_content) + mkdir_p(os.path.dirname(output_file_path)) + with open(output_file_path, 'w') as f: + f.write(content) if __name__ == '__main__': main() From 0174dd11ff8fc2e039815e4ae9f9bc1c626beb49 Mon Sep 17 00:00:00 2001 From: Corentin Wallez Date: Mon, 30 Jan 2023 15:02:26 +0100 Subject: [PATCH 030/523] BUILD.gn: Make MSVC report the correct __cplusplus value (#5088) --- BUILD.gn | 3 +++ 1 file changed, 3 insertions(+) diff --git a/BUILD.gn b/BUILD.gn index a375e9df82..862cd9556a 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -370,6 +370,9 @@ config("spvtools_internal_config") { } else if (!is_win) { # Work around a false-positive on a Skia GCC 10 builder. cflags += [ "-Wno-format-truncation" ] + } else { + # Make MSVC report the correct value for __cplusplus + cflags += [ "/Zc:__cplusplus" ] } } From fcfc3c580c75be90a33711dd894dec58ebde9eec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 30 Jan 2023 19:23:41 +0100 Subject: [PATCH 031/523] build: stop parsing CHANGES file. (#5067) The CHANGES file was an alternative source of truth that was trying to duplicate/replace the git history truth. This allow us to change the way we handle releases so we don't have to make sure our CHANGES PR are linked to the tag and tested PR, simplifying the process. --- Android.mk | 4 +- BUILD.bazel | 6 +- BUILD.gn | 4 +- source/CMakeLists.txt | 5 +- utils/update_build_version.py | 104 +++++++++++++++++++++++----------- 5 files changed, 79 insertions(+), 44 deletions(-) diff --git a/Android.mk b/Android.mk index a4e7615fad..8a70206629 100644 --- a/Android.mk +++ b/Android.mk @@ -311,9 +311,9 @@ define gen_spvtools_build_version_inc $(call generate-file-dir,$(1)/dummy_filename) $(1)/build-version.inc: \ $(LOCAL_PATH)/utils/update_build_version.py \ - $(LOCAL_PATH)/CHANGES + $(LOCAL_PATH) @$(HOST_PYTHON) $(LOCAL_PATH)/utils/update_build_version.py \ - $(LOCAL_PATH)/CHANGES $(1)/build-version.inc + $(LOCAL_PATH) $(1)/build-version.inc @echo "[$(TARGET_ARCH_ABI)] Generate : build-version.inc <= CHANGES" $(LOCAL_PATH)/source/software_version.cpp: $(1)/build-version.inc endef diff --git a/BUILD.bazel b/BUILD.bazel index 255d4e7466..71399b2f5d 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -104,11 +104,11 @@ py_binary( genrule( name = "build_version_inc", - srcs = ["CHANGES"], outs = ["build-version.inc"], - cmd = "SOURCE_DATE_EPOCH=0 $(location :update_build_version) $(location CHANGES) $(location build-version.inc)", - cmd_bat = "set SOURCE_DATE_EPOCH=0 && $(location :update_build_version) $(location CHANGES) $(location build-version.inc)", + cmd = "SOURCE_DATE_EPOCH=0 $(location :update_build_version) $(RULEDIR) $(location build-version.inc)", + cmd_bat = "set SOURCE_DATE_EPOCH=0 && $(location :update_build_version) $(RULEDIR) $(location build-version.inc)", exec_tools = [":update_build_version"], + local = True, ) # Libraries diff --git a/BUILD.gn b/BUILD.gn index 862cd9556a..ee3743b85d 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -262,12 +262,12 @@ action("spvtools_generators_inc") { action("spvtools_build_version") { script = "utils/update_build_version.py" - changes_file = "CHANGES" + repo_path = "." inc_file = "${target_gen_dir}/build-version.inc" outputs = [ inc_file ] args = [ - rebase_path(changes_file, root_build_dir), + rebase_path(repo_path, root_build_dir), rebase_path(inc_file, root_build_dir), ] } diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index acfa0c123b..b5924f516e 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -195,14 +195,11 @@ set(SPIRV_TOOLS_BUILD_VERSION_INC ${spirv-tools_BINARY_DIR}/build-version.inc) set(SPIRV_TOOLS_BUILD_VERSION_INC_GENERATOR ${spirv-tools_SOURCE_DIR}/utils/update_build_version.py) -set(SPIRV_TOOLS_CHANGES_FILE - ${spirv-tools_SOURCE_DIR}/CHANGES) add_custom_command(OUTPUT ${SPIRV_TOOLS_BUILD_VERSION_INC} COMMAND ${PYTHON_EXECUTABLE} ${SPIRV_TOOLS_BUILD_VERSION_INC_GENERATOR} - ${SPIRV_TOOLS_CHANGES_FILE} ${SPIRV_TOOLS_BUILD_VERSION_INC} + ${spirv-tools_SOURCE_DIR} ${SPIRV_TOOLS_BUILD_VERSION_INC} DEPENDS ${SPIRV_TOOLS_BUILD_VERSION_INC_GENERATOR} - ${SPIRV_TOOLS_CHANGES_FILE} COMMENT "Update build-version.inc in the SPIRV-Tools build directory (if necessary).") # Convenience target for standalone generation of the build-version.inc file. # This is not required for any dependence chain. diff --git a/utils/update_build_version.py b/utils/update_build_version.py index b1c7b21478..1ab986248d 100755 --- a/utils/update_build_version.py +++ b/utils/update_build_version.py @@ -17,16 +17,13 @@ # Updates an output file with version info unless the new content is the same # as the existing content. # -# Args: +# Args: # # The output file will contain a line of text consisting of two C source syntax # string literals separated by a comma: -# - The software version deduced from the given CHANGES file. +# - The software version deduced from the last release tag. # - A longer string with the project name, the software version number, and -# git commit information for the CHANGES file's directory. The commit -# information is the output of "git describe" if that succeeds, or "git -# rev-parse HEAD" if that succeeds, or otherwise a message containing the -# phrase "unknown hash". +# git commit information for this release. # The string contents are escaped as necessary. import datetime @@ -39,6 +36,13 @@ import sys import time +# Regex to match the SPIR-V version tag. +# Example of matching tags: +# - v2020.1 +# - v2020.1-dev +# - v2020.1.rc1 +VERSION_REGEX = re.compile(r'^v(\d+)\.(\d+)(-dev|rc\d+)?$') + # Format of the output generated by this script. Example: # "v2023.1", "SPIRV-Tools v2023.1 0fc5526f2b01a0cc89192c10cf8bef77f1007a62, 2023-01-18T14:51:49" OUTPUT_FORMAT = '"{version_tag}", "SPIRV-Tools {version_tag} {description}"\n' @@ -79,34 +83,62 @@ def command_output(cmd, directory): return False, None return p.returncode == 0, stdout -def deduce_software_version(changes_file): - """Returns a tuple (success, software version number) parsed from the - given CHANGES file. +def deduce_last_release(repo_path): + """Returns a software version number parsed from git tags.""" - Success is set to True if the software version could be deduced. - Software version is undefined if success if False. - Function expects the CHANGES file to describes most recent versions first. - """ + success, tag_list = command_output(['git', 'tag', '--sort=-v:refname'], repo_path) + if not success: + return False, None + + latest_version_tag = None + for tag in tag_list.decode().splitlines(): + if VERSION_REGEX.match(tag): + latest_version_tag = tag + break + + if latest_version_tag is None: + logging.error("No tag matching version regex matching.") + return False, None + return True, latest_version_tag + +def get_last_release_tuple(repo_path): + success, version = deduce_last_release(repo_path) + if not success: + return False, None - # Match the first well-formed version-and-date line - # Allow trailing whitespace in the checked-out source code has - # unexpected carriage returns on a linefeed-only system such as - # Linux. - pattern = re.compile(r'^(v\d+\.\d+(-dev)?) \d\d\d\d-\d\d-\d\d\s*$') - with open(changes_file, mode='r') as f: - for line in f.readlines(): - match = pattern.match(line) - if match: - return True, match.group(1) + m = VERSION_REGEX.match(version) + if len(m.groups()) != 3: return False, None + return True, (int(m.groups()[0]), int(m.groups()[1])) +def deduce_current_release(repo_path): + status, version_tuple = get_last_release_tuple(repo_path) + if not status: + return False, None -def describe(repo_path): - """Returns a string describing the current Git HEAD version as descriptively - as possible. + last_release_tag = "v{}.{}-dev".format(*version_tuple) + success, tag_list = command_output(['git', 'tag', '--contains'], repo_path) + if success: + if last_release_tag in set(tag_list.decode().splitlines()): + return True, last_release_tag + else: + logging.warning("Could not check tags for commit. Assuming -dev version.") - Runs 'git describe', or alternately 'git rev-parse HEAD', in directory. If - successful, returns the output; otherwise returns 'unknown hash, '.""" + now_year = datetime.datetime.now().year + if version_tuple[0] == now_year: + version_tuple = (now_year, version_tuple[1] + 1) + else: + version_tuple = (now_year, 1) + + return True, "v{}.{}-dev".format(*version_tuple) + +def get_description_for_head(repo_path): + """Returns a string describing the current Git HEAD version as descriptively + as possible, in order of priority: + - git describe output + - git rev-parse HEAD output + - "unknown-hash, " + """ success, output = command_output(['git', 'describe'], repo_path) if not success: @@ -130,6 +162,13 @@ def describe(repo_path): iso_date = datetime.datetime.utcfromtimestamp(timestamp).isoformat() return "unknown hash, {}".format(iso_date) +def is_folder_git_repo(path): + try: + success, _ = command_output(['git', 'branch'], path) + except NotADirectoryError as e: + return False + return success + def main(): FORMAT = '%(asctime)s %(message)s' logging.basicConfig(format="[%(asctime)s][%(levelname)-8s] %(message)s", datefmt="%H:%M:%S") @@ -137,16 +176,15 @@ def main(): logging.error("usage: {} ".format(sys.argv[0])) sys.exit(1) - changes_file_path = os.path.realpath(sys.argv[1]) + repo_path = os.path.realpath(sys.argv[1]) output_file_path = sys.argv[2] - success, version = deduce_software_version(changes_file_path) + success, version = deduce_current_release(repo_path) if not success: - logging.error("Could not deduce latest release version from {}.".format(changes_file_path)) + logging.error("Could not deduce latest release version.") sys.exit(1) - repo_path = os.path.dirname(changes_file_path) - description = describe(repo_path) + description = get_description_for_head(repo_path) content = OUTPUT_FORMAT.format(version_tag=version, description=description) # Escape file content. From b230a7c7d1eb02d59c1d6015a8da00703ca413e1 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Tue, 31 Jan 2023 15:40:22 -0500 Subject: [PATCH 032/523] Validate operand type before operating on it (#5092) Fixes https://crbug.com/oss-fuzz/52921 * Validate the data operand of OpBitCount before trying to get its dimension --- source/val/validate_bitwise.cpp | 5 +++-- test/val/val_bitwise_test.cpp | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/source/val/validate_bitwise.cpp b/source/val/validate_bitwise.cpp index 87c955630f..6ab1faebc3 100644 --- a/source/val/validate_bitwise.cpp +++ b/source/val/validate_bitwise.cpp @@ -206,13 +206,14 @@ spv_result_t BitwisePass(ValidationState_t& _, const Instruction* inst) { << spvOpcodeString(opcode); const uint32_t base_type = _.GetOperandTypeId(inst, 2); - const uint32_t base_dimension = _.GetDimension(base_type); - const uint32_t result_dimension = _.GetDimension(result_type); if (spv_result_t error = ValidateBaseType(_, inst, base_type)) { return error; } + const uint32_t base_dimension = _.GetDimension(base_type); + const uint32_t result_dimension = _.GetDimension(result_type); + if (base_dimension != result_dimension) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Base dimension to be equal to Result Type " diff --git a/test/val/val_bitwise_test.cpp b/test/val/val_bitwise_test.cpp index bebaa84fc2..b849e7b778 100644 --- a/test/val/val_bitwise_test.cpp +++ b/test/val/val_bitwise_test.cpp @@ -643,6 +643,32 @@ TEST_F(ValidateBitwise, OpBitCountNot32Vulkan) { HasSubstr("Expected 32-bit int type for Base operand: BitCount")); } +TEST_F(ValidateBitwise, OpBitCountPointer) { + const std::string body = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr_int = OpTypePointer Function %int +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%var = OpVariable %ptr_int Function +%count = OpBitCount %int %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Expected int scalar or vector type for Base operand: BitCount")); +} + } // namespace } // namespace val } // namespace spvtools From 8a0fe779e5da0042c9b72876edc8b7187ab7ab6a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 31 Jan 2023 21:54:27 +0000 Subject: [PATCH 033/523] Roll external/re2/ 8afcf7fcc..b025c6a3a (1 commit) (#5091) https://github.com/google/re2/compare/8afcf7fcc481...b025c6a3ae05 $ git log 8afcf7fcc..b025c6a3a --date=short --no-merges --format='%ad %ae %s' 2023-01-30 raj.khem Use plain int type instead of int32_t 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 f1866ea2f3..64e63e84e6 100644 --- a/DEPS +++ b/DEPS @@ -12,7 +12,7 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', - 're2_revision': '8afcf7fcc481692197e33612446d69e8f5777c54', + 're2_revision': 'b025c6a3ae05995660e3b882eb3277f4399ced1a', 'spirv_headers_revision': 'aa331ab0ffcb3a67021caa1a0c1c9017712f2f31', } From 0994ca45b663296d733e89c5d89dbd4347e065c1 Mon Sep 17 00:00:00 2001 From: Daniel Story <120753126+daniel-story@users.noreply.github.com> Date: Wed, 1 Feb 2023 05:58:52 -0800 Subject: [PATCH 034/523] Add C interface for Optimizer (#5030) --- include/spirv-tools/libspirv.h | 59 ++++ source/opt/optimizer.cpp | 92 ++++++ test/opt/CMakeLists.txt | 1 + test/opt/c_interface_test.cpp | 534 +++++++++++++++++++++++++++++++++ utils/check_copyright.py | 5 +- 5 files changed, 689 insertions(+), 2 deletions(-) create mode 100644 test/opt/c_interface_test.cpp diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index b549efbada..84a7726e78 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -441,6 +441,8 @@ typedef struct spv_reducer_options_t spv_reducer_options_t; typedef struct spv_fuzzer_options_t spv_fuzzer_options_t; +typedef struct spv_optimizer_t spv_optimizer_t; + // Type Definitions typedef spv_const_binary_t* spv_const_binary; @@ -900,6 +902,63 @@ SPIRV_TOOLS_EXPORT spv_result_t spvBinaryParse( const size_t num_words, spv_parsed_header_fn_t parse_header, spv_parsed_instruction_fn_t parse_instruction, spv_diagnostic* diagnostic); +// The optimizer interface. + +// A pointer to a function that accepts a log message from an optimizer. +typedef void (*spv_message_consumer)( + spv_message_level_t, const char*, const spv_position_t*, const char*); + +// Creates and returns an optimizer object. This object must be passed to +// optimizer APIs below and is valid until passed to spvOptimizerDestroy. +SPIRV_TOOLS_EXPORT spv_optimizer_t* spvOptimizerCreate(spv_target_env env); + +// Destroys the given optimizer object. +SPIRV_TOOLS_EXPORT void spvOptimizerDestroy(spv_optimizer_t* optimizer); + +// Sets an spv_message_consumer on an optimizer object. +SPIRV_TOOLS_EXPORT void spvOptimizerSetMessageConsumer( + spv_optimizer_t* optimizer, spv_message_consumer consumer); + +// Registers passes that attempt to legalize the generated code. +SPIRV_TOOLS_EXPORT void spvOptimizerRegisterLegalizationPasses( + spv_optimizer_t* optimizer); + +// Registers passes that attempt to improve performance of generated code. +SPIRV_TOOLS_EXPORT void spvOptimizerRegisterPerformancePasses( + spv_optimizer_t* optimizer); + +// Registers passes that attempt to improve the size of generated code. +SPIRV_TOOLS_EXPORT void spvOptimizerRegisterSizePasses( + spv_optimizer_t* optimizer); + +// Registers a pass specified by a flag in an optimizer object. +SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassFromFlag( + spv_optimizer_t* optimizer, const char* flag); + +// Registers passes specified by length number of flags in an optimizer object. +SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassesFromFlags( + spv_optimizer_t* optimizer, const char** flags, const size_t flag_count); + +// Optimizes the SPIR-V code of size |word_count| pointed to by |binary| and +// returns an optimized spv_binary in |optimized_binary|. +// +// Returns SPV_SUCCESS on successful optimization, whether or not the module is +// modified. Returns an SPV_ERROR_* if the module fails to validate or if +// errors occur when processing using any of the registered passes. In that +// case, no further passes are executed and the |optimized_binary| contents may +// be invalid. +// +// By default, the binary is validated before any transforms are performed, +// and optionally after each transform. Validation uses SPIR-V spec rules +// for the SPIR-V version named in the binary's header (at word offset 1). +// Additionally, if the target environment is a client API (such as +// Vulkan 1.1), then validate for that client API version, to the extent +// that it is verifiable from data in the binary itself, or from the +// validator options set on the optimizer options. +SPIRV_TOOLS_EXPORT spv_result_t spvOptimizerRun( + spv_optimizer_t* optimizer, const uint32_t* binary, const size_t word_count, + spv_binary* optimized_binary, const spv_optimizer_options options); + #ifdef __cplusplus } #endif diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index be0daebda8..cbc4b82f77 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -1065,3 +1065,95 @@ Optimizer::PassToken CreateFixFuncCallArgumentsPass() { MakeUnique()); } } // namespace spvtools + +extern "C" { + +SPIRV_TOOLS_EXPORT spv_optimizer_t* spvOptimizerCreate(spv_target_env env) { + return reinterpret_cast(new spvtools::Optimizer(env)); +} + +SPIRV_TOOLS_EXPORT void spvOptimizerDestroy(spv_optimizer_t* optimizer) { + delete reinterpret_cast(optimizer); +} + +SPIRV_TOOLS_EXPORT void spvOptimizerSetMessageConsumer( + spv_optimizer_t* optimizer, spv_message_consumer consumer) { + reinterpret_cast(optimizer)-> + SetMessageConsumer( + [consumer](spv_message_level_t level, const char* source, + const spv_position_t& position, const char* message) { + return consumer(level, source, &position, message); + }); +} + +SPIRV_TOOLS_EXPORT void spvOptimizerRegisterLegalizationPasses( + spv_optimizer_t* optimizer) { + reinterpret_cast(optimizer)-> + RegisterLegalizationPasses(); +} + +SPIRV_TOOLS_EXPORT void spvOptimizerRegisterPerformancePasses( + spv_optimizer_t* optimizer) { + reinterpret_cast(optimizer)-> + RegisterPerformancePasses(); +} + +SPIRV_TOOLS_EXPORT void spvOptimizerRegisterSizePasses( + spv_optimizer_t* optimizer) { + reinterpret_cast(optimizer)->RegisterSizePasses(); +} + +SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassFromFlag( + spv_optimizer_t* optimizer, const char* flag) +{ + return reinterpret_cast(optimizer)-> + RegisterPassFromFlag(flag); +} + +SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassesFromFlags( + spv_optimizer_t* optimizer, const char** flags, const size_t flag_count) { + std::vector opt_flags; + for (uint32_t i = 0; i < flag_count; i++) { + opt_flags.emplace_back(flags[i]); + } + + return reinterpret_cast(optimizer)-> + RegisterPassesFromFlags(opt_flags); +} + +SPIRV_TOOLS_EXPORT +spv_result_t spvOptimizerRun(spv_optimizer_t* optimizer, + const uint32_t* binary, + const size_t word_count, + spv_binary* optimized_binary, + const spv_optimizer_options options) { + std::vector optimized; + + if (!reinterpret_cast(optimizer)-> + Run(binary, word_count, &optimized, options)) { + return SPV_ERROR_INTERNAL; + } + + auto result_binary = new spv_binary_t(); + if (!result_binary) { + *optimized_binary = nullptr; + return SPV_ERROR_OUT_OF_MEMORY; + } + + result_binary->code = new uint32_t[optimized.size()]; + if (!result_binary->code) { + delete result_binary; + *optimized_binary = nullptr; + return SPV_ERROR_OUT_OF_MEMORY; + } + result_binary->wordCount = optimized.size(); + + memcpy(result_binary->code, optimized.data(), + optimized.size() * sizeof(uint32_t)); + + *optimized_binary = result_binary; + + return SPV_SUCCESS; +} + +} // extern "C" diff --git a/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt index af24e6599c..3b2d3844eb 100644 --- a/test/opt/CMakeLists.txt +++ b/test/opt/CMakeLists.txt @@ -21,6 +21,7 @@ add_spvtools_unittest(TARGET opt analyze_live_input_test.cpp assembly_builder_test.cpp block_merge_test.cpp + c_interface_test.cpp ccp_test.cpp cfg_cleanup_test.cpp cfg_test.cpp diff --git a/test/opt/c_interface_test.cpp b/test/opt/c_interface_test.cpp new file mode 100644 index 0000000000..a1725255ce --- /dev/null +++ b/test/opt/c_interface_test.cpp @@ -0,0 +1,534 @@ +// Copyright (c) 2023 Nintendo +// +// 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 +#include + +#include "gtest/gtest.h" +#include "spirv-tools/libspirv.h" + +namespace spvtools { +namespace { + +TEST(OptimizerCInterface, DefaultConsumerWithValidationNoPassesForInvalidInput) { + const uint32_t spirv[] = { + 0xDEADFEED, // Invalid Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x01000000, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001 // GLSL450 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + // Do not register any passes + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, true); + + spv_binary binary = nullptr; + EXPECT_NE(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_EQ(binary, nullptr); + + spvOptimizerOptionsDestroy(options); + + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, SpecifyConsumerWithValidationNoPassesForInvalidInput) { + const uint32_t spirv[] = { + 0xDEADFEED, // Invalid Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x01000000, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001 // GLSL450 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + spvOptimizerSetMessageConsumer( + optimizer, + [](spv_message_level_t, const char*, const spv_position_t*, + const char* message) { + std::cout << message << std::endl; + }); + + // Do not register any passes + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, true); + + testing::internal::CaptureStdout(); + + spv_binary binary = nullptr; + EXPECT_NE(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_EQ(binary, nullptr); + + auto output = testing::internal::GetCapturedStdout(); + EXPECT_STRNE(output.c_str(), ""); + + spvOptimizerOptionsDestroy(options); + + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerWithValidationNoPassesForValidInput) { + const uint32_t spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000001, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001 // GLSL450 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + // Do not register any passes + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, true); + + spv_binary binary = nullptr; + EXPECT_EQ(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_NE(binary, nullptr); + + spvOptimizerOptionsDestroy(options); + + // Should remain unchanged + EXPECT_EQ(binary->wordCount, sizeof(spirv) / sizeof(uint32_t)); + EXPECT_EQ(memcmp(binary->code, spirv, sizeof(spirv) / sizeof(uint32_t)), 0); + + spvBinaryDestroy(binary); + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerNoPassesForValidInput) { + const uint32_t spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000003, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001, // GLSL450 + 0x00040015, // OpTypeInt + 0x00000001, // %1 + 0x00000020, // 32 Bits + 0x00000000, // Unsigned + 0x0004002B, // OpConstant + 0x00000001, // %1 + 0x00000002, // %2 + 0x00000001 // 1 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + // Do not register any passes + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, true); + + spv_binary binary = nullptr; + EXPECT_EQ(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_NE(binary, nullptr); + + spvOptimizerOptionsDestroy(options); + + // Should remain unchanged + EXPECT_EQ(binary->wordCount, sizeof(spirv) / sizeof(uint32_t)); + EXPECT_EQ(memcmp(binary->code, spirv, sizeof(spirv) / sizeof(uint32_t)), 0); + + spvBinaryDestroy(binary); + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerLegalizationPassesForValidInput) { + const uint32_t spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000003, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001, // GLSL450 + 0x00040015, // OpTypeInt + 0x00000001, // %1 + 0x00000020, // 32 Bits + 0x00000000, // Unsigned + 0x0004002B, // OpConstant + 0x00000001, // %1 + 0x00000002, // %2 + 0x00000001 // 1 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + spvOptimizerRegisterLegalizationPasses(optimizer); + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, false); + + spv_binary binary = nullptr; + EXPECT_EQ(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_NE(binary, nullptr); + + spvOptimizerOptionsDestroy(options); + + // Only check that SPV_SUCCESS is returned, do not verify output + + spvBinaryDestroy(binary); + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerPerformancePassesForValidInput) { + const uint32_t spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000003, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001, // GLSL450 + 0x00040015, // OpTypeInt + 0x00000001, // %1 + 0x00000020, // 32 Bits + 0x00000000, // Unsigned + 0x0004002B, // OpConstant + 0x00000001, // %1 + 0x00000002, // %2 + 0x00000001 // 1 + }; + const uint32_t expected_spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000001, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001 // GLSL450 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + spvOptimizerRegisterPerformancePasses(optimizer); + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, false); + + spv_binary binary = nullptr; + EXPECT_EQ(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_NE(binary, nullptr); + + spvOptimizerOptionsDestroy(options); + + // Unreferenced OpTypeInt and OpConstant should be removed + EXPECT_EQ(binary->wordCount, sizeof(expected_spirv) / sizeof(uint32_t)); + EXPECT_EQ(memcmp(binary->code, expected_spirv, + sizeof(expected_spirv) / sizeof(uint32_t)), 0); + + spvBinaryDestroy(binary); + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerSizePassesForValidInput) { + const uint32_t spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000003, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001, // GLSL450 + 0x00040015, // OpTypeInt + 0x00000001, // %1 + 0x00000020, // 32 Bits + 0x00000000, // Unsigned + 0x0004002B, // OpConstant + 0x00000001, // %1 + 0x00000002, // %2 + 0x00000001 // 1 + }; + const uint32_t expected_spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000001, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001 // GLSL450 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + spvOptimizerRegisterSizePasses(optimizer); + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, false); + + spv_binary binary = nullptr; + EXPECT_EQ(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_NE(binary, nullptr); + + spvOptimizerOptionsDestroy(options); + + // Unreferenced OpTypeInt and OpConstant should be removed + EXPECT_EQ(binary->wordCount, sizeof(expected_spirv) / sizeof(uint32_t)); + EXPECT_EQ(memcmp(binary->code, expected_spirv, + sizeof(expected_spirv) / sizeof(uint32_t)), 0); + + spvBinaryDestroy(binary); + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerPassFromFlagForValidInput) { + const uint32_t spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000003, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001, // GLSL450 + 0x00040015, // OpTypeInt + 0x00000001, // %1 + 0x00000020, // 32 Bits + 0x00000000, // Unsigned + 0x0004002B, // OpConstant + 0x00000001, // %1 + 0x00000002, // %2 + 0x00000001 // 1 + }; + const uint32_t expected_spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000001, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001 // GLSL450 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + EXPECT_TRUE(spvOptimizerRegisterPassFromFlag( + optimizer, "--eliminate-dead-code-aggressive")); + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, false); + + spv_binary binary = nullptr; + EXPECT_EQ(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_NE(binary, nullptr); + + spvOptimizerOptionsDestroy(options); + + // Unreferenced OpTypeInt and OpConstant should be removed + EXPECT_EQ(binary->wordCount, sizeof(expected_spirv) / sizeof(uint32_t)); + EXPECT_EQ(memcmp(binary->code, expected_spirv, + sizeof(expected_spirv) / sizeof(uint32_t)), 0); + + spvBinaryDestroy(binary); + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerPassesFromFlagsForValidInput) { + const uint32_t spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000003, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001, // GLSL450 + 0x00040015, // OpTypeInt + 0x00000001, // %1 + 0x00000020, // 32 Bits + 0x00000000, // Unsigned + 0x0004002B, // OpConstant + 0x00000001, // %1 + 0x00000002, // %2 + 0x00000001 // 1 + }; + const uint32_t expected_spirv[] = { + 0x07230203, // Magic + 0x00010100, // Version 1.1 + 0x00000000, // No Generator + 0x00000001, // Bound + 0x00000000, // Schema + 0x00020011, // OpCapability + 0x00000001, // Shader + 0x00020011, // OpCapability + 0x00000005, // Linkage + 0x0003000E, // OpMemoryModel + 0x00000000, // Logical + 0x00000001 // GLSL450 + }; + + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + const char* flags[2] = { + "--eliminate-dead-const", + "--eliminate-dead-code-aggressive" + }; + + EXPECT_TRUE(spvOptimizerRegisterPassesFromFlags( + optimizer, flags, sizeof(flags) / sizeof(const char*))); + + auto options = spvOptimizerOptionsCreate(); + ASSERT_NE(options, nullptr); + spvOptimizerOptionsSetRunValidator(options, false); + + spv_binary binary = nullptr; + EXPECT_EQ(SPV_SUCCESS, + spvOptimizerRun(optimizer, spirv, sizeof(spirv) / sizeof(uint32_t), + &binary, options)); + ASSERT_NE(binary, nullptr); + + spvOptimizerOptionsDestroy(options); + + // Unreferenced OpTypeInt and OpConstant should be removed + EXPECT_EQ(binary->wordCount, sizeof(expected_spirv) / sizeof(uint32_t)); + EXPECT_EQ(memcmp(binary->code, expected_spirv, + sizeof(expected_spirv) / sizeof(uint32_t)), 0); + + spvBinaryDestroy(binary); + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerInvalidPassFromFlag) { + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + EXPECT_FALSE(spvOptimizerRegisterPassFromFlag( + optimizer, "--this-is-not-a-valid-pass")); + + spvOptimizerDestroy(optimizer); +} + +TEST(OptimizerCInterface, DefaultConsumerInvalidPassesFromFlags) { + auto optimizer = spvOptimizerCreate(SPV_ENV_UNIVERSAL_1_1); + ASSERT_NE(optimizer, nullptr); + + const char* flags[2] = { + "--eliminate-dead-const", + "--this-is-not-a-valid-pass" + }; + + EXPECT_FALSE(spvOptimizerRegisterPassesFromFlags( + optimizer, flags, sizeof(flags) / sizeof(const char*))); + + spvOptimizerDestroy(optimizer); +} + +} // namespace +} // namespace spvtools diff --git a/utils/check_copyright.py b/utils/check_copyright.py index aa647af58b..e3e74bc9d2 100755 --- a/utils/check_copyright.py +++ b/utils/check_copyright.py @@ -41,8 +41,9 @@ 'Alastair F. Donaldson', 'Mostafa Ashraf', 'Shiyu Liu', - 'ZHOU He'] -CURRENT_YEAR = 2022 + 'ZHOU He', + 'Nintendo'] +CURRENT_YEAR = 2023 FIRST_YEAR = 2014 FINAL_YEAR = CURRENT_YEAR + 5 From 1a49b52188e001c951a512004de0a36095e36880 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 1 Feb 2023 18:45:42 +0000 Subject: [PATCH 035/523] Remove vs2017 no longer being run (#5095) --- kokoro/windows-msvc-2017-debug/build.bat | 23 -------- kokoro/windows-msvc-2017-debug/continuous.cfg | 22 ------- kokoro/windows-msvc-2017-debug/presubmit.cfg | 16 ------ .../windows-msvc-2017-release-bazel/build.bat | 57 ------------------- .../continuous.cfg | 16 ------ .../presubmit.cfg | 16 ------ 6 files changed, 150 deletions(-) delete mode 100644 kokoro/windows-msvc-2017-debug/build.bat delete mode 100644 kokoro/windows-msvc-2017-debug/continuous.cfg delete mode 100644 kokoro/windows-msvc-2017-debug/presubmit.cfg delete mode 100644 kokoro/windows-msvc-2017-release-bazel/build.bat delete mode 100644 kokoro/windows-msvc-2017-release-bazel/continuous.cfg delete mode 100644 kokoro/windows-msvc-2017-release-bazel/presubmit.cfg diff --git a/kokoro/windows-msvc-2017-debug/build.bat b/kokoro/windows-msvc-2017-debug/build.bat deleted file mode 100644 index 25783a9e58..0000000000 --- a/kokoro/windows-msvc-2017-debug/build.bat +++ /dev/null @@ -1,23 +0,0 @@ -:: Copyright (c) 2018 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. -:: -:: Windows Build Script. - -@echo on - -:: Find out the directory of the common build script. -set SCRIPT_DIR=%~dp0 - -:: Call with correct parameter -call %SCRIPT_DIR%\..\scripts\windows\build.bat Debug 2017 diff --git a/kokoro/windows-msvc-2017-debug/continuous.cfg b/kokoro/windows-msvc-2017-debug/continuous.cfg deleted file mode 100644 index 25c5e113de..0000000000 --- a/kokoro/windows-msvc-2017-debug/continuous.cfg +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright (c) 2018 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. - -# Continuous build configuration. -build_file: "SPIRV-Tools/kokoro/windows-msvc-2017-debug/build.bat" - -action { - define_artifacts { - regex: "install.zip" - } -} diff --git a/kokoro/windows-msvc-2017-debug/presubmit.cfg b/kokoro/windows-msvc-2017-debug/presubmit.cfg deleted file mode 100644 index a7a553aee9..0000000000 --- a/kokoro/windows-msvc-2017-debug/presubmit.cfg +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2018 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. - -# Presubmit build configuration. -build_file: "SPIRV-Tools/kokoro/windows-msvc-2017-debug/build.bat" diff --git a/kokoro/windows-msvc-2017-release-bazel/build.bat b/kokoro/windows-msvc-2017-release-bazel/build.bat deleted file mode 100644 index c1945e25a3..0000000000 --- a/kokoro/windows-msvc-2017-release-bazel/build.bat +++ /dev/null @@ -1,57 +0,0 @@ -:: Copyright (c) 2019 Google LLC. -:: -:: Licensed under the Apache License, Version 2.0 (the "License"); -:: you may not use this file except in compliance with the License. -:: You may obtain a copy of the License at -:: -:: http://www.apache.org/licenses/LICENSE-2.0 -:: -:: Unless required by applicable law or agreed to in writing, software -:: distributed under the License is distributed on an "AS IS" BASIS, -:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -:: See the License for the specific language governing permissions and -:: limitations under the License. -:: -:: Windows Build Script. - -@echo on - -set SRC=%cd%\github\SPIRV-Tools - -:: Force usage of python 3.6 -set PATH=C:\python36;%PATH% - -:: Get dependencies -cd %SRC% -git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers -git clone https://github.com/google/googletest external/googletest -cd external && cd googletest && git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7 && cd .. && cd .. -git clone --depth=1 https://github.com/google/effcee external/effcee -git clone --depth=1 https://github.com/google/re2 external/re2 - -:: REM Install Bazel. -wget -q https://github.com/bazelbuild/bazel/releases/download/5.0.0/bazel-5.0.0-windows-x86_64.zip -unzip -q bazel-5.0.0-windows-x86_64.zip - -:: Set up MSVC -call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 -set BAZEL_VC=C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC - -:: ######################################### -:: Start building. -:: ######################################### -echo "Build everything... %DATE% %TIME%" -bazel.exe build :all -if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% -echo "Build Completed %DATE% %TIME%" - -:: ############## -:: Run the tests -:: ############## -echo "Running Tests... %DATE% %TIME%" -bazel.exe test :all -if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% -echo "Tests Completed %DATE% %TIME%" - -exit /b 0 - diff --git a/kokoro/windows-msvc-2017-release-bazel/continuous.cfg b/kokoro/windows-msvc-2017-release-bazel/continuous.cfg deleted file mode 100644 index f2387a6889..0000000000 --- a/kokoro/windows-msvc-2017-release-bazel/continuous.cfg +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2019 Google LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Continuous build configuration. -build_file: "SPIRV-Tools/kokoro/windows-msvc-2017-release-bazel/build.bat" diff --git a/kokoro/windows-msvc-2017-release-bazel/presubmit.cfg b/kokoro/windows-msvc-2017-release-bazel/presubmit.cfg deleted file mode 100644 index 13394b4100..0000000000 --- a/kokoro/windows-msvc-2017-release-bazel/presubmit.cfg +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2019 Google LLC. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Presubmit build configuration. -build_file: "SPIRV-Tools/kokoro/windows-msvc-2017-release-bazel/build.bat" From d8759a140bc65811332d5f91f3b08febadd5a21d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 2 Feb 2023 15:05:02 +0100 Subject: [PATCH 036/523] build: fix bazel build for c++17 (#5097) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit changes the way bazel chooses which version to build. Before, we had a COPT set to -std=c++17, which is analogous to the cmake way. However, googletest decided to follow abseil, meaning this is *not* recommended at all, and causes a mixed-standard build. From https://github.com/abseil/abseil-cpp/blob/master/FAQ.md#how-to-i-set-the-c-dialect-used-to-build-abseil we have 3 options to define the standard. Using a bazelrc is what I believe to be the simplest, as it "fixes" the repo standard. Signed-off-by: Nathan Gauër --- .bazelrc | 1 + .bazelversion | 2 +- DEPS | 4 +--- build_defs.bzl | 3 --- utils/roll_deps.sh | 2 +- 5 files changed, 4 insertions(+), 8 deletions(-) create mode 100644 .bazelrc diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 0000000000..5b3d13f534 --- /dev/null +++ b/.bazelrc @@ -0,0 +1 @@ +build --cxxopt=-std=c++17 diff --git a/.bazelversion b/.bazelversion index 28cbf7c0aa..0062ac9718 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -5.0.0 \ No newline at end of file +5.0.0 diff --git a/DEPS b/DEPS index 64e63e84e6..8a013549a3 100644 --- a/DEPS +++ b/DEPS @@ -5,9 +5,7 @@ vars = { 'effcee_revision': 'c7b4db79f340f7a9981e8a484f6d5785e24242d1', - # Pin to the last version of googletest that supports C++11. - # Anything later requires C++14 - 'googletest_revision': 'v1.12.0', + 'googletest_revision': 'ebedaa18c7cafa15f06ab3d814440e510fad9559', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', diff --git a/build_defs.bzl b/build_defs.bzl index 3a69de5c7b..4d6f15cb22 100644 --- a/build_defs.bzl +++ b/build_defs.bzl @@ -4,13 +4,10 @@ COMMON_COPTS = [ "-DSPIRV_CHECK_CONTEXT", "-DSPIRV_COLOR_TERMINAL", ] + select({ - # On Windows, assume MSVC. - # C++14 is the default in VisualStudio 2017. "@platforms//os:windows": [], "//conditions:default": [ "-DSPIRV_LINUX", "-DSPIRV_TIMER_ENABLED", - "-std=c++11", "-fvisibility=hidden", "-fno-exceptions", "-fno-rtti", diff --git a/utils/roll_deps.sh b/utils/roll_deps.sh index bf6d6930ea..6289c94e40 100755 --- a/utils/roll_deps.sh +++ b/utils/roll_deps.sh @@ -31,7 +31,7 @@ function ExitIfIsInterestingError() { # We are not rolling google test for now. The latest version requires C++14. dependencies=("external/effcee/" -# "external/googletest/") + "external/googletest/" "external/re2/" "external/spirv-headers/") From 5890763734c43ce50c66da8df80b79e07122b546 Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Thu, 2 Feb 2023 17:39:09 -0700 Subject: [PATCH 037/523] instrument: Clean up generation code (#5090) -Make more use of InstructionBuilder instruction helper methods -Use MakeUnique<>() rather than new -Add InstrumentPass::GenReadFunctionCall() which optimizes function calls in a loop with constant arguments and no side effects. This is a prepatory change for future work on the instrumentation code which will add more generated functions. --- source/opt/inst_bindless_check_pass.cpp | 7 +- source/opt/inst_buff_addr_check_pass.cpp | 29 +- source/opt/inst_debug_printf_pass.cpp | 9 +- source/opt/instrument_pass.cpp | 357 ++++++++++++----------- source/opt/instrument_pass.h | 31 +- test/opt/inst_bindless_check_test.cpp | 119 +------- test/opt/inst_buff_addr_check_test.cpp | 4 +- test/opt/inst_debug_printf_test.cpp | 4 +- 8 files changed, 247 insertions(+), 313 deletions(-) diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp index ad581e14c9..cd712f068e 100644 --- a/source/opt/inst_bindless_check_pass.cpp +++ b/source/opt/inst_bindless_check_pass.cpp @@ -497,8 +497,8 @@ uint32_t InstBindlessCheckPass::GenLastByteIdx(RefAnalysis* ref, if (sum_id == 0) sum_id = curr_offset_id; else { - Instruction* sum_inst = builder->AddBinaryOp(GetUintId(), spv::Op::OpIAdd, - sum_id, curr_offset_id); + Instruction* sum_inst = + builder->AddIAdd(GetUintId(), sum_id, curr_offset_id); sum_id = sum_inst->result_id(); } ++ac_in_idx; @@ -507,8 +507,7 @@ uint32_t InstBindlessCheckPass::GenLastByteIdx(RefAnalysis* ref, uint32_t bsize = ByteSize(curr_ty_id, matrix_stride, col_major, in_matrix); uint32_t last = bsize - 1; uint32_t last_id = builder->GetUintConstantId(last); - Instruction* sum_inst = - builder->AddBinaryOp(GetUintId(), spv::Op::OpIAdd, sum_id, last_id); + Instruction* sum_inst = builder->AddIAdd(GetUintId(), sum_id, last_id); return sum_inst->result_id(); } diff --git a/source/opt/inst_buff_addr_check_pass.cpp b/source/opt/inst_buff_addr_check_pass.cpp index 97d25f3c99..c18f91d7fd 100644 --- a/source/opt/inst_buff_addr_check_pass.cpp +++ b/source/opt/inst_buff_addr_check_pass.cpp @@ -257,9 +257,7 @@ uint32_t InstBuffAddrCheckPass::GetSearchAndTestFuncId() { uint32_t hdr_blk_id = TakeNextId(); // Branch to search loop header std::unique_ptr hdr_blk_label(NewLabel(hdr_blk_id)); - (void)builder.AddInstruction(MakeUnique( - context(), spv::Op::OpBranch, 0, 0, - std::initializer_list{{SPV_OPERAND_TYPE_ID, {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 @@ -293,17 +291,10 @@ uint32_t InstBuffAddrCheckPass::GetSearchAndTestFuncId() { uint32_t bound_test_blk_id = TakeNextId(); std::unique_ptr bound_test_blk_label( NewLabel(bound_test_blk_id)); - (void)builder.AddInstruction(MakeUnique( - context(), spv::Op::OpLoopMerge, 0, 0, - std::initializer_list{ - {SPV_OPERAND_TYPE_ID, {bound_test_blk_id}}, - {SPV_OPERAND_TYPE_ID, {cont_blk_id}}, - {SPV_OPERAND_TYPE_LITERAL_INTEGER, - {uint32_t(spv::LoopControlMask::MaskNone)}}})); + (void)builder.AddLoopMerge(bound_test_blk_id, cont_blk_id, + uint32_t(spv::LoopControlMask::MaskNone)); // Branch to continue/work block - (void)builder.AddInstruction(MakeUnique( - context(), spv::Op::OpBranch, 0, 0, - std::initializer_list{{SPV_OPERAND_TYPE_ID, {cont_blk_id}}})); + (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. @@ -386,10 +377,8 @@ uint32_t InstBuffAddrCheckPass::GetSearchAndTestFuncId() { GetBoolId(), spv::Op::OpULessThanEqual, ref_end_inst->result_id(), len_load_inst->result_id()); // Return test result - (void)builder.AddInstruction(MakeUnique( - context(), spv::Op::OpReturnValue, 0, 0, - std::initializer_list{ - {SPV_OPERAND_TYPE_ID, {len_test_inst->result_id()}}})); + (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 @@ -422,10 +411,8 @@ uint32_t InstBuffAddrCheckPass::GenSearchAndTest(Instruction* ref_inst, uint32_t ref_len = GetTypeLength(ref_ptr_ty_inst->GetSingleWordInOperand(1)); uint32_t ref_len_id = builder->GetUintConstantId(ref_len); // Gen call to search and test function - const std::vector args = {GetSearchAndTestFuncId(), *ref_uptr_id, - ref_len_id}; - Instruction* call_inst = - builder->AddNaryOp(GetBoolId(), spv::Op::OpFunctionCall, args); + Instruction* call_inst = builder->AddFunctionCall( + GetBoolId(), GetSearchAndTestFuncId(), {*ref_uptr_id, ref_len_id}); uint32_t retval = call_inst->result_id(); return retval; } diff --git a/source/opt/inst_debug_printf_pass.cpp b/source/opt/inst_debug_printf_pass.cpp index 151b94c73e..4f97277812 100644 --- a/source/opt/inst_debug_printf_pass.cpp +++ b/source/opt/inst_debug_printf_pass.cpp @@ -34,8 +34,8 @@ void InstDebugPrintfPass::GenOutputValues(Instruction* val_inst, const analysis::Type* c_ty = v_ty->element_type(); uint32_t c_ty_id = type_mgr->GetId(c_ty); for (uint32_t c = 0; c < v_ty->element_count(); ++c) { - Instruction* c_inst = builder->AddIdLiteralOp( - c_ty_id, spv::Op::OpCompositeExtract, val_inst->result_id(), c); + Instruction* c_inst = + builder->AddCompositeExtract(c_ty_id, val_inst->result_id(), {c}); GenOutputValues(c_inst, val_ids, builder); } return; @@ -44,9 +44,8 @@ void InstDebugPrintfPass::GenOutputValues(Instruction* val_inst, // Select between uint32 zero or one uint32_t zero_id = builder->GetUintConstantId(0); uint32_t one_id = builder->GetUintConstantId(1); - Instruction* sel_inst = - builder->AddTernaryOp(GetUintId(), spv::Op::OpSelect, - val_inst->result_id(), one_id, zero_id); + Instruction* sel_inst = builder->AddSelect( + GetUintId(), val_inst->result_id(), one_id, zero_id); val_ids->push_back(sel_inst->result_id()); return; } diff --git a/source/opt/instrument_pass.cpp b/source/opt/instrument_pass.cpp index 441d943f70..c6e405051d 100644 --- a/source/opt/instrument_pass.cpp +++ b/source/opt/instrument_pass.cpp @@ -54,7 +54,6 @@ void InstrumentPass::MovePreludeCode( void InstrumentPass::MovePostludeCode( UptrVectorIterator ref_block_itr, BasicBlock* new_blk_ptr) { - // new_blk_ptr->reset(new BasicBlock(NewLabel(ref_block_itr->id()))); // Move contents of original ref block. for (auto cii = ref_block_itr->begin(); cii != ref_block_itr->end(); cii = ref_block_itr->begin()) { @@ -77,21 +76,62 @@ void InstrumentPass::MovePostludeCode( } std::unique_ptr InstrumentPass::NewLabel(uint32_t label_id) { - std::unique_ptr newLabel( - new Instruction(context(), spv::Op::OpLabel, 0, label_id, {})); - get_def_use_mgr()->AnalyzeInstDefUse(&*newLabel); - return newLabel; + auto new_label = + MakeUnique(context(), spv::Op::OpLabel, 0, label_id, + std::initializer_list{}); + get_def_use_mgr()->AnalyzeInstDefUse(&*new_label); + return new_label; +} + +std::unique_ptr InstrumentPass::StartFunction( + uint32_t func_id, const analysis::Type* return_type, + const std::vector& param_types) { + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::Function* func_type = GetFunction(return_type, param_types); + + const std::vector operands{ + {spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, + {uint32_t(spv::FunctionControlMask::MaskNone)}}, + {spv_operand_type_t::SPV_OPERAND_TYPE_ID, {type_mgr->GetId(func_type)}}, + }; + auto func_inst = + MakeUnique(context(), spv::Op::OpFunction, + type_mgr->GetId(return_type), func_id, operands); + get_def_use_mgr()->AnalyzeInstDefUse(&*func_inst); + return MakeUnique(std::move(func_inst)); +} + +std::unique_ptr InstrumentPass::EndFunction() { + auto end = MakeUnique(context(), spv::Op::OpFunctionEnd, 0, 0, + std::initializer_list{}); + get_def_use_mgr()->AnalyzeInstDefUse(end.get()); + return end; +} + +std::vector InstrumentPass::AddParameters( + Function& func, const std::vector& param_types) { + std::vector param_ids; + param_ids.reserve(param_types.size()); + for (const analysis::Type* param : param_types) { + uint32_t pid = TakeNextId(); + param_ids.push_back(pid); + auto param_inst = + MakeUnique(context(), spv::Op::OpFunctionParameter, + context()->get_type_mgr()->GetId(param), pid, + std::initializer_list{}); + get_def_use_mgr()->AnalyzeInstDefUse(param_inst.get()); + func.AddParameter(std::move(param_inst)); + } + return param_ids; } std::unique_ptr InstrumentPass::NewName( uint32_t id, const std::string& name_str) { - std::unique_ptr new_name(new Instruction( + return MakeUnique( context(), spv::Op::OpName, 0, 0, std::initializer_list{ {SPV_OPERAND_TYPE_ID, {id}}, - {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}})); - - return new_name; + {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}}); } std::unique_ptr InstrumentPass::NewGlobalName( @@ -118,14 +158,12 @@ std::unique_ptr InstrumentPass::NewGlobalName( std::unique_ptr InstrumentPass::NewMemberName( uint32_t id, uint32_t member_index, const std::string& name_str) { - std::unique_ptr new_name(new Instruction( + 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)}})); - - return new_name; + {SPV_OPERAND_TYPE_LITERAL_STRING, utils::MakeVector(name_str)}}); } uint32_t InstrumentPass::Gen32BitCvtCode(uint32_t val_id, @@ -167,17 +205,15 @@ void InstrumentPass::GenDebugOutputFieldCode(uint32_t base_offset_id, // Cast value to 32-bit unsigned if necessary uint32_t val_id = GenUintCastCode(field_value_id, builder); // Store value - Instruction* data_idx_inst = - builder->AddBinaryOp(GetUintId(), spv::Op::OpIAdd, base_offset_id, - builder->GetUintConstantId(field_offset)); + 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->AddTernaryOp(buf_uint_ptr_id, spv::Op::OpAccessChain, buf_id, - builder->GetUintConstantId(kDebugOutputDataOffset), - data_idx_inst->result_id()); - (void)builder->AddBinaryOp(0, spv::Op::OpStore, achain_inst->result_id(), - val_id); + 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); } void InstrumentPass::GenCommonStreamWriteCode(uint32_t record_sz, @@ -202,8 +238,8 @@ void InstrumentPass::GenCommonStreamWriteCode(uint32_t record_sz, void InstrumentPass::GenFragCoordEltDebugOutputCode( uint32_t base_offset_id, uint32_t uint_frag_coord_id, uint32_t element, InstructionBuilder* builder) { - Instruction* element_val_inst = builder->AddIdLiteralOp( - GetUintId(), spv::Op::OpCompositeExtract, uint_frag_coord_id, element); + Instruction* element_val_inst = + builder->AddCompositeExtract(GetUintId(), uint_frag_coord_id, {element}); GenDebugOutputFieldCode(base_offset_id, kInstFragOutFragCoordX + element, element_val_inst->result_id(), builder); } @@ -212,8 +248,7 @@ uint32_t InstrumentPass::GenVarLoad(uint32_t var_id, InstructionBuilder* builder) { Instruction* var_inst = get_def_use_mgr()->GetDef(var_id); uint32_t type_id = GetPointeeTypeId(var_inst); - Instruction* load_inst = - builder->AddUnaryOp(type_id, spv::Op::OpLoad, var_id); + Instruction* load_inst = builder->AddLoad(type_id, var_id); return load_inst->result_id(); } @@ -249,12 +284,12 @@ void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx, uint32_t load_id = GenVarLoad(context()->GetBuiltinInputVarId(uint32_t( spv::BuiltIn::GlobalInvocationId)), builder); - Instruction* x_inst = builder->AddIdLiteralOp( - GetUintId(), spv::Op::OpCompositeExtract, load_id, 0); - Instruction* y_inst = builder->AddIdLiteralOp( - GetUintId(), spv::Op::OpCompositeExtract, load_id, 1); - Instruction* z_inst = builder->AddIdLiteralOp( - GetUintId(), spv::Op::OpCompositeExtract, load_id, 2); + Instruction* x_inst = + builder->AddCompositeExtract(GetUintId(), load_id, {0}); + Instruction* y_inst = + builder->AddCompositeExtract(GetUintId(), load_id, {1}); + Instruction* z_inst = + builder->AddCompositeExtract(GetUintId(), load_id, {2}); GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdX, x_inst->result_id(), builder); GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdY, @@ -291,10 +326,10 @@ void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx, Instruction* uvec3_cast_inst = builder->AddUnaryOp(GetVec3UintId(), spv::Op::OpBitcast, load_id); uint32_t uvec3_cast_id = uvec3_cast_inst->result_id(); - Instruction* u_inst = builder->AddIdLiteralOp( - GetUintId(), spv::Op::OpCompositeExtract, uvec3_cast_id, 0); - Instruction* v_inst = builder->AddIdLiteralOp( - GetUintId(), spv::Op::OpCompositeExtract, uvec3_cast_id, 1); + Instruction* u_inst = + builder->AddCompositeExtract(GetUintId(), uvec3_cast_id, {0}); + Instruction* v_inst = + builder->AddCompositeExtract(GetUintId(), uvec3_cast_id, {1}); GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordU, u_inst->result_id(), builder); GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordV, @@ -302,8 +337,8 @@ void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx, } break; case spv::ExecutionModel::Fragment: { // Load FragCoord and convert to Uint - Instruction* frag_coord_inst = builder->AddUnaryOp( - GetVec4FloatId(), spv::Op::OpLoad, + Instruction* frag_coord_inst = builder->AddLoad( + GetVec4FloatId(), context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::FragCoord))); Instruction* uint_frag_coord_inst = builder->AddUnaryOp( GetVec4UintId(), spv::Op::OpBitcast, frag_coord_inst->result_id()); @@ -321,12 +356,12 @@ void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx, uint32_t launch_id = GenVarLoad( context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::LaunchIdNV)), builder); - Instruction* x_launch_inst = builder->AddIdLiteralOp( - GetUintId(), spv::Op::OpCompositeExtract, launch_id, 0); - Instruction* y_launch_inst = builder->AddIdLiteralOp( - GetUintId(), spv::Op::OpCompositeExtract, launch_id, 1); - Instruction* z_launch_inst = builder->AddIdLiteralOp( - GetUintId(), spv::Op::OpCompositeExtract, launch_id, 2); + Instruction* x_launch_inst = + builder->AddCompositeExtract(GetUintId(), launch_id, {0}); + Instruction* y_launch_inst = + builder->AddCompositeExtract(GetUintId(), launch_id, {1}); + Instruction* z_launch_inst = + builder->AddCompositeExtract(GetUintId(), launch_id, {2}); GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdX, x_launch_inst->result_id(), builder); GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdY, @@ -344,11 +379,10 @@ void InstrumentPass::GenDebugStreamWrite( // Call debug output function. Pass func_idx, instruction_idx and // validation ids as args. uint32_t val_id_cnt = static_cast(validation_ids.size()); - uint32_t output_func_id = GetStreamWriteFunctionId(stage_idx, val_id_cnt); - std::vector args = {output_func_id, - builder->GetUintConstantId(instruction_idx)}; + std::vector args = {builder->GetUintConstantId(instruction_idx)}; (void)args.insert(args.end(), validation_ids.begin(), validation_ids.end()); - (void)builder->AddNaryOp(GetVoidId(), spv::Op::OpFunctionCall, args); + (void)builder->AddFunctionCall( + GetVoidId(), GetStreamWriteFunctionId(stage_idx, val_id_cnt), args); } bool InstrumentPass::AllConstant(const std::vector& ids) { @@ -360,33 +394,38 @@ bool InstrumentPass::AllConstant(const std::vector& ids) { } uint32_t InstrumentPass::GenDebugDirectRead( - const std::vector& offset_ids, InstructionBuilder* ref_builder) { + const std::vector& offset_ids, InstructionBuilder* builder) { // Call debug input function. Pass func_idx and offset ids as args. - uint32_t off_id_cnt = static_cast(offset_ids.size()); - uint32_t input_func_id = GetDirectReadFunctionId(off_id_cnt); - std::vector args = {input_func_id}; - (void)args.insert(args.end(), offset_ids.begin(), offset_ids.end()); + const uint32_t off_id_cnt = static_cast(offset_ids.size()); + const uint32_t input_func_id = GetDirectReadFunctionId(off_id_cnt); + return GenReadFunctionCall(input_func_id, offset_ids, builder); +} + +uint32_t InstrumentPass::GenReadFunctionCall( + uint32_t func_id, const std::vector& func_call_args, + InstructionBuilder* ref_builder) { // If optimizing direct reads and the call has already been generated, // use its result if (opt_direct_reads_) { - uint32_t res_id = call2id_[args]; + uint32_t res_id = call2id_[func_call_args]; if (res_id != 0) return res_id; } - // If the offsets are all constants, the call can be moved to the first block - // of the function where its result can be reused. One example where this is - // profitable is for uniform buffer references, of which there are often many. + // If the function arguments are all constants, the call can be moved to the + // first block of the function where its result can be reused. One example + // where this is profitable is for uniform buffer references, of which there + // are often many. InstructionBuilder builder(ref_builder->GetContext(), &*ref_builder->GetInsertPoint(), ref_builder->GetPreservedAnalysis()); - bool insert_in_first_block = opt_direct_reads_ && AllConstant(offset_ids); + bool insert_in_first_block = opt_direct_reads_ && AllConstant(func_call_args); if (insert_in_first_block) { Instruction* insert_before = &*curr_func_->begin()->tail(); builder.SetInsertPoint(insert_before); } uint32_t res_id = - builder.AddNaryOp(GetUintId(), spv::Op::OpFunctionCall, args) + builder.AddFunctionCall(GetUintId(), func_id, func_call_args) ->result_id(); - if (insert_in_first_block) call2id_[args] = res_id; + if (insert_in_first_block) call2id_[func_call_args] = res_id; return res_id; } @@ -502,32 +541,61 @@ uint32_t InstrumentPass::GetInputBufferBinding() { return 0; } -analysis::Type* InstrumentPass::GetUintXRuntimeArrayType( - uint32_t width, analysis::Type** rarr_ty) { +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); + assert(type && type->AsInteger()); + return type->AsInteger(); +} + +analysis::Struct* InstrumentPass::GetStruct( + const std::vector& fields) { + analysis::Struct s(fields); + analysis::Type* type = context()->get_type_mgr()->GetRegisteredType(&s); + assert(type && type->AsStruct()); + return type->AsStruct(); +} + +analysis::RuntimeArray* InstrumentPass::GetRuntimeArray( + const analysis::Type* element) { + analysis::RuntimeArray r(element); + analysis::Type* type = context()->get_type_mgr()->GetRegisteredType(&r); + assert(type && type->AsRuntimeArray()); + return type->AsRuntimeArray(); +} + +analysis::Function* InstrumentPass::GetFunction( + const analysis::Type* return_val, + const std::vector& args) { + analysis::Function func(return_val, args); + analysis::Type* type = context()->get_type_mgr()->GetRegisteredType(&func); + assert(type && type->AsFunction()); + return type->AsFunction(); +} + +analysis::RuntimeArray* InstrumentPass::GetUintXRuntimeArrayType( + uint32_t width, analysis::RuntimeArray** rarr_ty) { if (*rarr_ty == nullptr) { - analysis::DecorationManager* deco_mgr = get_decoration_mgr(); - analysis::TypeManager* type_mgr = context()->get_type_mgr(); - analysis::Integer uint_ty(width, false); - analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty); - analysis::RuntimeArray uint_rarr_ty_tmp(reg_uint_ty); - *rarr_ty = type_mgr->GetRegisteredType(&uint_rarr_ty_tmp); - uint32_t uint_arr_ty_id = type_mgr->GetTypeInstruction(*rarr_ty); + *rarr_ty = GetRuntimeArray(GetInteger(width, false)); + uint32_t uint_arr_ty_id = + context()->get_type_mgr()->GetTypeInstruction(*rarr_ty); // By the Vulkan spec, a pre-existing RuntimeArray of uint must be part of // a block, and will therefore be decorated with an ArrayStride. 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(uint_arr_ty_id) == 0 && + assert(get_def_use_mgr()->NumUses(uint_arr_ty_id) == 0 && "used RuntimeArray type returned"); - deco_mgr->AddDecorationVal( + get_decoration_mgr()->AddDecorationVal( uint_arr_ty_id, uint32_t(spv::Decoration::ArrayStride), width / 8u); } return *rarr_ty; } -analysis::Type* InstrumentPass::GetUintRuntimeArrayType(uint32_t width) { - analysis::Type** rarr_ty = +analysis::RuntimeArray* InstrumentPass::GetUintRuntimeArrayType( + uint32_t width) { + analysis::RuntimeArray** rarr_ty = (width == 64) ? &uint64_rarr_ty_ : &uint32_rarr_ty_; return GetUintXRuntimeArrayType(width, rarr_ty); } @@ -546,11 +614,10 @@ uint32_t InstrumentPass::GetOutputBufferId() { // If not created yet, create one analysis::DecorationManager* deco_mgr = get_decoration_mgr(); analysis::TypeManager* type_mgr = context()->get_type_mgr(); - analysis::Type* reg_uint_rarr_ty = GetUintRuntimeArrayType(32); - analysis::Integer uint_ty(32, false); - analysis::Type* reg_uint_ty = type_mgr->GetRegisteredType(&uint_ty); - analysis::Struct buf_ty({reg_uint_ty, reg_uint_ty, reg_uint_rarr_ty}); - analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty); + 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 @@ -604,8 +671,7 @@ uint32_t InstrumentPass::GetInputBufferId() { 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 buf_ty({reg_uint_rarr_ty}); - analysis::Type* reg_buf_ty = type_mgr->GetRegisteredType(&buf_ty); + 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 @@ -747,37 +813,17 @@ uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx, // Create function param2output_func_id_[param_cnt] = TakeNextId(); analysis::TypeManager* type_mgr = context()->get_type_mgr(); - std::vector param_types; - for (uint32_t c = 0; c < param_cnt; ++c) - param_types.push_back(type_mgr->GetType(GetUintId())); - analysis::Function func_ty(type_mgr->GetType(GetVoidId()), 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, - GetVoidId(), param2output_func_id_[param_cnt], - {{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 output_func = - MakeUnique(std::move(func_inst)); - // Add parameters - std::vector param_vec; - for (uint32_t c = 0; c < param_cnt; ++c) { - uint32_t pid = TakeNextId(); - param_vec.push_back(pid); - std::unique_ptr param_inst( - new Instruction(get_module()->context(), spv::Op::OpFunctionParameter, - GetUintId(), pid, {})); - get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst); - output_func->AddParameter(std::move(param_inst)); - } + + const std::vector param_types(param_cnt, + GetInteger(32, false)); + 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 - uint32_t test_blk_id = TakeNextId(); - std::unique_ptr test_label(NewLabel(test_blk_id)); - std::unique_ptr new_blk_ptr = - MakeUnique(std::move(test_label)); + auto new_blk_ptr = MakeUnique(NewLabel(TakeNextId())); + InstructionBuilder builder( context(), &*new_blk_ptr, IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); @@ -786,9 +832,9 @@ uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx, uint32_t obuf_record_sz = val_spec_offset + val_spec_param_cnt; uint32_t buf_id = GetOutputBufferId(); uint32_t buf_uint_ptr_id = GetOutputBufferPtrId(); - Instruction* obuf_curr_sz_ac_inst = - builder.AddBinaryOp(buf_uint_ptr_id, spv::Op::OpAccessChain, buf_id, - builder.GetUintConstantId(kDebugOutputSizeOffset)); + 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); @@ -802,8 +848,8 @@ uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx, uint32_t obuf_curr_sz_id = obuf_curr_sz_inst->result_id(); // Compute new written size Instruction* obuf_new_sz_inst = - builder.AddBinaryOp(GetUintId(), spv::Op::OpIAdd, obuf_curr_sz_id, - builder.GetUintConstantId(obuf_record_sz)); + 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, @@ -825,13 +871,13 @@ uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx, new_blk_ptr = MakeUnique(std::move(write_label)); builder.SetInsertPoint(&*new_blk_ptr); // Generate common and stage-specific debug record members - GenCommonStreamWriteCode(obuf_record_sz, param_vec[kInstCommonParamInstIdx], + GenCommonStreamWriteCode(obuf_record_sz, param_ids[kInstCommonParamInstIdx], stage_idx, obuf_curr_sz_id, &builder); GenStageStreamWriteCode(stage_idx, obuf_curr_sz_id, &builder); // Gen writes of validation specific data for (uint32_t i = 0; i < val_spec_param_cnt; ++i) { GenDebugOutputFieldCode(obuf_curr_sz_id, val_spec_offset + i, - param_vec[kInstCommonParamCnt + i], &builder); + param_ids[kInstCommonParamCnt + i], &builder); } // Close write block and gen merge block (void)builder.AddBranch(merge_blk_id); @@ -840,11 +886,9 @@ uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx, 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)); - std::unique_ptr func_end_inst(new Instruction( - get_module()->context(), spv::Op::OpFunctionEnd, 0, 0, {})); - get_def_use_mgr()->AnalyzeInstDefUse(&*func_end_inst); - output_func->SetFunctionEnd(std::move(func_end_inst)); + output_func->SetFunctionEnd(EndFunction()); context()->AddFunction(std::move(output_func)); std::string name("stream_write_"); @@ -861,77 +905,48 @@ uint32_t InstrumentPass::GetDirectReadFunctionId(uint32_t param_cnt) { if (func_id != 0) return func_id; // Create input function for param_cnt. func_id = TakeNextId(); - analysis::TypeManager* type_mgr = context()->get_type_mgr(); - std::vector param_types; - for (uint32_t c = 0; c < param_cnt; ++c) - param_types.push_back(type_mgr->GetType(GetUintId())); - uint32_t ibuf_type_id = GetInputBufferTypeId(); - analysis::Function func_ty(type_mgr->GetType(ibuf_type_id), 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, ibuf_type_id, 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); + analysis::Integer* uint_type = GetInteger(32, false); + std::vector param_types(param_cnt, uint_type); + std::unique_ptr input_func = - MakeUnique(std::move(func_inst)); - // Add parameters - std::vector param_vec; - for (uint32_t c = 0; c < param_cnt; ++c) { - uint32_t pid = TakeNextId(); - param_vec.push_back(pid); - std::unique_ptr param_inst( - new Instruction(get_module()->context(), spv::Op::OpFunctionParameter, - GetUintId(), pid, {})); - get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst); - input_func->AddParameter(std::move(param_inst)); - } + StartFunction(func_id, uint_type, param_types); + std::vector param_ids = AddParameters(*input_func, param_types); + // Create block - uint32_t blk_id = TakeNextId(); - std::unique_ptr blk_label(NewLabel(blk_id)); - std::unique_ptr new_blk_ptr = - MakeUnique(std::move(blk_label)); + 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_vec[0]; + offset_id = param_ids[0]; } else { if (ibuf_type_id != GetUintId()) { - Instruction* ucvt_inst = - builder.AddUnaryOp(GetUintId(), spv::Op::OpUConvert, last_value_id); - last_value_id = ucvt_inst->result_id(); + last_value_id = + builder.AddUnaryOp(GetUintId(), spv::Op::OpUConvert, last_value_id) + ->result_id(); } - Instruction* offset_inst = builder.AddBinaryOp( - GetUintId(), spv::Op::OpIAdd, last_value_id, param_vec[p]); - offset_id = offset_inst->result_id(); + offset_id = builder.AddIAdd(GetUintId(), last_value_id, param_ids[p]) + ->result_id(); } - Instruction* ac_inst = builder.AddTernaryOp( - buf_ptr_id, spv::Op::OpAccessChain, buf_id, - builder.GetUintConstantId(kDebugInputDataOffset), offset_id); - Instruction* load_inst = - builder.AddUnaryOp(ibuf_type_id, spv::Op::OpLoad, ac_inst->result_id()); - last_value_id = load_inst->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.AddInstruction(MakeUnique( - context(), spv::Op::OpReturnValue, 0, 0, - std::initializer_list{{SPV_OPERAND_TYPE_ID, {last_value_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)); - 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)); + input_func->SetFunctionEnd(EndFunction()); context()->AddFunction(std::move(input_func)); std::string name("direct_read_"); diff --git a/source/opt/instrument_pass.h b/source/opt/instrument_pass.h index e98ba88e42..13119297cb 100644 --- a/source/opt/instrument_pass.h +++ b/source/opt/instrument_pass.h @@ -214,6 +214,10 @@ class InstrumentPass : public Pass { uint32_t GenDebugDirectRead(const std::vector& offset_ids, InstructionBuilder* builder); + uint32_t GenReadFunctionCall(uint32_t func_id, + const std::vector& args, + InstructionBuilder* builder); + // Generate code to convert integer |value_id| to 32bit, if needed. Return // an id to the 32bit equivalent. uint32_t Gen32BitCvtCode(uint32_t value_id, InstructionBuilder* builder); @@ -222,6 +226,15 @@ class InstrumentPass : public Pass { // Return an id to the Uint equivalent. uint32_t GenUintCastCode(uint32_t value_id, InstructionBuilder* builder); + std::unique_ptr StartFunction( + uint32_t func_id, const analysis::Type* return_type, + const std::vector& param_types); + + std::vector AddParameters( + Function& func, const std::vector& param_types); + + std::unique_ptr EndFunction(); + // Return new label. std::unique_ptr NewLabel(uint32_t label_id); @@ -253,12 +266,20 @@ class InstrumentPass : public Pass { // Return id for void type uint32_t GetVoidId(); + // Get registered type structures + analysis::Integer* GetInteger(uint32_t width, bool is_signed); + analysis::Struct* GetStruct(const std::vector& fields); + analysis::RuntimeArray* GetRuntimeArray(const analysis::Type* element); + analysis::Function* GetFunction( + const analysis::Type* return_val, + const std::vector& args); + // Return pointer to type for runtime array of uint - analysis::Type* GetUintXRuntimeArrayType(uint32_t width, - analysis::Type** rarr_ty); + analysis::RuntimeArray* GetUintXRuntimeArrayType( + uint32_t width, analysis::RuntimeArray** rarr_ty); // Return pointer to type for runtime array of uint - analysis::Type* GetUintRuntimeArrayType(uint32_t width); + analysis::RuntimeArray* GetUintRuntimeArrayType(uint32_t width); // Return id for buffer uint type uint32_t GetOutputBufferPtrId(); @@ -448,10 +469,10 @@ class InstrumentPass : public Pass { bool storage_buffer_ext_defined_; // runtime array of uint type - analysis::Type* uint64_rarr_ty_; + analysis::RuntimeArray* uint64_rarr_ty_; // runtime array of uint type - analysis::Type* uint32_rarr_ty_; + analysis::RuntimeArray* uint32_rarr_ty_; // Pre-instrumentation same-block insts std::unordered_map same_block_pre_; diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp index 3600d0d228..d450511e0c 100644 --- a/test/opt/inst_bindless_check_test.cpp +++ b/test/opt/inst_bindless_check_test.cpp @@ -1040,10 +1040,6 @@ 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: uint_0 = OpConstant %uint 0 -; CHECK: bool = OpTypeBool -; CHECK: %41 = OpTypeFunction %void %uint %uint %uint %uint -; CHECK: _runtimearr_uint = OpTypeRuntimeArray %uint )" + kOutputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float @@ -2385,14 +2381,7 @@ OpDecorate %b Location 1 %_ptr_Input_float = OpTypePointer Input %float %b = OpVariable %_ptr_Input_float Input %_ptr_Uniform_float = OpTypePointer Uniform %float -; CHECK: %uint = OpTypeInt 32 0 -; CHECK: %26 = OpTypeFunction %uint %uint %uint -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %bool = OpTypeBool -; CHECK: %48 = OpTypeFunction %void %uint %uint %uint %uint -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ; CHECK: %v4uint = OpTypeVector %uint 4 ; CHECK: %102 = OpTypeFunction %uint %uint %uint %uint %uint @@ -2508,10 +2497,7 @@ OpDecorate %22 NonUniform %nu_ii = OpVariable %_ptr_Input_int Input %int_0 = OpConstant %int 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -; CHECK: %bool = OpTypeBool -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint )" + kOutputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %v4float = OpTypeVector %float 4 ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input @@ -2637,11 +2623,7 @@ OpDecorate %images NonWritable %v4float = OpTypeVector %float 4 %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: %v3uint = OpTypeVector %uint 3 ; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint ; CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input @@ -2797,12 +2779,7 @@ OpDecorate %images NonWritable %v4float = OpTypeVector %float 4 %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -; CHECK: %34 = OpTypeFunction %uint %uint %uint -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float ; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint )"; @@ -2954,12 +2931,7 @@ OpDecorate %images NonWritable %v4float = OpTypeVector %float 4 %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -; CHECK: %34 = OpTypeFunction %uint %uint %uint -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input ; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float ; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint @@ -3112,12 +3084,7 @@ OpDecorate %images NonWritable %v4float = OpTypeVector %float 4 %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -; CHECK: %34 = OpTypeFunction %uint %uint %uint -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input ; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float ; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint @@ -3270,12 +3237,7 @@ OpDecorate %images NonWritable %v4float = OpTypeVector %float 4 %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -; CHECK: %34 = OpTypeFunction %uint %uint %uint -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input ; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float ; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint @@ -3428,12 +3390,7 @@ OpDecorate %images NonWritable %v4float = OpTypeVector %float 4 %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -; CHECK: %34 = OpTypeFunction %uint %uint %uint -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input ; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float ; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint @@ -3586,12 +3543,7 @@ OpDecorate %images NonWritable %v4float = OpTypeVector %float 4 %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -; CHECK: %34 = OpTypeFunction %uint %uint %uint -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float ; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint )"; @@ -3777,8 +3729,6 @@ OpDecorate %outColor Location 0 %_ptr_Output_v4float = OpTypePointer Output %v4float %outColor = OpVariable %_ptr_Output_v4float Output %float_0 = OpConstant %float 0 -; CHECK: %bool = OpTypeBool -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint )" + kOutputGlobals + R"( ; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )" + kInputGlobals + R"( @@ -3963,11 +3913,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output - ;CHECK: %122 = OpTypeFunction %uint %uint %uint %uint - ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint - )" + kInputGlobals + R"( - ;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint - )" + kOutputGlobals + R"( + )" + kInputGlobals + kOutputGlobals + R"( ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -4154,12 +4100,7 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -;CHECK: %105 = OpTypeFunction %uint %uint %uint %uint -;CHECK:%_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -;CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -4296,12 +4237,7 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -;CHECK: %104 = OpTypeFunction %uint %uint %uint %uint %uint -;CHECK:%_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -;CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: %v4uint = OpTypeVector %uint 4 @@ -4436,10 +4372,7 @@ TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -;CHECK: %bool = OpTypeBool -;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 @@ -4620,12 +4553,7 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -;CHECK: %61 = OpTypeFunction %uint %uint %uint %uint -;CHECK:%_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -;CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float @@ -4750,12 +4678,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { %v4float = OpTypeVector %float 4 %_ptr_Input_v4float = OpTypePointer Input %v4float %a_position = OpVariable %_ptr_Input_v4float Input -;CHECK: %37 = OpTypeFunction %uint %uint %uint %uint -;CHECK:%_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -;CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + 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 @@ -4873,12 +4796,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { %v4float = OpTypeVector %float 4 %_ptr_Input_v4float = OpTypePointer Input %v4float %a_position = OpVariable %_ptr_Input_v4float Input -;CHECK: %37 = OpTypeFunction %uint %uint %uint %uint -;CHECK:%_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -;CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + 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 @@ -5003,12 +4921,7 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { %v4float = OpTypeVector %float 4 %_ptr_Input_v4float = OpTypePointer Input %v4float %a_position = OpVariable %_ptr_Input_v4float Input -;CHECK: %46 = OpTypeFunction %uint %uint %uint %uint -;CHECK:%_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -;CHECK:%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -;CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + 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 @@ -5202,7 +5115,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { %x = OpVariable %_ptr_Output_v4float Output ;CHECK: %uint = OpTypeInt 32 0 ;CHECK: %bool = OpTypeBool -;CHECK: %34 = OpTypeFunction %void %uint %uint %uint %uint %uint +;CHECK: {{%\w+}} = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint )" + kOutputGlobals + R"( ;CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint diff --git a/test/opt/inst_buff_addr_check_test.cpp b/test/opt/inst_buff_addr_check_test.cpp index b08f7b0b42..4a56f60500 100644 --- a/test/opt/inst_buff_addr_check_test.cpp +++ b/test/opt/inst_buff_addr_check_test.cpp @@ -272,7 +272,7 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer ; CHECK: %_runtimearr_ulong = OpTypeRuntimeArray %ulong )" + kInputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_ulong = OpTypePointer StorageBuffer %ulong -; CHECK: %70 = OpTypeFunction %void %uint %uint %uint %uint +; CHECK: {{%\w+}} = OpTypeFunction %void %uint %uint %uint %uint ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint )" + kOutputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint @@ -524,7 +524,7 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffe %ulong_18446744073172680704 = OpConstant %ulong 18446744073172680704 ; CHECK: %47 = OpTypeFunction %bool %ulong %uint )" + kInputGlobals + R"( -; CHECK: %90 = OpTypeFunction %void %uint %uint %uint %uint +; CHECK: {{%\w+}} = OpTypeFunction %void %uint %uint %uint %uint )" + kOutputGlobals + R"( ; CHECK: %143 = OpConstantNull %Test_0 )"; diff --git a/test/opt/inst_debug_printf_test.cpp b/test/opt/inst_debug_printf_test.cpp index 6a4cbddd10..4031480311 100644 --- a/test/opt/inst_debug_printf_test.cpp +++ b/test/opt/inst_debug_printf_test.cpp @@ -111,7 +111,7 @@ OpDecorate %4 Location 0 %_ptr_Output_v4float = OpTypePointer Output %v4float %4 = OpVariable %_ptr_Output_v4float Output ; CHECK: %uint = OpTypeInt 32 0 -; CHECK: %38 = OpTypeFunction %void %uint %uint %uint %uint %uint %uint +; CHECK: [[func_type:%\w+]] = OpTypeFunction %void %uint %uint %uint %uint %uint %uint ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint )" + kOutputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint @@ -149,7 +149,7 @@ OpFunctionEnd )"; const std::string output_func = R"( -; CHECK: %inst_printf_stream_write_6 = OpFunction %void None %38 +; CHECK: %inst_printf_stream_write_6 = OpFunction %void None [[func_type]] ; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint ; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint ; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint From fd1e650cfe6fe2fa3acd30b4cda313271015bedf Mon Sep 17 00:00:00 2001 From: Maciej Date: Fri, 3 Feb 2023 14:58:51 +0100 Subject: [PATCH 038/523] Validate decoration of structs with RuntimeArray (#5094) Contributes to https://github.com/KhronosGroup/glslang/issues/2439 * When OpTypeStruct is used in Vulkan env and its last member is a RuntimeArray, check if the struct is decorated with Block or BufferBlock, as required by VUID-...-04680. --- source/val/validate_type.cpp | 9 +++++++++ test/val/val_decoration_test.cpp | 31 +++++++++++++++++++++++++++++++ test/val/val_memory_test.cpp | 9 ++++++--- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/source/val/validate_type.cpp b/source/val/validate_type.cpp index e7adab80fc..430d819084 100644 --- a/source/val/validate_type.cpp +++ b/source/val/validate_type.cpp @@ -349,6 +349,15 @@ spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) { << ", OpTypeRuntimeArray must only be used for the last member " "of an OpTypeStruct"; } + + if (!_.HasDecoration(inst->id(), spv::Decoration::Block) && + !_.HasDecoration(inst->id(), spv::Decoration::BufferBlock)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << _.VkErrorID(4680) + << spvLogStringForEnv(_.context()->target_env) + << ", OpTypeStruct containing an OpTypeRuntimeArray " + << "must be decorated with Block or BufferBlock."; + } } } diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp index 04d373a75f..4f90e6b03d 100644 --- a/test/val/val_decoration_test.cpp +++ b/test/val/val_decoration_test.cpp @@ -5281,6 +5281,37 @@ OpFunctionEnd "rules: member 1 at offset 1 is not aligned to 4")); } +TEST_F(ValidateDecorations, VulkanStructWithoutDecorationWithRuntimeArray) { + std::string str = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %func "func" + OpExecutionMode %func OriginUpperLeft + OpDecorate %array_t ArrayStride 4 + OpMemberDecorate %struct_t 0 Offset 0 + OpMemberDecorate %struct_t 1 Offset 4 + %uint_t = OpTypeInt 32 0 + %array_t = OpTypeRuntimeArray %uint_t + %struct_t = OpTypeStruct %uint_t %array_t +%struct_ptr = OpTypePointer StorageBuffer %struct_t + %2 = OpVariable %struct_ptr StorageBuffer + %void = OpTypeVoid + %func_t = OpTypeFunction %void + %func = OpFunction %void None %func_t + %1 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpTypeRuntimeArray-04680")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Vulkan, OpTypeStruct containing an OpTypeRuntimeArray " + "must be decorated with Block or BufferBlock.")); +} + TEST_F(ValidateDecorations, EmptyStructAtNonZeroOffsetGood) { const std::string spirv = R"( OpCapability Shader diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp index d0735dca13..d575318953 100644 --- a/test/val/val_memory_test.cpp +++ b/test/val/val_memory_test.cpp @@ -2475,6 +2475,7 @@ OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" OpExecutionMode %func OriginUpperLeft +OpDecorate %struct_t Block %uint_t = OpTypeInt 32 0 %array_t = OpTypeRuntimeArray %uint_t %struct_t = OpTypeStruct %array_t @@ -2498,7 +2499,7 @@ OpFunctionEnd "For Vulkan, OpTypeStruct variables containing OpTypeRuntimeArray " "must have storage class of StorageBuffer, PhysicalStorageBuffer, or " "Uniform.\n %6 = " - "OpVariable %_ptr_Workgroup__struct_4 Workgroup\n")); + "OpVariable %_ptr_Workgroup__struct_2 Workgroup\n")); } TEST_F(ValidateMemory, VulkanRTAInsideStorageBufferStructWithoutBlockBad) { @@ -2507,6 +2508,7 @@ OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" OpExecutionMode %func OriginUpperLeft +OpDecorate %struct_t BufferBlock %uint_t = OpTypeInt 32 0 %array_t = OpTypeRuntimeArray %uint_t %struct_t = OpTypeStruct %array_t @@ -2529,7 +2531,7 @@ OpFunctionEnd "OpTypeRuntimeArray must be decorated with Block if it " "has storage class StorageBuffer or " "PhysicalStorageBuffer.\n %6 = OpVariable " - "%_ptr_StorageBuffer__struct_4 StorageBuffer\n")); + "%_ptr_StorageBuffer__struct_2 StorageBuffer\n")); } TEST_F(ValidateMemory, VulkanRTAInsideUniformStructGood) { @@ -2564,6 +2566,7 @@ OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" OpExecutionMode %func OriginUpperLeft +OpDecorate %struct_t Block %uint_t = OpTypeInt 32 0 %array_t = OpTypeRuntimeArray %uint_t %struct_t = OpTypeStruct %array_t @@ -2585,7 +2588,7 @@ OpFunctionEnd HasSubstr("For Vulkan, an OpTypeStruct variable containing an " "OpTypeRuntimeArray must be decorated with BufferBlock " "if it has storage class Uniform.\n %6 = OpVariable " - "%_ptr_Uniform__struct_4 Uniform\n")); + "%_ptr_Uniform__struct_2 Uniform\n")); } TEST_F(ValidateMemory, VulkanRTAInsideRTABad) { From cac9a5a3ee8d442e896ac88483514b5594e0ad84 Mon Sep 17 00:00:00 2001 From: Laura Hermanns Date: Fri, 3 Feb 2023 10:03:15 -0500 Subject: [PATCH 039/523] Fix null pointer in FoldInsertWithConstants. (#5093) * Fix null pointer in FoldInsertWithConstants. Struct types are not supported in constant folding yet. * Added 'Test case 16' to fold_test. Tests OpCompositeInsert not to be folded on a struct type. --- source/opt/const_folding_rules.cpp | 15 ++++++++++----- test/opt/fold_test.cpp | 11 ++++++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/source/opt/const_folding_rules.cpp b/source/opt/const_folding_rules.cpp index 14f22089b4..516c34b3bc 100644 --- a/source/opt/const_folding_rules.cpp +++ b/source/opt/const_folding_rules.cpp @@ -145,12 +145,17 @@ ConstantFoldingRule FoldInsertWithConstants() { if (composite->AsNullConstant()) { // Make new composite so it can be inserted in the index with the // non-null value - const auto new_composite = const_mgr->GetNullCompositeConstant(type); - // Keep track of any indexes along the way to last index - if (i != final_index) { - chain.push_back(new_composite); + if (const auto new_composite = + const_mgr->GetNullCompositeConstant(type)) { + // Keep track of any indexes along the way to last index + if (i != final_index) { + chain.push_back(new_composite); + } + components = new_composite->AsCompositeConstant()->GetComponents(); + } else { + // Unsupported input type (such as structs) + return nullptr; } - components = new_composite->AsCompositeConstant()->GetComponents(); } else { // Keep track of any indexes along the way to last index if (i != final_index) { diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index 06b91f3a66..cc9bcd6f9e 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -7363,7 +7363,16 @@ ::testing::Values( "%5 = OpCompositeConstruct %v2int %3 %4\n" + "OpReturn\n" + "OpFunctionEnd", - 5, true) + 5, true), + // Test case 16: Don't fold when type cannot be deduced to a constant. + InstructionFoldingCase( + Header() + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%4 = OpCompositeInsert %struct_v2int_int_int %int_1 %struct_v2int_int_int_null 2\n" + + "OpReturn\n" + + "OpFunctionEnd", + 4, false) )); INSTANTIATE_TEST_SUITE_P(DotProductMatchingTest, MatchingInstructionFoldingTest, From 7823b8ff4a58ce7578c41f0a9f0488d84dfa8210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Fri, 3 Feb 2023 21:43:03 +0100 Subject: [PATCH 040/523] build: allow update_build to generate fake version (#5098) When the build is done on a shallow repo, or on a non-git copy, the version script failed. We should not hard fail, but generate a "version" (unknown). Sample outputs: with git history: `"v2023.2-dev", "SPIRV-Tools v2023.2-dev v2022.4-87-g53541064"` with shallow clone: `"unknown_version", "SPIRV-Tools unknown_version d8759a140bc65811332d5f91f3b08febadd5a21d"` not a git repo: `"unknown_version", "SPIRV-Tools unknown_version unknown_hash, 2023-02-02T16:25:48.077995"` --- utils/update_build_version.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/utils/update_build_version.py b/utils/update_build_version.py index 1ab986248d..ec475ea4e5 100755 --- a/utils/update_build_version.py +++ b/utils/update_build_version.py @@ -142,7 +142,7 @@ def get_description_for_head(repo_path): 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, @@ -158,16 +158,12 @@ def get_description_for_head(repo_path): # reproducible builds, allow the builder to override the wall # clock time with environment variable SOURCE_DATE_EPOCH # containing a (presumably) fixed timestamp. - timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) - iso_date = datetime.datetime.utcfromtimestamp(timestamp).isoformat() - return "unknown hash, {}".format(iso_date) - -def is_folder_git_repo(path): - try: - success, _ = command_output(['git', 'branch'], path) - except NotADirectoryError as e: - return False - return success + if 'SOURCE_DATE_EPOCH' in os.environ: + timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) + iso_date = datetime.datetime.utcfromtimestamp(timestamp).isoformat() + else: + iso_date = datetime.datetime.now().isoformat() + return "unknown_hash, {}".format(iso_date) def main(): FORMAT = '%(asctime)s %(message)s' @@ -181,8 +177,8 @@ def main(): success, version = deduce_current_release(repo_path) if not success: - logging.error("Could not deduce latest release version.") - sys.exit(1) + logging.warning("Could not deduce latest release version from history.") + version = "unknown_version" description = get_description_for_head(repo_path) content = OUTPUT_FORMAT.format(version_tag=version, description=description) From e9dc2c8ce12df55514546511abd19afdf6980cc7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 5 Feb 2023 01:35:10 +0000 Subject: [PATCH 041/523] Roll external/googletest/ ebedaa18c..2f2e72bae (4 commits) (#5099) https://github.com/google/googletest/compare/ebedaa18c7ca...2f2e72bae991 $ git log ebedaa18c..2f2e72bae --date=short --no-merges --format='%ad %ae %s' 2023-02-02 tomhughes Fix compiler flags in Linux presubmit 2023-02-02 tomhughes Fix -Wsign-conversion warnings 2023-02-02 tomhughes Remove unneccessary "#if _MSC_VER" 2023-02-02 absl-team Add a trailing decimal point to FormatTimeInMillisAsSeconds() output when input is an exact N seconds. 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 8a013549a3..c6be512780 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': 'c7b4db79f340f7a9981e8a484f6d5785e24242d1', - 'googletest_revision': 'ebedaa18c7cafa15f06ab3d814440e510fad9559', + 'googletest_revision': '2f2e72bae991138cedd0e3d06a115022736cd568', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From 0ce2bc4ce0ac768b86047a85f31ccb5ea3263f31 Mon Sep 17 00:00:00 2001 From: Caio Oliveira Date: Mon, 6 Feb 2023 07:31:47 -0800 Subject: [PATCH 042/523] spirv-val: Conditional Branch without an exit is invalid in loop header (#5069) * Update fuzz tests to not use invalid combinations of LoopMerge + BranchConditional New IDs were selected to make clear the transformation being done here, instead of reordering all IDs in between or refactoring the SPIR-V in the test. * spirv-val: Conditional Branch without an exit is invalid in loop header From 2.16.2, for CFG: Selections must be structured. That is, an OpSelectionMerge instruction is required to precede: - an OpSwitch instruction - an OpBranchConditional instruction that has different True Label and False Label operands where neither are declared merge blocks or Continue Targets. --- source/val/validate_cfg.cpp | 3 +- .../transformation_add_dead_block_test.cpp | 5 +++ .../transformation_add_dead_break_test.cpp | 10 ++++++ test/val/val_cfg_test.cpp | 31 +++++++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/source/val/validate_cfg.cpp b/source/val/validate_cfg.cpp index 9ba66f4224..a29b5fd074 100644 --- a/source/val/validate_cfg.cpp +++ b/source/val/validate_cfg.cpp @@ -671,7 +671,8 @@ spv_result_t ValidateStructuredSelections( // previously. const bool true_label_unseen = seen.insert(true_label).second; const bool false_label_unseen = seen.insert(false_label).second; - if (!merge && true_label_unseen && false_label_unseen) { + if ((!merge || merge->opcode() == spv::Op::OpLoopMerge) && + true_label_unseen && false_label_unseen) { return _.diag(SPV_ERROR_INVALID_CFG, terminator) << "Selection must be structured"; } diff --git a/test/fuzz/transformation_add_dead_block_test.cpp b/test/fuzz/transformation_add_dead_block_test.cpp index 3c9e6b43c4..534ad6932c 100644 --- a/test/fuzz/transformation_add_dead_block_test.cpp +++ b/test/fuzz/transformation_add_dead_block_test.cpp @@ -295,11 +295,16 @@ TEST(TransformationAddDeadBlockTest, TargetBlockMustNotBeLoopMergeOrContinue) { OpBranch %8 %8 = OpLabel OpLoopMerge %12 %11 None + OpBranch %13 + %13 = OpLabel + OpSelectionMerge %14 None OpBranchConditional %5 %9 %10 %9 = OpLabel OpBranch %11 %10 = OpLabel OpBranch %12 + %14 = OpLabel + OpUnreachable %11 = OpLabel OpBranch %8 %12 = OpLabel diff --git a/test/fuzz/transformation_add_dead_break_test.cpp b/test/fuzz/transformation_add_dead_break_test.cpp index 5302d8a6e3..fd46c96aa1 100644 --- a/test/fuzz/transformation_add_dead_break_test.cpp +++ b/test/fuzz/transformation_add_dead_break_test.cpp @@ -2743,6 +2743,9 @@ TEST(TransformationAddDeadBreakTest, RespectDominanceRules7) { OpBranch %100 %100 = OpLabel OpLoopMerge %101 %104 None + OpBranch %105 + %105 = OpLabel + OpSelectionMerge %106 None OpBranchConditional %11 %102 %103 %103 = OpLabel %200 = OpCopyObject %10 %11 @@ -2752,6 +2755,8 @@ TEST(TransformationAddDeadBreakTest, RespectDominanceRules7) { OpReturn %102 = OpLabel OpBranch %103 + %106 = OpLabel + OpUnreachable %104 = OpLabel OpBranch %100 OpFunctionEnd @@ -2791,12 +2796,17 @@ TEST(TransformationAddDeadBreakTest, RespectDominanceRules8) { OpBranch %100 %100 = OpLabel OpLoopMerge %101 %104 None + OpBranch %105 + %105 = OpLabel + OpSelectionMerge %106 None OpBranchConditional %11 %102 %103 %103 = OpLabel %200 = OpCopyObject %10 %11 OpBranch %101 %102 = OpLabel OpBranch %103 + %106 = OpLabel + OpUnreachable %101 = OpLabel %201 = OpCopyObject %10 %200 OpReturn diff --git a/test/val/val_cfg_test.cpp b/test/val/val_cfg_test.cpp index d876c4881d..a43f72dbe4 100644 --- a/test/val/val_cfg_test.cpp +++ b/test/val/val_cfg_test.cpp @@ -3546,6 +3546,37 @@ OpFunctionEnd EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured")); } +TEST_F(ValidateCFG, LoopConditionalBranchWithoutExitBad) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%bool = OpTypeBool +%undef = OpUndef %bool +%func = OpFunction %void None %void_fn +%entry = OpLabel +OpBranch %loop +%loop = OpLabel +OpLoopMerge %exit %continue None +OpBranchConditional %undef %then %else +%then = OpLabel +OpBranch %continue +%else = OpLabel +OpBranch %exit +%continue = OpLabel +OpBranch %loop +%exit = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured")); +} + TEST_F(ValidateCFG, MissingMergeSwitchBad) { const std::string text = R"( OpCapability Shader From c965624e34b4a140b6afe063a7d4a71514a055fd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 7 Feb 2023 14:17:24 +0000 Subject: [PATCH 043/523] Roll external/googletest/ 2f2e72bae..3d568bdda (1 commit) (#5100) https://github.com/google/googletest/compare/2f2e72bae991...3d568bdda59a $ git log 2f2e72bae..3d568bdda --date=short --no-merges --format='%ad %ae %s' 2023-02-06 absl-team Add support for the alternative base64 encoding in RFC 4648 section 5 to `WhenBase64Unescaped`. 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 c6be512780..f62efdf67b 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': 'c7b4db79f340f7a9981e8a484f6d5785e24242d1', - 'googletest_revision': '2f2e72bae991138cedd0e3d06a115022736cd568', + 'googletest_revision': '3d568bdda59a0b5e50d5f08038eb092b6d88e309', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From b0504f990503109c3a13ada7ce8fa66eee43044d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 8 Feb 2023 12:48:50 +0000 Subject: [PATCH 044/523] Roll external/googletest/ 3d568bdda..0570e2d93 (2 commits) (#5102) https://github.com/google/googletest/compare/3d568bdda59a...0570e2d930a1 $ git log 3d568bdda..0570e2d93 --date=short --no-merges --format='%ad %ae %s' 2023-02-07 tomhughes Remove GTEST_USES_PCRE references 2023-02-07 mvels Fix GTEST_HAS_ABSL define check for [-Werror=undef] compilations 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 f62efdf67b..a23c83bfe9 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': 'c7b4db79f340f7a9981e8a484f6d5785e24242d1', - 'googletest_revision': '3d568bdda59a0b5e50d5f08038eb092b6d88e309', + 'googletest_revision': '0570e2d930a185bbc375be70d9ad96836b955a4f', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From dfcbf310afd9a0bfb44b06238befea3ac051d999 Mon Sep 17 00:00:00 2001 From: Kevin Lubick Date: Wed, 8 Feb 2023 09:20:47 -0500 Subject: [PATCH 045/523] Change exec_tools -> tools for local genrule (#5104) --- BUILD.bazel | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/BUILD.bazel b/BUILD.bazel index 71399b2f5d..0b44b559f0 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -107,7 +107,9 @@ genrule( outs = ["build-version.inc"], cmd = "SOURCE_DATE_EPOCH=0 $(location :update_build_version) $(RULEDIR) $(location build-version.inc)", cmd_bat = "set SOURCE_DATE_EPOCH=0 && $(location :update_build_version) $(RULEDIR) $(location build-version.inc)", - exec_tools = [":update_build_version"], + # This is explicitly tools and not exec_tools because we run it locally (on the host platform) instead of + # (potentially remotely) on the execution platform. + tools = [":update_build_version"], local = True, ) From 5b48c549b031b618cb2cc28a4ac38b6a3ccc89b6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 9 Feb 2023 13:16:56 +0000 Subject: [PATCH 046/523] Roll external/googletest/ 0570e2d93..b73f27fd1 (1 commit) (#5105) https://github.com/google/googletest/compare/0570e2d930a1...b73f27fd1644 $ git log 0570e2d93..b73f27fd1 --date=short --no-merges --format='%ad %ae %s' 2023-02-08 tomhughes Fix _MSC_VER check 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 a23c83bfe9..4685dd7776 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': 'c7b4db79f340f7a9981e8a484f6d5785e24242d1', - 'googletest_revision': '0570e2d930a185bbc375be70d9ad96836b955a4f', + 'googletest_revision': 'b73f27fd164456fea9aba56163f5511355a03272', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From 72213813611134fffc36e061c1b1c029adfa6e91 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 12 Feb 2023 00:29:44 +0000 Subject: [PATCH 047/523] Roll external/re2/ b025c6a3a..891fa6684 (1 commit) (#5108) https://github.com/google/re2/compare/b025c6a3ae05...891fa668468f $ git log b025c6a3a..891fa6684 --date=short --no-merges --format='%ad %ae %s' 2023-02-10 junyer Fix a typographical error. 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 4685dd7776..7ac6e6d927 100644 --- a/DEPS +++ b/DEPS @@ -10,7 +10,7 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', - 're2_revision': 'b025c6a3ae05995660e3b882eb3277f4399ced1a', + 're2_revision': '891fa668468f201f6a0c16bbff76f26d8ae59e82', 'spirv_headers_revision': 'aa331ab0ffcb3a67021caa1a0c1c9017712f2f31', } From e150e716ff57dd69cf31d45344121f10de8925af Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 14 Feb 2023 04:04:34 +0000 Subject: [PATCH 048/523] roll deps (#5110) * Roll external/googletest/ b73f27fd1..b80a07ffe (1 commit) https://github.com/google/googletest/compare/b73f27fd1644...b80a07ffe627 $ git log b73f27fd1..b80a07ffe --date=short --no-merges --format='%ad %ae %s' 2023-02-13 absl-team Avoid reliance on header without RTTI on MSVC Created with: roll-dep external/googletest * Roll external/re2/ 891fa6684..9049cd28d (2 commits) https://github.com/google/re2/compare/891fa668468f...9049cd28d749 $ git log 891fa6684..9049cd28d --date=short --no-merges --format='%ad %ae %s' 2023-02-13 junyer Add the `RE2_BUILD_FRAMEWORK` option to build RE2 as a framework. 2023-02-13 junyer Use `PUBLIC_HEADER` to install headers. 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 7ac6e6d927..6b6f61affc 100644 --- a/DEPS +++ b/DEPS @@ -5,12 +5,12 @@ vars = { 'effcee_revision': 'c7b4db79f340f7a9981e8a484f6d5785e24242d1', - 'googletest_revision': 'b73f27fd164456fea9aba56163f5511355a03272', + 'googletest_revision': 'b80a07ffe627b20781516f51c548367d1e4d57dd', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', - 're2_revision': '891fa668468f201f6a0c16bbff76f26d8ae59e82', + 're2_revision': '9049cd28d7496e05e7b7beaec89291d8bc6a31ee', 'spirv_headers_revision': 'aa331ab0ffcb3a67021caa1a0c1c9017712f2f31', } From b84c86f718b07f0ece7f4ba2120604c13d8218f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 14 Feb 2023 20:08:20 +0100 Subject: [PATCH 049/523] libspirv.cpp: adds c++ api for spvBinaryParse (#5109) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a C++ wrapper above the current spvBinaryParse function. I tried to match it 1:1, except for 2 things: - std::function<>& are used. No more function pointers, allowing context capture. - spv_result_t replaced with a boolean, to match other C++ apis. Callbacks still return a spv_result_t because the underlying implem relies on that. The convertion from spv_result_t to boolean is only done at the boundary. Signed-off-by: Nathan Gauër --- include/spirv-tools/libspirv.h | 13 ++ include/spirv-tools/libspirv.hpp | 22 +++ source/libspirv.cpp | 34 ++++ test/binary_parse_test.cpp | 300 +++++++++++++++++++++++++++++++ 4 files changed, 369 insertions(+) diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index 84a7726e78..542b745327 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -402,6 +402,19 @@ typedef struct spv_parsed_instruction_t { uint16_t num_operands; } spv_parsed_instruction_t; +typedef struct spv_parsed_header_t { + // The magic number of the SPIR-V module. + uint32_t magic; + // Version number. + uint32_t version; + // Generator's magic number. + uint32_t generator; + // IDs bound for this module (0 < id < bound). + uint32_t bound; + // reserved. + uint32_t reserved; +} spv_parsed_header_t; + typedef struct spv_const_binary_t { const uint32_t* code; const size_t wordCount; diff --git a/include/spirv-tools/libspirv.hpp b/include/spirv-tools/libspirv.hpp index 408e3ebb23..ee6c8469a0 100644 --- a/include/spirv-tools/libspirv.hpp +++ b/include/spirv-tools/libspirv.hpp @@ -31,6 +31,11 @@ using MessageConsumer = std::function; +using HeaderParser = std::function; +using InstructionParser = + std::function; + // C++ RAII wrapper around the C context object spv_context. class Context { public: @@ -336,6 +341,23 @@ class SpirvTools { std::string* text, uint32_t options = kDefaultDisassembleOption) const; + // Parses a SPIR-V binary, specified as counted sequence of 32-bit words. + // Parsing feedback is provided via two callbacks provided as std::function. + // In a valid parse the parsed-header callback is called once, and + // then the parsed-instruction callback is called once for each instruction + // in the stream. + // Returns true on successful parsing. + // If diagnostic is non-null, a diagnostic is emitted on failed parsing. + // If diagnostic is null the context's message consumer + // will be used to emit any errors. If a callback returns anything other than + // SPV_SUCCESS, then that status code is returned, no further callbacks are + // issued, and no additional diagnostics are emitted. + // This is a wrapper around the C API spvBinaryParse. + bool Parse(const std::vector& binary, + const HeaderParser& header_parser, + const InstructionParser& instruction_parser, + spv_diagnostic* diagnostic = nullptr); + // Validates the given SPIR-V |binary|. Returns true if no issues are found. // Otherwise, returns false and communicates issues via the message consumer // registered. diff --git a/source/libspirv.cpp b/source/libspirv.cpp index be76caaa8b..83e8629b70 100644 --- a/source/libspirv.cpp +++ b/source/libspirv.cpp @@ -108,6 +108,40 @@ bool SpirvTools::Disassemble(const uint32_t* binary, const size_t binary_size, return status == SPV_SUCCESS; } +struct CxxParserContext { + const HeaderParser& header_parser; + const InstructionParser& instruction_parser; +}; + +bool SpirvTools::Parse(const std::vector& binary, + const HeaderParser& header_parser, + const InstructionParser& instruction_parser, + spv_diagnostic* diagnostic) { + CxxParserContext parser_context = {header_parser, instruction_parser}; + + spv_parsed_header_fn_t header_fn_wrapper = + [](void* user_data, spv_endianness_t endianness, uint32_t magic, + uint32_t version, uint32_t generator, uint32_t id_bound, + uint32_t reserved) { + CxxParserContext* ctx = reinterpret_cast(user_data); + spv_parsed_header_t header = {magic, version, generator, id_bound, + reserved}; + + return ctx->header_parser(endianness, header); + }; + + spv_parsed_instruction_fn_t instruction_fn_wrapper = + [](void* user_data, const spv_parsed_instruction_t* instruction) { + CxxParserContext* ctx = reinterpret_cast(user_data); + return ctx->instruction_parser(*instruction); + }; + + spv_result_t status = spvBinaryParse( + impl_->context, &parser_context, binary.data(), binary.size(), + header_fn_wrapper, instruction_fn_wrapper, diagnostic); + return status == SPV_SUCCESS; +} + bool SpirvTools::Validate(const std::vector& binary) const { return Validate(binary.data(), binary.size()); } diff --git a/test/binary_parse_test.cpp b/test/binary_parse_test.cpp index 4c699c1759..50710cd131 100644 --- a/test/binary_parse_test.cpp +++ b/test/binary_parse_test.cpp @@ -214,6 +214,40 @@ class BinaryParseTest : public spvtest::TextToBinaryTestBase<::testing::Test> { MockParseClient client_; }; +class CxxBinaryParseTest + : public spvtest::TextToBinaryTestBase<::testing::Test> { + protected: + CxxBinaryParseTest() { + header_parser_ = [this](const spv_endianness_t endianness, + const spv_parsed_header_t& header) { + return this->client_.Header(endianness, header.magic, header.version, + header.generator, header.bound, + header.reserved); + }; + + instruction_parser_ = [this](const spv_parsed_instruction_t& instruction) { + return this->client_.Instruction(ParsedInstruction(instruction)); + }; + } + + ~CxxBinaryParseTest() override { spvDiagnosticDestroy(diagnostic_); } + + void Parse(const SpirvVector& words, bool expected_result, + bool flip_words = false, + spv_target_env env = SPV_ENV_UNIVERSAL_1_0) { + SpirvVector flipped_words(words); + MaybeFlipWords(flip_words, flipped_words.begin(), flipped_words.end()); + spvtools::SpirvTools tools(env); + EXPECT_EQ(expected_result, tools.Parse(flipped_words, header_parser_, + instruction_parser_, &diagnostic_)); + } + + spv_diagnostic diagnostic_ = nullptr; + MockParseClient client_; + HeaderParser header_parser_; + InstructionParser instruction_parser_; +}; + // Adds an EXPECT_CALL to client_->Header() with appropriate parameters, // including bound. Returns the EXPECT_CALL result. #define EXPECT_HEADER(bound) \ @@ -235,6 +269,16 @@ TEST_F(BinaryParseTest, EmptyModuleHasValidHeaderAndNoInstructionCallbacks) { } } +TEST_F(CxxBinaryParseTest, EmptyModuleHasValidHeaderAndNoInstructionCallbacks) { + for (bool endian_swap : kSwapEndians) { + const auto words = CompileSuccessfully(""); + EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS)); + EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback. + Parse(words, true, endian_swap); + EXPECT_EQ(nullptr, diagnostic_); + } +} + TEST_F(BinaryParseTest, NullDiagnosticsIsOkForGoodParse) { const auto words = CompileSuccessfully(""); EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS)); @@ -245,6 +289,15 @@ TEST_F(BinaryParseTest, NullDiagnosticsIsOkForGoodParse) { words.size(), invoke_header, invoke_instruction, nullptr)); } +TEST_F(CxxBinaryParseTest, NullDiagnosticsIsOkForGoodParse) { + const auto words = CompileSuccessfully(""); + EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS)); + EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback. + spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_0); + EXPECT_EQ(true, + tools.Parse(words, header_parser_, instruction_parser_, nullptr)); +} + TEST_F(BinaryParseTest, NullDiagnosticsIsOkForBadParse) { auto words = CompileSuccessfully(""); words.push_back(0xffffffff); // Certainly invalid instruction header. @@ -256,6 +309,16 @@ TEST_F(BinaryParseTest, NullDiagnosticsIsOkForBadParse) { words.size(), invoke_header, invoke_instruction, nullptr)); } +TEST_F(CxxBinaryParseTest, NullDiagnosticsIsOkForBadParse) { + auto words = CompileSuccessfully(""); + words.push_back(0xffffffff); // Certainly invalid instruction header. + EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS)); + EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback. + spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_0); + EXPECT_EQ(false, + tools.Parse(words, header_parser_, instruction_parser_, nullptr)); +} + // Make sure that we don't blow up when both the consumer and the diagnostic are // null. TEST_F(BinaryParseTest, NullConsumerNullDiagnosticsForBadParse) { @@ -272,6 +335,18 @@ TEST_F(BinaryParseTest, NullConsumerNullDiagnosticsForBadParse) { invoke_header, invoke_instruction, nullptr)); } +TEST_F(CxxBinaryParseTest, NullConsumerNullDiagnosticsForBadParse) { + spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_1); + tools.SetMessageConsumer(nullptr); + + auto words = CompileSuccessfully(""); + words.push_back(0xffffffff); // Certainly invalid instruction header. + EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS)); + EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback. + EXPECT_EQ(false, + tools.Parse(words, header_parser_, instruction_parser_, nullptr)); +} + TEST_F(BinaryParseTest, SpecifyConsumerNullDiagnosticsForGoodParse) { const auto words = CompileSuccessfully(""); @@ -289,6 +364,21 @@ TEST_F(BinaryParseTest, SpecifyConsumerNullDiagnosticsForGoodParse) { EXPECT_EQ(0, invocation); } +TEST_F(CxxBinaryParseTest, SpecifyConsumerNullDiagnosticsForGoodParse) { + const auto words = CompileSuccessfully(""); + spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_1); + int invocation = 0; + tools.SetMessageConsumer([&invocation](spv_message_level_t, const char*, + const spv_position_t&, + const char*) { ++invocation; }); + + EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS)); + EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback. + EXPECT_EQ(true, + tools.Parse(words, header_parser_, instruction_parser_, nullptr)); + EXPECT_EQ(0, invocation); +} + TEST_F(BinaryParseTest, SpecifyConsumerNullDiagnosticsForBadParse) { auto words = CompileSuccessfully(""); @@ -315,6 +405,30 @@ TEST_F(BinaryParseTest, SpecifyConsumerNullDiagnosticsForBadParse) { EXPECT_EQ(1, invocation); } +TEST_F(CxxBinaryParseTest, SpecifyConsumerNullDiagnosticsForBadParse) { + auto words = CompileSuccessfully(""); + spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_1); + int invocation = 0; + tools.SetMessageConsumer( + [&invocation](spv_message_level_t level, const char* source, + const spv_position_t& position, const char* message) { + ++invocation; + EXPECT_EQ(SPV_MSG_ERROR, level); + EXPECT_STREQ("input", source); + EXPECT_EQ(0u, position.line); + EXPECT_EQ(0u, position.column); + EXPECT_EQ(1u, position.index); + EXPECT_STREQ("Invalid opcode: 65535", message); + }); + + words.push_back(0xffffffff); // Certainly invalid instruction header. + EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS)); + EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback. + EXPECT_EQ(false, + tools.Parse(words, header_parser_, instruction_parser_, nullptr)); + EXPECT_EQ(1, invocation); +} + TEST_F(BinaryParseTest, SpecifyConsumerSpecifyDiagnosticsForGoodParse) { const auto words = CompileSuccessfully(""); @@ -333,6 +447,22 @@ TEST_F(BinaryParseTest, SpecifyConsumerSpecifyDiagnosticsForGoodParse) { EXPECT_EQ(nullptr, diagnostic_); } +TEST_F(CxxBinaryParseTest, SpecifyConsumerSpecifyDiagnosticsForGoodParse) { + const auto words = CompileSuccessfully(""); + spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_1); + int invocation = 0; + tools.SetMessageConsumer([&invocation](spv_message_level_t, const char*, + const spv_position_t&, + const char*) { ++invocation; }); + + EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS)); + EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback. + EXPECT_EQ(true, tools.Parse(words, header_parser_, instruction_parser_, + &diagnostic_)); + EXPECT_EQ(0, invocation); + EXPECT_EQ(nullptr, diagnostic_); +} + TEST_F(BinaryParseTest, SpecifyConsumerSpecifyDiagnosticsForBadParse) { auto words = CompileSuccessfully(""); @@ -352,6 +482,23 @@ TEST_F(BinaryParseTest, SpecifyConsumerSpecifyDiagnosticsForBadParse) { EXPECT_STREQ("Invalid opcode: 65535", diagnostic_->error); } +TEST_F(CxxBinaryParseTest, SpecifyConsumerSpecifyDiagnosticsForBadParse) { + auto words = CompileSuccessfully(""); + spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_1); + int invocation = 0; + tools.SetMessageConsumer([&invocation](spv_message_level_t, const char*, + const spv_position_t&, + const char*) { ++invocation; }); + + words.push_back(0xffffffff); // Certainly invalid instruction header. + EXPECT_HEADER(1).WillOnce(Return(SPV_SUCCESS)); + EXPECT_CALL(client_, Instruction(_)).Times(0); // No instruction callback. + EXPECT_EQ(false, tools.Parse(words, header_parser_, instruction_parser_, + &diagnostic_)); + EXPECT_EQ(0, invocation); + EXPECT_STREQ("Invalid opcode: 65535", diagnostic_->error); +} + TEST_F(BinaryParseTest, ModuleWithSingleInstructionHasValidHeaderAndInstructionCallback) { for (bool endian_swap : kSwapEndians) { @@ -365,6 +512,19 @@ TEST_F(BinaryParseTest, } } +TEST_F(CxxBinaryParseTest, + ModuleWithSingleInstructionHasValidHeaderAndInstructionCallback) { + for (bool endian_swap : kSwapEndians) { + const auto words = CompileSuccessfully("%1 = OpTypeVoid"); + InSequence calls_expected_in_specific_order; + EXPECT_HEADER(2).WillOnce(Return(SPV_SUCCESS)); + EXPECT_CALL(client_, Instruction(MakeParsedVoidTypeInstruction(1))) + .WillOnce(Return(SPV_SUCCESS)); + Parse(words, true, endian_swap); + EXPECT_EQ(nullptr, diagnostic_); + } +} + TEST_F(BinaryParseTest, NullHeaderCallbackIsIgnored) { const auto words = CompileSuccessfully("%1 = OpTypeVoid"); EXPECT_CALL(client_, Header(_, _, _, _, _, _)) @@ -408,6 +568,22 @@ TEST_F(BinaryParseTest, TwoScalarTypesGenerateTwoInstructionCallbacks) { } } +TEST_F(CxxBinaryParseTest, TwoScalarTypesGenerateTwoInstructionCallbacks) { + for (bool endian_swap : kSwapEndians) { + const auto words = CompileSuccessfully( + "%1 = OpTypeVoid " + "%2 = OpTypeInt 32 1"); + InSequence calls_expected_in_specific_order; + EXPECT_HEADER(3).WillOnce(Return(SPV_SUCCESS)); + EXPECT_CALL(client_, Instruction(MakeParsedVoidTypeInstruction(1))) + .WillOnce(Return(SPV_SUCCESS)); + EXPECT_CALL(client_, Instruction(MakeParsedInt32TypeInstruction(2))) + .WillOnce(Return(SPV_SUCCESS)); + Parse(words, true, endian_swap); + EXPECT_EQ(nullptr, diagnostic_); + } +} + TEST_F(BinaryParseTest, EarlyReturnWithZeroPassingCallbacks) { for (bool endian_swap : kSwapEndians) { const auto words = CompileSuccessfully( @@ -423,6 +599,21 @@ TEST_F(BinaryParseTest, EarlyReturnWithZeroPassingCallbacks) { } } +TEST_F(CxxBinaryParseTest, EarlyReturnWithZeroPassingCallbacks) { + for (bool endian_swap : kSwapEndians) { + const auto words = CompileSuccessfully( + "%1 = OpTypeVoid " + "%2 = OpTypeInt 32 1"); + InSequence calls_expected_in_specific_order; + EXPECT_HEADER(3).WillOnce(Return(SPV_ERROR_INVALID_BINARY)); + // Early exit means no calls to Instruction(). + EXPECT_CALL(client_, Instruction(_)).Times(0); + Parse(words, false, endian_swap); + // On error, the binary parser doesn't generate its own diagnostics. + EXPECT_EQ(nullptr, diagnostic_); + } +} + TEST_F(BinaryParseTest, EarlyReturnWithZeroPassingCallbacksAndSpecifiedResultCode) { for (bool endian_swap : kSwapEndians) { @@ -440,6 +631,23 @@ TEST_F(BinaryParseTest, } } +TEST_F(CxxBinaryParseTest, + EarlyReturnWithZeroPassingCallbacksAndSpecifiedResultCode) { + for (bool endian_swap : kSwapEndians) { + const auto words = CompileSuccessfully( + "%1 = OpTypeVoid " + "%2 = OpTypeInt 32 1"); + InSequence calls_expected_in_specific_order; + EXPECT_HEADER(3).WillOnce(Return(SPV_REQUESTED_TERMINATION)); + // Early exit means no calls to Instruction(). + EXPECT_CALL(client_, Instruction(_)).Times(0); + Parse(words, false, endian_swap); + // On early termination, the binary parser doesn't generate its own + // diagnostics. + EXPECT_EQ(nullptr, diagnostic_); + } +} + TEST_F(BinaryParseTest, EarlyReturnWithOnePassingCallback) { for (bool endian_swap : kSwapEndians) { const auto words = CompileSuccessfully( @@ -457,6 +665,23 @@ TEST_F(BinaryParseTest, EarlyReturnWithOnePassingCallback) { } } +TEST_F(CxxBinaryParseTest, EarlyReturnWithOnePassingCallback) { + for (bool endian_swap : kSwapEndians) { + const auto words = CompileSuccessfully( + "%1 = OpTypeVoid " + "%2 = OpTypeInt 32 1 " + "%3 = OpTypeFloat 32"); + InSequence calls_expected_in_specific_order; + EXPECT_HEADER(4).WillOnce(Return(SPV_SUCCESS)); + EXPECT_CALL(client_, Instruction(MakeParsedVoidTypeInstruction(1))) + .WillOnce(Return(SPV_REQUESTED_TERMINATION)); + Parse(words, false, endian_swap); + // On early termination, the binary parser doesn't generate its own + // diagnostics. + EXPECT_EQ(nullptr, diagnostic_); + } +} + TEST_F(BinaryParseTest, EarlyReturnWithTwoPassingCallbacks) { for (bool endian_swap : kSwapEndians) { const auto words = CompileSuccessfully( @@ -476,6 +701,25 @@ TEST_F(BinaryParseTest, EarlyReturnWithTwoPassingCallbacks) { } } +TEST_F(CxxBinaryParseTest, EarlyReturnWithTwoPassingCallbacks) { + for (bool endian_swap : kSwapEndians) { + const auto words = CompileSuccessfully( + "%1 = OpTypeVoid " + "%2 = OpTypeInt 32 1 " + "%3 = OpTypeFloat 32"); + InSequence calls_expected_in_specific_order; + EXPECT_HEADER(4).WillOnce(Return(SPV_SUCCESS)); + EXPECT_CALL(client_, Instruction(MakeParsedVoidTypeInstruction(1))) + .WillOnce(Return(SPV_SUCCESS)); + EXPECT_CALL(client_, Instruction(MakeParsedInt32TypeInstruction(2))) + .WillOnce(Return(SPV_REQUESTED_TERMINATION)); + Parse(words, false, endian_swap); + // On early termination, the binary parser doesn't generate its own + // diagnostics. + EXPECT_EQ(nullptr, diagnostic_); + } +} + TEST_F(BinaryParseTest, InstructionWithStringOperand) { for (bool endian_swap : kSwapEndians) { const std::string str = @@ -501,6 +745,31 @@ TEST_F(BinaryParseTest, InstructionWithStringOperand) { } } +TEST_F(CxxBinaryParseTest, InstructionWithStringOperand) { + for (bool endian_swap : kSwapEndians) { + const std::string str = + "the future is already here, it's just not evenly distributed"; + const auto str_words = MakeVector(str); + const auto instruction = MakeInstruction(spv::Op::OpName, {99}, str_words); + const auto words = Concatenate({ExpectedHeaderForBound(100), instruction}); + InSequence calls_expected_in_specific_order; + EXPECT_HEADER(100).WillOnce(Return(SPV_SUCCESS)); + const auto operands = std::vector{ + MakeSimpleOperand(1, SPV_OPERAND_TYPE_ID), + MakeLiteralStringOperand(2, static_cast(str_words.size()))}; + EXPECT_CALL( + client_, + Instruction(ParsedInstruction(spv_parsed_instruction_t{ + instruction.data(), static_cast(instruction.size()), + uint16_t(spv::Op::OpName), SPV_EXT_INST_TYPE_NONE, 0 /*type id*/, + 0 /* No result id for OpName*/, operands.data(), + static_cast(operands.size())}))) + .WillOnce(Return(SPV_SUCCESS)); + Parse(words, true, endian_swap); + EXPECT_EQ(nullptr, diagnostic_); + } +} + // Checks for non-zero values for the result_id and ext_inst_type members // spv_parsed_instruction_t. TEST_F(BinaryParseTest, ExtendedInstruction) { @@ -534,6 +803,37 @@ TEST_F(BinaryParseTest, ExtendedInstruction) { EXPECT_EQ(nullptr, diagnostic_); } +TEST_F(CxxBinaryParseTest, ExtendedInstruction) { + const auto words = CompileSuccessfully( + "%extcl = OpExtInstImport \"OpenCL.std\" " + "%result = OpExtInst %float %extcl sqrt %x"); + EXPECT_HEADER(5).WillOnce(Return(SPV_SUCCESS)); + EXPECT_CALL(client_, Instruction(_)).WillOnce(Return(SPV_SUCCESS)); + // We're only interested in the second call to Instruction(): + const auto operands = std::vector{ + MakeSimpleOperand(1, SPV_OPERAND_TYPE_TYPE_ID), + MakeSimpleOperand(2, SPV_OPERAND_TYPE_RESULT_ID), + MakeSimpleOperand(3, + SPV_OPERAND_TYPE_ID), // Extended instruction set Id + MakeSimpleOperand(4, SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER), + MakeSimpleOperand(5, SPV_OPERAND_TYPE_ID), // Id of the argument + }; + const auto instruction = MakeInstruction( + spv::Op::OpExtInst, + {2, 3, 1, static_cast(OpenCLLIB::Entrypoints::Sqrt), 4}); + EXPECT_CALL(client_, + Instruction(ParsedInstruction(spv_parsed_instruction_t{ + instruction.data(), static_cast(instruction.size()), + uint16_t(spv::Op::OpExtInst), SPV_EXT_INST_TYPE_OPENCL_STD, + 2 /*type id*/, 3 /*result id*/, operands.data(), + static_cast(operands.size())}))) + .WillOnce(Return(SPV_SUCCESS)); + // Since we are actually checking the output, don't test the + // endian-swapped version. + Parse(words, true, false); + EXPECT_EQ(nullptr, diagnostic_); +} + // A binary parser diagnostic test case where we provide the words array // pointer and word count explicitly. struct WordsAndCountDiagnosticCase { From 95f93810bbae12e1a601a3a5a5d975e5558a2994 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 15 Feb 2023 12:11:14 +0000 Subject: [PATCH 050/523] Roll external/googletest/ b80a07ffe..2057566e4 (1 commit) (#5112) https://github.com/google/googletest/compare/b80a07ffe627...2057566e4e16 $ git log b80a07ffe..2057566e4 --date=short --no-merges --format='%ad %ae %s' 2023-02-14 absl-team Remove some filesystem APIs and tests under !GTEST_HAS_FILE_SYSTEM 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 6b6f61affc..6e40c58667 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': 'c7b4db79f340f7a9981e8a484f6d5785e24242d1', - 'googletest_revision': 'b80a07ffe627b20781516f51c548367d1e4d57dd', + 'googletest_revision': '2057566e4e16c88f1fea4d6c96b2e2bfb87507a6', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From f4343515ad73f68718429d2bb9b3a64a8fc7c15e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Petit?= Date: Wed, 15 Feb 2023 20:09:55 +0000 Subject: [PATCH 051/523] Remove duplicate lists of constant and type opcodes (#5106) Adding a new type instruction required making the same change in two places. Also remove IsCompileTimeConstantInst that was used in a single place and replace its use by an expression that better conveys the intent. Change-Id: I49330b74bd34a35db6369c438c053224805c18e0 Signed-off-by: Kevin Petit --- source/opcode.cpp | 1 + source/opt/instruction.h | 2 +- source/opt/reflect.h | 21 ++++----------------- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/source/opcode.cpp b/source/opcode.cpp index b1785cccce..d26024abb4 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -240,6 +240,7 @@ int32_t spvOpcodeIsConstant(const spv::Op opcode) { case spv::Op::OpConstantComposite: case spv::Op::OpConstantSampler: case spv::Op::OpConstantNull: + case spv::Op::OpConstantFunctionPointerINTEL: case spv::Op::OpSpecConstantTrue: case spv::Op::OpSpecConstantFalse: case spv::Op::OpSpecConstant: diff --git a/source/opt/instruction.h b/source/opt/instruction.h index 22736bff89..d50e625177 100644 --- a/source/opt/instruction.h +++ b/source/opt/instruction.h @@ -906,7 +906,7 @@ bool Instruction::IsAtomicWithLoad() const { bool Instruction::IsAtomicOp() const { return spvOpcodeIsAtomicOp(opcode()); } bool Instruction::IsConstant() const { - return IsCompileTimeConstantInst(opcode()); + return IsConstantInst(opcode()) && !IsSpecConstantInst(opcode()); } } // namespace opt } // namespace spvtools diff --git a/source/opt/reflect.h b/source/opt/reflect.h index 45bb5c57c0..aaa4c63d36 100644 --- a/source/opt/reflect.h +++ b/source/opt/reflect.h @@ -46,27 +46,14 @@ inline bool IsAnnotationInst(spv::Op opcode) { opcode == spv::Op::OpMemberDecorateStringGOOGLE; } inline bool IsTypeInst(spv::Op opcode) { - return (opcode >= spv::Op::OpTypeVoid && - opcode <= spv::Op::OpTypeForwardPointer) || - opcode == spv::Op::OpTypePipeStorage || - opcode == spv::Op::OpTypeNamedBarrier || - opcode == spv::Op::OpTypeAccelerationStructureNV || - opcode == spv::Op::OpTypeAccelerationStructureKHR || - opcode == spv::Op::OpTypeRayQueryKHR || - opcode == spv::Op::OpTypeCooperativeMatrixNV || - opcode == spv::Op::OpTypeHitObjectNV; + return spvOpcodeGeneratesType(opcode) || + opcode == spv::Op::OpTypeForwardPointer; } inline bool IsConstantInst(spv::Op opcode) { - return (opcode >= spv::Op::OpConstantTrue && - opcode <= spv::Op::OpSpecConstantOp) || - opcode == spv::Op::OpConstantFunctionPointerINTEL; -} -inline bool IsCompileTimeConstantInst(spv::Op opcode) { - return opcode >= spv::Op::OpConstantTrue && opcode <= spv::Op::OpConstantNull; + return spvOpcodeIsConstant(opcode); } inline bool IsSpecConstantInst(spv::Op opcode) { - return opcode >= spv::Op::OpSpecConstantTrue && - opcode <= spv::Op::OpSpecConstantOp; + return spvOpcodeIsSpecConstant(opcode); } } // namespace opt From 956114df28aabc899696f6843c67eb821bd82864 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 16 Feb 2023 06:11:30 +1000 Subject: [PATCH 052/523] opt: fix spirv ABI on Linux again. (#5113) Breaking the ABI for this API isn't worth it when the fix is so simple. --- include/spirv-tools/optimizer.hpp | 6 ++++-- source/opt/optimizer.cpp | 10 ++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp index aa6a614ea6..8bdd4e8268 100644 --- a/include/spirv-tools/optimizer.hpp +++ b/include/spirv-tools/optimizer.hpp @@ -525,8 +525,10 @@ Optimizer::PassToken CreateDeadInsertElimPass(); // If |remove_outputs| is true, allow outputs to be removed from the interface. // This is only safe if the caller knows that there is no corresponding input // variable in the following shader. It is false by default. -Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface = false, - bool remove_outputs = false); +Optimizer::PassToken CreateAggressiveDCEPass(); +Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface); +Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface, + bool remove_outputs); // Creates a remove-unused-interface-variables pass. // Removes variables referenced on the |OpEntryPoint| instruction that are not diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index cbc4b82f77..46a92dd90e 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -785,6 +785,16 @@ Optimizer::PassToken CreateLocalMultiStoreElimPass() { MakeUnique()); } +Optimizer::PassToken CreateAggressiveDCEPass() { + return MakeUnique( + MakeUnique(false, false)); +} + +Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface) { + return MakeUnique( + MakeUnique(preserve_interface, false)); +} + Optimizer::PassToken CreateAggressiveDCEPass(bool preserve_interface, bool remove_outputs) { return MakeUnique( From c9947cc8d5e421c876c39947f9a4f35a84cf5733 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 16 Feb 2023 13:11:36 +0000 Subject: [PATCH 053/523] Roll external/googletest/ 2057566e4..f063cd25c (1 commit) (#5115) https://github.com/google/googletest/compare/2057566e4e16...f063cd25c90c $ git log 2057566e4..f063cd25c --date=short --no-merges --format='%ad %ae %s' 2023-02-15 absl-team Remove strdup usage 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 6e40c58667..9cd1b3b13b 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': 'c7b4db79f340f7a9981e8a484f6d5785e24242d1', - 'googletest_revision': '2057566e4e16c88f1fea4d6c96b2e2bfb87507a6', + 'googletest_revision': 'f063cd25c90cbd4089a0ff96f5991df4f2721338', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From 69ed5adf108fbd9860f8bcab69b6e80767b8c5aa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 17 Feb 2023 14:45:07 +0000 Subject: [PATCH 054/523] Roll external/googletest/ f063cd25c..7a7231c44 (1 commit) (#5116) https://github.com/google/googletest/compare/f063cd25c90c...7a7231c44248 $ git log f063cd25c..7a7231c44 --date=short --no-merges --format='%ad %ae %s' 2023-02-16 absl-team Fix link in ReportUninterestingCall message 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 9cd1b3b13b..4a0fd5550f 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': 'c7b4db79f340f7a9981e8a484f6d5785e24242d1', - 'googletest_revision': 'f063cd25c90cbd4089a0ff96f5991df4f2721338', + 'googletest_revision': '7a7231c442484be389fdf01594310349ca0e42a8', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From 987a5f1367e5db5b8eba82018b7250ec58606099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 20 Feb 2023 11:11:16 +0100 Subject: [PATCH 055/523] build: change the way we set cxx version for bazel. (#5114) Before, we did set cxx version to c++17 using COPTS in our bazel files. This was wrong, and part of the dependencies were then built with the default standard version. This was not an issue until we moved to c++17. Then, we decided to use the bazel --cxxopt=-std=c++17, but this was only valid for nix platforms. The last option left is to ask the user to specify the standard when building using bazel. --- .bazelrc | 1 - .github/workflows/bazel.yml | 16 ++++++++++++---- README.md | 18 ++++++++++++++++-- kokoro/macos-clang-release-bazel/build.sh | 4 ++-- kokoro/scripts/linux/build-docker.sh | 4 ++-- 5 files changed, 32 insertions(+), 11 deletions(-) delete mode 100644 .bazelrc diff --git a/.bazelrc b/.bazelrc deleted file mode 100644 index 5b3d13f534..0000000000 --- a/.bazelrc +++ /dev/null @@ -1 +0,0 @@ -build --cxxopt=-std=c++17 diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 77ef657568..dfb5e5ae32 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -26,7 +26,15 @@ jobs: with: path: ~/.bazel/cache key: bazel-cache-${{ runner.os }} - - name: Build All - run: bazel --output_user_root=~/.bazel/cache build //... - - name: Test All - run: bazel --output_user_root=~/.bazel/cache test //... + - name: Build All (Windows) + if: ${{matrix.os == 'windows-latest' }} + run: bazel --output_user_root=~/.bazel/cache build --cxxopt=/std:c++17 //... + - name: Test All (Windows) + if: ${{matrix.os == 'windows-latest' }} + run: bazel --output_user_root=~/.bazel/cache test --cxxopt=/std:c++17 //... + - name: Build All (Linux, MacOS) + if: ${{ matrix.os != 'windows-latest' }} + run: bazel --output_user_root=~/.bazel/cache build --cxxopt=-std=c++17 //... + - name: Test All (Linux, MacOS) + if: ${{ matrix.os != 'windows-latest' }} + run: bazel --output_user_root=~/.bazel/cache test --cxxopt=-std=c++17 //... diff --git a/README.md b/README.md index baa44e7077..92e4d3c06d 100644 --- a/README.md +++ b/README.md @@ -380,10 +380,18 @@ fuzzer tests. ### Build using Bazel You can also use [Bazel](https://bazel.build/) to build the project. + +On linux: ```sh cd -bazel build :all +bazel build --cxxopt=-std=c++17 :all +``` + +On windows: +```sh +bazel build --cxxopt=/std:c++17 :all ``` + ### Build a node.js package using Emscripten The SPIRV-Tools core library can be built to a WebAssembly [node.js](https://nodejs.org) @@ -723,10 +731,16 @@ Use `bazel test :all` to run all tests. This will run tests in parallel by defau To run a single test target, specify `:my_test_target` instead of `:all`. Test target names get printed when you run `bazel test :all`. For example, you can run `opt_def_use_test` with: + +on linux: ```shell -bazel test :opt_def_use_test +bazel test --cxxopt=-std=c++17 :opt_def_use_test ``` +on windows: +```shell +bazel test --cxxopt=/std:c++17 :opt_def_use_test +``` ## Future Work diff --git a/kokoro/macos-clang-release-bazel/build.sh b/kokoro/macos-clang-release-bazel/build.sh index 50ad42bc81..2465d9c602 100644 --- a/kokoro/macos-clang-release-bazel/build.sh +++ b/kokoro/macos-clang-release-bazel/build.sh @@ -41,9 +41,9 @@ gsutil cp gs://bazel/5.0.0/release/bazel-5.0.0-darwin-x86_64 . chmod +x bazel-5.0.0-darwin-x86_64 echo $(date): Build everything... -./bazel-5.0.0-darwin-x86_64 build :all +./bazel-5.0.0-darwin-x86_64 build --cxxopt=-std=c++17 :all echo $(date): Build completed. echo $(date): Starting bazel test... -./bazel-5.0.0-darwin-x86_64 test :all +./bazel-5.0.0-darwin-x86_64 test --cxxopt=-std=c++17 :all echo $(date): Bazel test completed. diff --git a/kokoro/scripts/linux/build-docker.sh b/kokoro/scripts/linux/build-docker.sh index 52fbb9e4bb..6bd71ce864 100755 --- a/kokoro/scripts/linux/build-docker.sh +++ b/kokoro/scripts/linux/build-docker.sh @@ -191,10 +191,10 @@ elif [ $TOOL = "bazel" ]; then using bazel-5.0.0 echo $(date): Build everything... - bazel build :all + bazel build --cxxopt=-std=c++17 :all echo $(date): Build completed. echo $(date): Starting bazel test... - bazel test :all + bazel test --cxxopt=-std=c++17 :all echo $(date): Bazel test completed. fi From 8bcaad28f73498b9471cd642dd0203b6d0e1756b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 21 Feb 2023 13:44:37 +0000 Subject: [PATCH 056/523] Roll external/re2/ 9049cd28d..3a8436ac4 (1 commit) (#5117) https://github.com/google/re2/compare/9049cd28d749...3a8436ac4361 $ git log 9049cd28d..3a8436ac4 --date=short --no-merges --format='%ad %ae %s' 2023-02-20 junyer Fuzz `RE2::Set` and `FilteredRE2`. 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 4a0fd5550f..b10be9ca82 100644 --- a/DEPS +++ b/DEPS @@ -10,7 +10,7 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', - 're2_revision': '9049cd28d7496e05e7b7beaec89291d8bc6a31ee', + 're2_revision': '3a8436ac436124a57a4e22d5c8713a2d42b381d7', 'spirv_headers_revision': 'aa331ab0ffcb3a67021caa1a0c1c9017712f2f31', } From 9017cfcf6286e6b37552828cdf6ca0b62a030e47 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 22 Feb 2023 11:23:34 +0000 Subject: [PATCH 057/523] Roll external/googletest/ 7a7231c44..750d67d80 (1 commit) (#5119) https://github.com/google/googletest/compare/7a7231c44248...750d67d80970 $ git log 7a7231c44..750d67d80 --date=short --no-merges --format='%ad %ae %s' 2023-02-21 tomhughes Remove int64_t cast in RecordProperty 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 b10be9ca82..db0a1df852 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': 'c7b4db79f340f7a9981e8a484f6d5785e24242d1', - 'googletest_revision': '7a7231c442484be389fdf01594310349ca0e42a8', + 'googletest_revision': '750d67d809700ae8fca6d610f7b41b71aa161808', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From 2cf48e95341db788355bc347f0b092115bec8819 Mon Sep 17 00:00:00 2001 From: Bruce Dawson Date: Wed, 22 Feb 2023 19:24:34 -0800 Subject: [PATCH 058/523] Allow invoking git.bat as git on Windows (#5118) In a Chromium build environment on Windows git is supplied by depot_tools as git.bat. This was causing build errors on Windows that are most easily reproduced with this command: gn gen out\default && gn clean out\default && ninja -C out\default spirv-as The errors included: [12:55:40][ERROR ] Failed to run "['git', 'tag', '--sort=-v:refname']" in "C:\src\chromium\src\third_party\vulkan-deps\spirv-tools\src": [WinError 2] The system cannot find the file specified [12:55:40][WARNING ] Could not deduce latest release version from history. This is because 'git' does not resolve to git.bat unless shell=True is passed to subprocess.Popen. This change passes shell=True but only on Windows which resolves these errors. --- utils/update_build_version.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/utils/update_build_version.py b/utils/update_build_version.py index ec475ea4e5..871036f24d 100755 --- a/utils/update_build_version.py +++ b/utils/update_build_version.py @@ -71,10 +71,13 @@ def command_output(cmd, directory): Raises a RuntimeError 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 + # 'git' is invoked. p = subprocess.Popen(cmd, cwd=directory, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + stderr=subprocess.PIPE, + shell=os.name == 'nt') (stdout, stderr) = p.communicate() if p.returncode != 0: logging.error('Failed to run "{}" in "{}": {}'.format(cmd, directory, stderr.decode())) From 4183faa2eca6e531aecc7fb4a3f8a1b12c63a252 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 23 Feb 2023 12:14:28 +0000 Subject: [PATCH 059/523] Roll external/googletest/ 750d67d80..39a26e12d (2 commits) (#5120) https://github.com/google/googletest/compare/750d67d80970...39a26e12d67e $ git log 750d67d80..39a26e12d --date=short --no-merges --format='%ad %ae %s' 2023-02-22 dinor Avoid redundant declaration of static constexpr members in c++17 2023-02-22 dinor Update googletest's test docker containers 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 db0a1df852..74b7e1a073 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': 'c7b4db79f340f7a9981e8a484f6d5785e24242d1', - 'googletest_revision': '750d67d809700ae8fca6d610f7b41b71aa161808', + 'googletest_revision': '39a26e12d67ed6c21feeb606372bfee39a8e6d53', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From 5d2bc6f064f00935dd552aa13afbff40e66458c5 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Thu, 23 Feb 2023 20:10:35 -0500 Subject: [PATCH 060/523] Fix removal of dependent non-semantic instructions (#5122) Fixes #5121 * If the non-semantic info instructions depended on other moved instructions the def/use manager would get corrupted. --- source/opt/eliminate_dead_functions_util.cpp | 4 ++- test/opt/eliminate_dead_functions_test.cpp | 33 ++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/source/opt/eliminate_dead_functions_util.cpp b/source/opt/eliminate_dead_functions_util.cpp index cf7f92f550..e95b7f6a86 100644 --- a/source/opt/eliminate_dead_functions_util.cpp +++ b/source/opt/eliminate_dead_functions_util.cpp @@ -37,7 +37,9 @@ Module::iterator EliminateFunction(IRContext* context, assert(inst->IsNonSemanticInstruction()); if (to_kill.find(inst) != to_kill.end()) return; std::unique_ptr clone(inst->Clone(context)); - context->ForgetUses(inst); + // Clear uses of "inst" to in case this moves a dependent chain of + // instructions. + context->get_def_use_mgr()->ClearInst(inst); context->AnalyzeDefUse(clone.get()); if (first_func) { context->AddGlobalValue(std::move(clone)); diff --git a/test/opt/eliminate_dead_functions_test.cpp b/test/opt/eliminate_dead_functions_test.cpp index 96deb2a68c..e9f79a10f2 100644 --- a/test/opt/eliminate_dead_functions_test.cpp +++ b/test/opt/eliminate_dead_functions_test.cpp @@ -517,6 +517,39 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } +TEST_F(EliminateDeadFunctionsBasicTest, DependentNonSemanticChain) { + const std::string text = R"( +; CHECK: OpEntryPoint GLCompute [[main:%\w+]] +; CHECK: [[main]] = OpFunction +; CHECK-NOT: = OpFunction +; CHECK: [[ext1:%\w+]] = OpExtInst %void {{%\w+}} 1 [[main]] +; CHECK: [[ext2:%\w+]] = OpExtInst %void {{%\w+}} 2 [[ext1]] +; CHECK: [[ext3:%\w+]] = OpExtInst %void {{%\w+}} 3 [[ext1]] [[ext2]] +OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%1 = OpExtInstImport "NonSemantic.Test" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%main_entry = OpLabel +OpReturn +OpFunctionEnd +%dead = OpFunction %void None %void_fn +%dead_entry = OpLabel +OpReturn +OpFunctionEnd +%2 = OpExtInst %void %1 1 %main +%3 = OpExtInst %void %1 2 %2 +%4 = OpExtInst %void %1 3 %2 %3 +)"; + + SetTargetEnv(SPV_ENV_VULKAN_1_0); + SinglePassRunAndMatch(text, true); +} + } // namespace } // namespace opt } // namespace spvtools From b955c468b189f4480d045a157b62b68540ba6e07 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Fri, 24 Feb 2023 13:21:53 -0500 Subject: [PATCH 061/523] Add missing header include (#5124) * Found during an internal build --- source/opt/reflect.h | 1 + 1 file changed, 1 insertion(+) diff --git a/source/opt/reflect.h b/source/opt/reflect.h index aaa4c63d36..ec7c2dd075 100644 --- a/source/opt/reflect.h +++ b/source/opt/reflect.h @@ -16,6 +16,7 @@ #define SOURCE_OPT_REFLECT_H_ #include "source/latest_version_spirv_header.h" +#include "source/opcode.h" namespace spvtools { namespace opt { From 3b2ea1a422ee52570c266973382e92b0e7eda635 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 25 Feb 2023 18:54:35 +0000 Subject: [PATCH 062/523] Roll external/googletest/ 39a26e12d..3d787f5a0 (2 commits) (#5123) https://github.com/google/googletest/compare/39a26e12d67e...3d787f5a0d58 $ git log 39a26e12d..3d787f5a0 --date=short --no-merges --format='%ad %ae %s' 2023-02-24 absl-team Add `const` qualifier to `gtest_sentinel` which doesn't change. 2023-02-23 absl-team Added a missing semicolon for GTEST_FLAG_SET code snippet. 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 74b7e1a073..f1c16b6c3c 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': 'c7b4db79f340f7a9981e8a484f6d5785e24242d1', - 'googletest_revision': '39a26e12d67ed6c21feeb606372bfee39a8e6d53', + 'googletest_revision': '3d787f5a0d58cfc37a0563bb15647a0d8aa2c1bf', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From 2e0f4b52c9bf2169377900c7584286d032d499c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 27 Feb 2023 18:45:14 +0100 Subject: [PATCH 063/523] tools: refactorize tools flags parsing. (#5111) * tools: refactorize tools flags parsing. Each SPIR-V tool was handing their own flag parsing. This PR adds a new flag parsing utility that should be flexible enough for our usage, but generic enough so it can be shared across tools while remaining simple to use. * cfg: replace cfg option parsing with the new one. * change spirv-dis parsing + title + summary * clang format * flags: fix static init fiasco & remove help Static initialization order is important, and was working just by sheer luck. Also removing the help generation tooling. It's less flexible than the hand-written string, and making it as-good and as-flexible brings too much complexity. * review feedback --- BUILD.bazel | 9 +- BUILD.gn | 31 +++-- test/CMakeLists.txt | 3 +- test/tools/CMakeLists.txt | 7 + test/tools/flags_test.cpp | 286 ++++++++++++++++++++++++++++++++++++++ tools/CMakeLists.txt | 24 ++-- tools/as/as.cpp | 144 ++++++++----------- tools/cfg/cfg.cpp | 100 +++++-------- tools/dis/dis.cpp | 150 +++++++------------- tools/util/flags.cpp | 204 +++++++++++++++++++++++++++ tools/util/flags.h | 251 +++++++++++++++++++++++++++++++++ 11 files changed, 942 insertions(+), 267 deletions(-) create mode 100644 test/tools/flags_test.cpp create mode 100644 tools/util/flags.cpp create mode 100644 tools/util/flags.h diff --git a/BUILD.bazel b/BUILD.bazel index 0b44b559f0..759f043a8c 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -285,6 +285,7 @@ cc_binary( deps = [ ":spirv_tools_internal", ":tools_io", + ":tools_util", ], ) @@ -298,6 +299,7 @@ cc_binary( deps = [ ":spirv_tools", ":tools_io", + ":tools_util", ], ) @@ -357,6 +359,7 @@ cc_binary( ":spirv_tools_internal", ":spirv_tools_link", ":tools_io", + ":tools_util", ], ) @@ -387,6 +390,7 @@ cc_binary( deps = [ ":spirv_tools_internal", ":tools_io", + ":tools_util", ], ) @@ -416,7 +420,7 @@ cc_library( name = "base_{testcase}_test".format(testcase = f[len("test/"):-len("_test.cpp")]), size = "small", srcs = [f], - copts = TEST_COPTS, + copts = TEST_COPTS + ['-DTESTING'], linkstatic = 1, target_compatible_with = { "test/timer_test.cpp": incompatible_with(["@bazel_tools//src/conditions:windows"]), @@ -424,11 +428,12 @@ cc_library( deps = [ ":spirv_tools_internal", ":test_lib", + "tools_util", "@com_google_googletest//:gtest", "@com_google_googletest//:gtest_main", ], ) for f in glob( - ["test/*_test.cpp"], + ["test/*_test.cpp", "test/tools/*_test.cpp"], exclude = [ "test/cpp_interface_test.cpp", "test/log_test.cpp", diff --git a/BUILD.gn b/BUILD.gn index ee3743b85d..b576be15c4 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1430,15 +1430,6 @@ if (spirv_tools_standalone) { } } -source_set("spvtools_util_cli_consumer") { - sources = [ - "tools/util/cli_consumer.cpp", - "tools/util/cli_consumer.h", - ] - deps = [ ":spvtools_headers" ] - configs += [ ":spvtools_internal_config" ] -} - source_set("spvtools_software_version") { sources = [ "source/software_version.cpp" ] deps = [ @@ -1448,12 +1439,23 @@ source_set("spvtools_software_version") { configs += [ ":spvtools_internal_config" ] } +source_set("spvtools_tools_util") { + sources = [ + "tools/util/flags.cpp" + "tools/util/cli_consumer.cpp", + "tools/util/cli_consumer.h", + ] + deps = [ ":spvtools_headers" ] + configs += [ ":spvtools_internal_config" ] +} + if (spvtools_build_executables) { executable("spirv-as") { sources = [ "tools/as/as.cpp" ] deps = [ ":spvtools", ":spvtools_software_version", + ":spvtools_tools_util", ] configs += [ ":spvtools_internal_config" ] } @@ -1463,6 +1465,7 @@ if (spvtools_build_executables) { deps = [ ":spvtools", ":spvtools_software_version", + ":spvtools_tools_util", ] configs += [ ":spvtools_internal_config" ] } @@ -1472,7 +1475,7 @@ if (spvtools_build_executables) { deps = [ ":spvtools", ":spvtools_software_version", - ":spvtools_util_cli_consumer", + ":spvtools_tools_util", ":spvtools_val", ] configs += [ ":spvtools_internal_config" ] @@ -1487,6 +1490,7 @@ if (spvtools_build_executables) { deps = [ ":spvtools", ":spvtools_software_version", + ":spvtools_tools_util", ] configs += [ ":spvtools_internal_config" ] } @@ -1497,7 +1501,7 @@ if (spvtools_build_executables) { ":spvtools", ":spvtools_opt", ":spvtools_software_version", - ":spvtools_util_cli_consumer", + ":spvtools_tools_util", ":spvtools_val", ] configs += [ ":spvtools_internal_config" ] @@ -1510,6 +1514,7 @@ if (spvtools_build_executables) { ":spvtools_link", ":spvtools_opt", ":spvtools_software_version", + ":spvtools_tools_util", ":spvtools_val", ] configs += [ ":spvtools_internal_config" ] @@ -1529,7 +1534,7 @@ if (!is_ios && !spirv_is_winuwp && build_with_chromium && spvtools_build_executa ":spvtools_opt", ":spvtools_reduce", ":spvtools_software_version", - ":spvtools_util_cli_consumer", + ":spvtools_tools_util", ":spvtools_val", "//third_party/protobuf:protobuf_full", ] @@ -1548,7 +1553,7 @@ if (!is_ios && !spirv_is_winuwp && spvtools_build_executables) { ":spvtools_opt", ":spvtools_reduce", ":spvtools_software_version", - ":spvtools_util_cli_consumer", + ":spvtools_tools_util", ":spvtools_val", ] configs += [ ":spvtools_internal_config" ] diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4ca8ef8fb9..37c5e1d514 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -31,7 +31,7 @@ endif() function(add_spvtools_unittest) if (NOT "${SPIRV_SKIP_TESTS}" AND TARGET gmock_main) set(one_value_args TARGET PCH_FILE) - set(multi_value_args SRCS LIBS ENVIRONMENT) + set(multi_value_args SRCS LIBS ENVIRONMENT DEFINES) cmake_parse_arguments( ARG "" "${one_value_args}" "${multi_value_args}" ${ARGN}) set(target test_${ARG_TARGET}) @@ -40,6 +40,7 @@ function(add_spvtools_unittest) spvtools_pch(SRC_COPY ${ARG_PCH_FILE}) endif() add_executable(${target} ${SRC_COPY}) + target_compile_definitions(${target} PUBLIC ${ARG_DEFINES}) spvtools_default_compile_options(${target}) if(${COMPILER_IS_LIKE_GNU}) target_compile_options(${target} PRIVATE -Wno-undef) diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 99f9780c55..0520bd7519 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -18,4 +18,11 @@ add_test(NAME spirv-tools_expect_unittests add_test(NAME spirv-tools_spirv_test_framework_unittests COMMAND ${PYTHON_EXECUTABLE} -m unittest spirv_test_framework_unittest.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +add_spvtools_unittest( + TARGET spirv_unit_test_tools_util + SRCS flags_test.cpp ${spirv-tools_SOURCE_DIR}/tools/util/flags.cpp + LIBS ${SPIRV_TOOLS_FULL_VISIBILITY} + DEFINES TESTING=1) + add_subdirectory(opt) diff --git a/test/tools/flags_test.cpp b/test/tools/flags_test.cpp new file mode 100644 index 0000000000..d92f001027 --- /dev/null +++ b/test/tools/flags_test.cpp @@ -0,0 +1,286 @@ +// Copyright (c) 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. + +#include "tools/util/flags.h" + +#include "gmock/gmock.h" + +#ifdef UTIL_FLAGS_FLAG +#undef UTIL_FLAGS_FLAG +#define UTIL_FLAGS_FLAG(Type, Prefix, Name, Default, Required, IsShort) \ + flags::Flag Name(Default); \ + flags::FlagRegistration Name##_registration(Name, Prefix #Name, Required, \ + IsShort) +#else +#error \ + "UTIL_FLAGS_FLAG is not defined. Either flags.h is not included of the flag name changed." +#endif + +class FlagTest : public ::testing::Test { + protected: + void SetUp() override { flags::FlagList::reset(); } +}; + +TEST_F(FlagTest, NoFlags) { + const char* argv[] = {"binary", nullptr}; + EXPECT_TRUE(flags::Parse(argv)); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, DashIsPositional) { + const char* argv[] = {"binary", "-", nullptr}; + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_EQ(flags::positional_arguments.size(), 1); + EXPECT_EQ(flags::positional_arguments[0], "-"); +} + +TEST_F(FlagTest, Positional) { + const char* argv[] = {"binary", "A", "BCD", nullptr}; + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_EQ(flags::positional_arguments.size(), 2); + EXPECT_EQ(flags::positional_arguments[0], "A"); + EXPECT_EQ(flags::positional_arguments[1], "BCD"); +} + +TEST_F(FlagTest, MissingRequired) { + FLAG_SHORT_bool(g, false, true); + + const char* argv[] = {"binary", nullptr}; + EXPECT_FALSE(flags::Parse(argv)); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, BooleanShortValue) { + FLAG_SHORT_bool(g, false, false); + const char* argv[] = {"binary", "-g", nullptr}; + EXPECT_FALSE(g.value()); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_TRUE(g.value()); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, BooleanShortDefaultValue) { + FLAG_SHORT_bool(g, true, false); + const char* argv[] = {"binary", nullptr}; + EXPECT_TRUE(g.value()); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_TRUE(g.value()); +} + +TEST_F(FlagTest, BooleanLongValueNotParsed) { + FLAG_SHORT_bool(g, false, false); + const char* argv[] = {"binary", "-g", "false", nullptr}; + EXPECT_FALSE(g.value()); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_TRUE(g.value()); + EXPECT_EQ(flags::positional_arguments.size(), 1); + EXPECT_EQ(flags::positional_arguments[0], "false"); +} + +TEST_F(FlagTest, BooleanLongSplitNotParsed) { + FLAG_LONG_bool(foo, false, false); + const char* argv[] = {"binary", "--foo", "true", nullptr}; + EXPECT_FALSE(foo.value()); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_TRUE(foo.value()); + EXPECT_EQ(flags::positional_arguments.size(), 1); + EXPECT_EQ(flags::positional_arguments[0], "true"); +} + +TEST_F(FlagTest, BooleanLongExplicitTrue) { + FLAG_LONG_bool(foo, false, false); + const char* argv[] = {"binary", "--foo=true", nullptr}; + EXPECT_FALSE(foo.value()); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_TRUE(foo.value()); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, BooleanLongExplicitFalse) { + FLAG_LONG_bool(foo, false, false); + const char* argv[] = {"binary", "--foo=false", nullptr}; + EXPECT_FALSE(foo.value()); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_FALSE(foo.value()); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, BooleanLongDefaultValue) { + FLAG_LONG_bool(foo, true, false); + const char* argv[] = {"binary", nullptr}; + EXPECT_TRUE(foo.value()); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_TRUE(foo.value()); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, BooleanLongDefaultValueCancelled) { + FLAG_LONG_bool(foo, true, false); + const char* argv[] = {"binary", "--foo=false", nullptr}; + EXPECT_TRUE(foo.value()); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_FALSE(foo.value()); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, StringFlagDefaultValue) { + FLAG_SHORT_string(f, "default", false); + const char* argv[] = {"binary", nullptr}; + EXPECT_EQ(f.value(), "default"); + + EXPECT_TRUE(flags::Parse(argv)); + EXPECT_EQ(f.value(), "default"); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, StringFlagShortMissingString) { + FLAG_SHORT_string(f, "default", false); + const char* argv[] = {"binary", "-f", nullptr}; + EXPECT_EQ(f.value(), "default"); + + EXPECT_FALSE(flags::Parse(argv)); +} + +TEST_F(FlagTest, StringFlagDefault) { + FLAG_SHORT_string(f, "default", false); + const char* argv[] = {"binary", nullptr}; + EXPECT_EQ(f.value(), "default"); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_EQ(f.value(), "default"); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, StringFlagSet) { + FLAG_SHORT_string(f, "default", false); + const char* argv[] = {"binary", "-f", "toto", nullptr}; + EXPECT_EQ(f.value(), "default"); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_EQ(f.value(), "toto"); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, StringLongFlagSetSplit) { + FLAG_LONG_string(foo, "default", false); + const char* argv[] = {"binary", "--foo", "toto", nullptr}; + EXPECT_EQ(foo.value(), "default"); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_EQ(foo.value(), "toto"); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, StringLongFlagSetUnified) { + FLAG_LONG_string(foo, "default", false); + const char* argv[] = {"binary", "--foo=toto", nullptr}; + EXPECT_EQ(foo.value(), "default"); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_EQ(foo.value(), "toto"); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, StringLongFlagSetEmpty) { + FLAG_LONG_string(foo, "default", false); + const char* argv[] = {"binary", "--foo=", nullptr}; + EXPECT_EQ(foo.value(), "default"); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_EQ(foo.value(), ""); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, AllPositionalAfterDoubleDash) { + FLAG_LONG_string(foo, "default", false); + const char* argv[] = {"binary", "--", "--foo=toto", nullptr}; + EXPECT_EQ(foo.value(), "default"); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_EQ(foo.value(), "default"); + EXPECT_EQ(flags::positional_arguments.size(), 1); + EXPECT_EQ(flags::positional_arguments[0], "--foo=toto"); +} + +TEST_F(FlagTest, NothingAfterDoubleDash) { + FLAG_LONG_string(foo, "default", false); + const char* argv[] = {"binary", "--", nullptr}; + EXPECT_EQ(foo.value(), "default"); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_EQ(foo.value(), "default"); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, FlagDoubleSetNotAllowed) { + FLAG_LONG_string(foo, "default", false); + const char* argv[] = {"binary", "--foo=abc", "--foo=def", nullptr}; + EXPECT_EQ(foo.value(), "default"); + + EXPECT_FALSE(flags::Parse(argv)); +} + +TEST_F(FlagTest, MultipleFlags) { + FLAG_LONG_string(foo, "default foo", false); + FLAG_LONG_string(bar, "default_bar", false); + const char* argv[] = {"binary", "--foo", "abc", "--bar=def", nullptr}; + EXPECT_EQ(foo.value(), "default foo"); + EXPECT_EQ(bar.value(), "default_bar"); + + EXPECT_TRUE(flags::Parse(argv)); + EXPECT_EQ(foo.value(), "abc"); + EXPECT_EQ(bar.value(), "def"); +} + +TEST_F(FlagTest, MixedStringAndBool) { + FLAG_LONG_string(foo, "default foo", false); + FLAG_LONG_string(bar, "default_bar", false); + FLAG_SHORT_bool(g, false, false); + const char* argv[] = {"binary", "--foo", "abc", "-g", "--bar=def", nullptr}; + EXPECT_EQ(foo.value(), "default foo"); + EXPECT_EQ(bar.value(), "default_bar"); + EXPECT_FALSE(g.value()); + + EXPECT_TRUE(flags::Parse(argv)); + EXPECT_EQ(foo.value(), "abc"); + EXPECT_EQ(bar.value(), "def"); + EXPECT_TRUE(g.value()); +} diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index d272b08e71..6bf7a1190c 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -39,21 +39,29 @@ function(add_spvtools_tool) set_property(TARGET ${ARG_TARGET} PROPERTY FOLDER "SPIRV-Tools executables") endfunction() +set(COMMON_TOOLS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/util/flags.cpp") + if (NOT ${SPIRV_SKIP_EXECUTABLES}) - add_spvtools_tool(TARGET spirv-as SRCS as/as.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}) - add_spvtools_tool(TARGET spirv-diff SRCS diff/diff.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-diff SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY}) - add_spvtools_tool(TARGET spirv-dis SRCS dis/dis.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}) - add_spvtools_tool(TARGET spirv-val SRCS val/val.cpp util/cli_consumer.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}) - add_spvtools_tool(TARGET spirv-opt SRCS opt/opt.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY}) + add_spvtools_tool(TARGET spirv-diff SRCS ${COMMON_TOOLS_SRCS} diff/diff.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-diff SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY}) + add_spvtools_tool(TARGET spirv-dis SRCS ${COMMON_TOOLS_SRCS} dis/dis.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}) + add_spvtools_tool(TARGET spirv-val SRCS ${COMMON_TOOLS_SRCS} val/val.cpp util/cli_consumer.cpp LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}) + add_spvtools_tool(TARGET spirv-opt SRCS ${COMMON_TOOLS_SRCS} opt/opt.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY}) if(NOT (${CMAKE_SYSTEM_NAME} STREQUAL "iOS")) # iOS does not allow std::system calls which spirv-reduce requires - add_spvtools_tool(TARGET spirv-reduce SRCS reduce/reduce.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-reduce ${SPIRV_TOOLS_FULL_VISIBILITY}) + add_spvtools_tool(TARGET spirv-reduce SRCS ${COMMON_TOOLS_SRCS} reduce/reduce.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-reduce ${SPIRV_TOOLS_FULL_VISIBILITY}) endif() - add_spvtools_tool(TARGET spirv-link SRCS link/linker.cpp LIBS SPIRV-Tools-link ${SPIRV_TOOLS_FULL_VISIBILITY}) - add_spvtools_tool(TARGET spirv-lint SRCS lint/lint.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-lint SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY}) + add_spvtools_tool(TARGET spirv-link SRCS ${COMMON_TOOLS_SRCS} link/linker.cpp LIBS SPIRV-Tools-link ${SPIRV_TOOLS_FULL_VISIBILITY}) + add_spvtools_tool(TARGET spirv-lint SRCS ${COMMON_TOOLS_SRCS} lint/lint.cpp util/cli_consumer.cpp LIBS SPIRV-Tools-lint SPIRV-Tools-opt ${SPIRV_TOOLS_FULL_VISIBILITY}) + add_spvtools_tool(TARGET spirv-as + SRCS as/as.cpp + ${COMMON_TOOLS_SRCS} + LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}) + target_include_directories(spirv-as PRIVATE ${spirv-tools_SOURCE_DIR} + ${SPIRV_HEADER_INCLUDE_DIR}) add_spvtools_tool(TARGET spirv-cfg SRCS cfg/cfg.cpp cfg/bin_to_dot.h cfg/bin_to_dot.cpp + ${COMMON_TOOLS_SRCS} LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}) target_include_directories(spirv-cfg PRIVATE ${spirv-tools_SOURCE_DIR} ${SPIRV_HEADER_INCLUDE_DIR}) diff --git a/tools/as/as.cpp b/tools/as/as.cpp index 506b058562..2a000cf09b 100644 --- a/tools/as/as.cpp +++ b/tools/as/as.cpp @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include #include @@ -19,11 +20,11 @@ #include "source/spirv_target_env.h" #include "spirv-tools/libspirv.h" #include "tools/io.h" +#include "tools/util/flags.h" -void print_usage(char* argv0) { - std::string target_env_list = spvTargetEnvList(19, 80); - printf( - R"(%s - Create a SPIR-V binary module from SPIR-V assembly text +static const auto kDefaultEnvironment = "spv1.6"; +static const std::string kHelpText = + R"(%s - Create a SPIR-V binary module from SPIR-V assembly text Usage: %s [options] [] @@ -42,94 +43,70 @@ is used. Numeric IDs in the binary will have the same values as in the source. Non-numeric IDs are allocated by filling in the gaps, starting with 1 and going up. - --target-env {%s} + --target-env %s Use specified environment. -)", - argv0, argv0, target_env_list.c_str()); -} +)"; + +// clang-format off +FLAG_SHORT_bool( h, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( help, /* default_value= */ false, /* required= */false); +FLAG_LONG_bool( version, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( preserve_numeric_ids, /* default_value= */ false, /* required= */ false); +FLAG_SHORT_string(o, /* default_value= */ "", /* required= */ false); +FLAG_LONG_string( target_env, /* default_value= */ kDefaultEnvironment, /* required= */ false); +// clang-format on + +int main(int, const char** argv) { + if (!flags::Parse(argv)) { + return 1; + } -static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6; + if (flags::h.value() || flags::help.value()) { + const std::string target_env_list = spvTargetEnvList(19, 80); + printf(kHelpText.c_str(), argv[0], argv[0], target_env_list.c_str()); + return 0; + } -int main(int argc, char** argv) { - const char* inFile = nullptr; - const char* outFile = nullptr; - uint32_t options = 0; - spv_target_env target_env = kDefaultEnvironment; - for (int argi = 1; argi < argc; ++argi) { - if ('-' == argv[argi][0]) { - switch (argv[argi][1]) { - case 'h': { - print_usage(argv[0]); - return 0; - } - case 'o': { - if (!outFile && argi + 1 < argc) { - outFile = argv[++argi]; - } else { - print_usage(argv[0]); - return 1; - } - } break; - case 0: { - // Setting a filename of "-" to indicate stdin. - if (!inFile) { - inFile = argv[argi]; - } else { - fprintf(stderr, "error: More than one input file specified\n"); - return 1; - } - } break; - case '-': { - // Long options - if (0 == strcmp(argv[argi], "--version")) { - printf("%s\n", spvSoftwareVersionDetailsString()); - printf("Target: %s\n", - spvTargetEnvDescription(kDefaultEnvironment)); - return 0; - } else if (0 == strcmp(argv[argi], "--help")) { - print_usage(argv[0]); - return 0; - } else if (0 == strcmp(argv[argi], "--preserve-numeric-ids")) { - options |= SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS; - } else if (0 == strcmp(argv[argi], "--target-env")) { - if (argi + 1 < argc) { - const auto env_str = argv[++argi]; - if (!spvParseTargetEnv(env_str, &target_env)) { - fprintf(stderr, "error: Unrecognized target env: %s\n", - env_str); - return 1; - } - } else { - fprintf(stderr, "error: Missing argument to --target-env\n"); - return 1; - } - } else { - fprintf(stderr, "error: Unrecognized option: %s\n\n", argv[argi]); - print_usage(argv[0]); - return 1; - } - } break; - default: - fprintf(stderr, "error: Unrecognized option: %s\n\n", argv[argi]); - print_usage(argv[0]); - return 1; - } - } else { - if (!inFile) { - inFile = argv[argi]; - } else { - fprintf(stderr, "error: More than one input file specified\n"); - return 1; - } + if (flags::version.value()) { + spv_target_env target_env; + bool success = spvParseTargetEnv(kDefaultEnvironment, &target_env); + assert(success && "Default environment should always parse."); + if (!success) { + fprintf(stderr, + "error: invalid default target environment. Please report this " + "issue."); + return 1; } + printf("%s\n", spvSoftwareVersionDetailsString()); + printf("Target: %s\n", spvTargetEnvDescription(target_env)); + return 0; } - if (!outFile) { + std::string outFile = flags::o.value(); + if (outFile.empty()) { outFile = "out.spv"; } + uint32_t options = 0; + if (flags::preserve_numeric_ids.value()) { + options |= SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS; + } + + spv_target_env target_env; + if (!spvParseTargetEnv(flags::target_env.value().c_str(), &target_env)) { + fprintf(stderr, "error: Unrecognized target env: %s\n", + flags::target_env.value().c_str()); + return 1; + } + + if (flags::positional_arguments.size() != 1) { + fprintf(stderr, "error: exactly one input file must be specified.\n"); + return 1; + } + std::string inFile = flags::positional_arguments[0]; + std::vector contents; - if (!ReadTextFile(inFile, &contents)) return 1; + if (!ReadTextFile(inFile.c_str(), &contents)) return 1; spv_binary binary; spv_diagnostic diagnostic = nullptr; @@ -143,7 +120,8 @@ int main(int argc, char** argv) { return error; } - if (!WriteFile(outFile, "wb", binary->code, binary->wordCount)) { + if (!WriteFile(outFile.c_str(), "wb", binary->code, + binary->wordCount)) { spvBinaryDestroy(binary); return 1; } diff --git a/tools/cfg/cfg.cpp b/tools/cfg/cfg.cpp index 5380c21ecd..2d11e6fb06 100644 --- a/tools/cfg/cfg.cpp +++ b/tools/cfg/cfg.cpp @@ -21,11 +21,11 @@ #include "spirv-tools/libspirv.h" #include "tools/cfg/bin_to_dot.h" #include "tools/io.h" +#include "tools/util/flags.h" -// Prints a program usage message to stdout. -static void print_usage(const char* argv0) { - printf( - R"(%s - Show the control flow graph in GraphiViz "dot" form. EXPERIMENTAL +static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6; +static const std::string kHelpText = + R"(%s - Show the control flow graph in GraphiViz "dot" form. EXPERIMENTAL Usage: %s [options] [] @@ -40,71 +40,42 @@ or if the filename is "-", then the binary is read from standard input. -o Set the output filename. Output goes to standard output if this option is not specified, or if the filename is "-". -)", - argv0, argv0); -} +)"; -static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6; +// clang-format off +FLAG_SHORT_bool( h, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( help, /* default_value= */ false, /* required= */false); +FLAG_LONG_bool( version, /* default_value= */ false, /* required= */ false); +FLAG_SHORT_string(o, /* default_value= */ "", /* required= */ false); +// clang-format on + +int main(int, const char** argv) { + if (!flags::Parse(argv)) { + return 1; + } -int main(int argc, char** argv) { - const char* inFile = nullptr; - const char* outFile = nullptr; // Stays nullptr if printing to stdout. - - for (int argi = 1; argi < argc; ++argi) { - if ('-' == argv[argi][0]) { - switch (argv[argi][1]) { - case 'h': - print_usage(argv[0]); - return 0; - case 'o': { - if (!outFile && argi + 1 < argc) { - outFile = argv[++argi]; - } else { - print_usage(argv[0]); - return 1; - } - } break; - case '-': { - // Long options - if (0 == strcmp(argv[argi], "--help")) { - print_usage(argv[0]); - return 0; - } - if (0 == strcmp(argv[argi], "--version")) { - printf("%s EXPERIMENTAL\n", spvSoftwareVersionDetailsString()); - printf("Target: %s\n", - spvTargetEnvDescription(kDefaultEnvironment)); - return 0; - } - print_usage(argv[0]); - return 1; - } - case 0: { - // Setting a filename of "-" to indicate stdin. - if (!inFile) { - inFile = argv[argi]; - } else { - fprintf(stderr, "error: More than one input file specified\n"); - return 1; - } - } break; - default: - print_usage(argv[0]); - return 1; - } - } else { - if (!inFile) { - inFile = argv[argi]; - } else { - fprintf(stderr, "error: More than one input file specified\n"); - return 1; - } - } + if (flags::h.value() || flags::help.value()) { + printf(kHelpText.c_str(), argv[0], argv[0]); + return 0; } + if (flags::version.value()) { + printf("%s EXPERIMENTAL\n", spvSoftwareVersionDetailsString()); + printf("Target: %s\n", spvTargetEnvDescription(kDefaultEnvironment)); + return 0; + } + + if (flags::positional_arguments.size() != 1) { + fprintf(stderr, "error: exactly one input file must be specified.\n"); + return 1; + } + + std::string inFile = flags::positional_arguments[0]; + std::string outFile = flags::o.value(); + // Read the input binary. std::vector contents; - if (!ReadBinaryFile(inFile, &contents)) return 1; + if (!ReadBinaryFile(inFile.c_str(), &contents)) return 1; spv_context context = spvContextCreate(kDefaultEnvironment); spv_diagnostic diagnostic = nullptr; @@ -118,7 +89,8 @@ int main(int argc, char** argv) { return error; } std::string str = ss.str(); - WriteFile(outFile, "w", str.data(), str.size()); + WriteFile(outFile.empty() ? nullptr : outFile.c_str(), "w", str.data(), + str.size()); spvDiagnosticDestroy(diagnostic); spvContextDestroy(context); diff --git a/tools/dis/dis.cpp b/tools/dis/dis.cpp index 64380db06f..aacd37f079 100644 --- a/tools/dis/dis.cpp +++ b/tools/dis/dis.cpp @@ -24,10 +24,9 @@ #include "spirv-tools/libspirv.h" #include "tools/io.h" +#include "tools/util/flags.h" -static void print_usage(char* argv0) { - printf( - R"(%s - Disassemble a SPIR-V binary module +static const std::string kHelpText = R"(%s - Disassemble a SPIR-V binary module Usage: %s [options] [] @@ -58,15 +57,49 @@ or if the filename is "-", then the binary is read from standard input. --offsets Show byte offsets for each instruction. --comment Add comments to make reading easier -)", - argv0, argv0); -} +)"; + +// clang-format off +FLAG_SHORT_bool (h, /* default_value= */ false, /* required= */ false); +FLAG_SHORT_string(o, /* default_value= */ "-", /* required= */ false); +FLAG_LONG_bool (help, /* default_value= */ false, /* required= */false); +FLAG_LONG_bool (version, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool (color, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool (no_color, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool (no_indent, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool (no_header, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool (raw_id, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool (offsets, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool (comment, /* default_value= */ false, /* required= */ false); +// clang-format on static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5; -int main(int argc, char** argv) { - const char* inFile = nullptr; - const char* outFile = nullptr; +int main(int, const char** argv) { + if (!flags::Parse(argv)) { + return 1; + } + + if (flags::h.value() || flags::help.value()) { + printf(kHelpText.c_str(), argv[0], argv[0]); + return 0; + } + + if (flags::version.value()) { + printf("%s\n", spvSoftwareVersionDetailsString()); + printf("Target: %s\n", spvTargetEnvDescription(kDefaultEnvironment)); + return 0; + } + + if (flags::positional_arguments.size() > 1) { + fprintf(stderr, "error: more than one input file specified.\n"); + return 1; + } + + const std::string inFile = flags::positional_arguments.size() == 0 + ? "-" + : flags::positional_arguments[0]; + const std::string outFile = flags::o.value(); bool color_is_possible = #if SPIRV_COLOR_TERMINAL @@ -74,105 +107,30 @@ int main(int argc, char** argv) { #else false; #endif - bool force_color = false; - bool force_no_color = false; - - bool allow_indent = true; - bool show_byte_offsets = false; - bool no_header = false; - bool friendly_names = true; - bool comments = false; - - for (int argi = 1; argi < argc; ++argi) { - if ('-' == argv[argi][0]) { - switch (argv[argi][1]) { - case 'h': - print_usage(argv[0]); - return 0; - case 'o': { - if (!outFile && argi + 1 < argc) { - outFile = argv[++argi]; - } else { - print_usage(argv[0]); - return 1; - } - } break; - case '-': { - // Long options - if (0 == strcmp(argv[argi], "--no-color")) { - force_no_color = true; - force_color = false; - } else if (0 == strcmp(argv[argi], "--color")) { - force_no_color = false; - force_color = true; - } else if (0 == strcmp(argv[argi], "--comment")) { - comments = true; - } else if (0 == strcmp(argv[argi], "--no-indent")) { - allow_indent = false; - } else if (0 == strcmp(argv[argi], "--offsets")) { - show_byte_offsets = true; - } else if (0 == strcmp(argv[argi], "--no-header")) { - no_header = true; - } else if (0 == strcmp(argv[argi], "--raw-id")) { - friendly_names = false; - } else if (0 == strcmp(argv[argi], "--help")) { - print_usage(argv[0]); - return 0; - } else if (0 == strcmp(argv[argi], "--version")) { - printf("%s\n", spvSoftwareVersionDetailsString()); - printf("Target: %s\n", - spvTargetEnvDescription(kDefaultEnvironment)); - return 0; - } else { - print_usage(argv[0]); - return 1; - } - } break; - case 0: { - // Setting a filename of "-" to indicate stdin. - if (!inFile) { - inFile = argv[argi]; - } else { - fprintf(stderr, "error: More than one input file specified\n"); - return 1; - } - } break; - default: - print_usage(argv[0]); - return 1; - } - } else { - if (!inFile) { - inFile = argv[argi]; - } else { - fprintf(stderr, "error: More than one input file specified\n"); - return 1; - } - } - } uint32_t options = SPV_BINARY_TO_TEXT_OPTION_NONE; - if (allow_indent) options |= SPV_BINARY_TO_TEXT_OPTION_INDENT; + if (!flags::no_indent.value()) options |= SPV_BINARY_TO_TEXT_OPTION_INDENT; - if (show_byte_offsets) options |= SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET; + if (flags::offsets.value()) + options |= SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET; - if (no_header) options |= SPV_BINARY_TO_TEXT_OPTION_NO_HEADER; + if (flags::no_header.value()) options |= SPV_BINARY_TO_TEXT_OPTION_NO_HEADER; - if (friendly_names) options |= SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES; + if (!flags::raw_id.value()) + options |= SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES; - if (comments) options |= SPV_BINARY_TO_TEXT_OPTION_COMMENT; + if (flags::comment.value()) options |= SPV_BINARY_TO_TEXT_OPTION_COMMENT; - if (!outFile || (0 == strcmp("-", outFile))) { + if (flags::o.value() == "-") { // Print to standard output. options |= SPV_BINARY_TO_TEXT_OPTION_PRINT; - - if (color_is_possible && !force_no_color) { + if (color_is_possible && !flags::no_color.value()) { bool output_is_tty = true; #if defined(_POSIX_VERSION) output_is_tty = isatty(fileno(stdout)); #endif - if (output_is_tty || force_color) { + if (output_is_tty || flags::color.value()) { options |= SPV_BINARY_TO_TEXT_OPTION_COLOR; } } @@ -180,7 +138,7 @@ int main(int argc, char** argv) { // Read the input binary. std::vector contents; - if (!ReadBinaryFile(inFile, &contents)) return 1; + if (!ReadBinaryFile(inFile.c_str(), &contents)) return 1; // If printing to standard output, then spvBinaryToText should // do the printing. In particular, colour printing on Windows is @@ -205,7 +163,7 @@ int main(int argc, char** argv) { } if (!print_to_stdout) { - if (!WriteFile(outFile, "w", text->str, text->length)) { + if (!WriteFile(outFile.c_str(), "w", text->str, text->length)) { spvTextDestroy(text); return 1; } diff --git a/tools/util/flags.cpp b/tools/util/flags.cpp new file mode 100644 index 0000000000..c773347b94 --- /dev/null +++ b/tools/util/flags.cpp @@ -0,0 +1,204 @@ +// Copyright (c) 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. + +#include "flags.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace flags { + +std::vector positional_arguments; + +namespace { + +using token_t = const char*; +using token_iterator_t = token_t*; + +// Extracts the flag name from a potential token. +// This function only looks for a '=', to split the flag name from the value for +// long-form flags. Returns the name of the flag, prefixed with the hyphen(s). +inline std::string get_flag_name(const std::string& flag, bool is_short_flag) { + if (is_short_flag) { + return flag; + } + + size_t equal_index = flag.find('='); + if (equal_index == std::string::npos) { + return flag; + } + return flag.substr(0, equal_index); +} + +// Parse a boolean flag. Returns `true` if the parsing succeeded, `false` +// otherwise. +bool parse_flag(Flag& flag, bool is_short_flag, + const std::string& token) { + if (is_short_flag) { + flag.value() = true; + return true; + } + + const std::string raw_flag(token); + size_t equal_index = raw_flag.find('='); + if (equal_index == std::string::npos) { + flag.value() = true; + return true; + } + + const std::string value = raw_flag.substr(equal_index + 1); + if (value == "true") { + flag.value() = true; + return true; + } + + if (value == "false") { + flag.value() = false; + return true; + } + + return false; +} + +// Parse a string flag. Moved the iterator to the last flag's token if it's a +// multi-token flag. Returns `true` if the parsing succeeded. +// The iterator is moved to the last parsed token. +bool parse_flag(Flag& flag, bool is_short_flag, + token_iterator_t* iterator) { + const std::string raw_flag(**iterator); + const size_t equal_index = raw_flag.find('='); + if (is_short_flag || equal_index == std::string::npos) { + if ((*iterator)[1] == nullptr) { + return false; + } + + // This is a bi-token flag. Moving iterator to the last parsed token. + flag.value() = (*iterator)[1]; + *iterator += 1; + return true; + } + + // This is a mono-token flag, no need to move the iterator. + const std::string value = raw_flag.substr(equal_index + 1); + flag.value() = value; + return true; +} +} // namespace + +// This is the function to expand if you want to support a new type. +bool FlagList::parse_flag_info(FlagInfo& info, token_iterator_t* iterator) { + bool success = false; + + std::visit( + [&](auto&& item) { + using T = std::decay_t; + if constexpr (std::is_same_v>) { + success = parse_flag(item.get(), info.is_short, **iterator); + } else if constexpr (std::is_same_v>) { + success = parse_flag(item.get(), info.is_short, iterator); + } else { + static_assert(always_false_v, "Unsupported flag type."); + } + }, + info.flag); + + return success; +} + +bool FlagList::parse(token_t* argv) { + flags::positional_arguments.clear(); + std::unordered_set parsed_flags; + + bool ignore_flags = false; + for (const char** it = argv + 1; *it != nullptr; it++) { + if (ignore_flags) { + flags::positional_arguments.emplace_back(*it); + continue; + } + + // '--' alone is used to mark the end of the flags. + if (std::strcmp(*it, "--") == 0) { + ignore_flags = true; + continue; + } + + // '-' alone is not a flag, but often used to say 'stdin'. + if (std::strcmp(*it, "-") == 0) { + flags::positional_arguments.emplace_back(*it); + continue; + } + + const std::string raw_flag(*it); + if (raw_flag.size() == 0) { + continue; + } + + if (raw_flag[0] != '-') { + flags::positional_arguments.emplace_back(*it); + continue; + } + + // Only case left: flags (long and shorts). + if (raw_flag.size() < 2) { + std::cerr << "Unknown flag " << raw_flag << std::endl; + return false; + } + const bool is_short_flag = std::strncmp(*it, "--", 2) != 0; + const std::string flag_name = get_flag_name(raw_flag, is_short_flag); + + auto needle = std::find_if( + get_flags().begin(), get_flags().end(), + [&flag_name](const auto& item) { return item.name == flag_name; }); + if (needle == get_flags().end()) { + std::cerr << "Unknown flag " << flag_name << std::endl; + return false; + } + + if (parsed_flags.count(&*needle) != 0) { + std::cerr << "The flag " << flag_name << " was specified multiple times." + << std::endl; + return false; + } + parsed_flags.insert(&*needle); + + if (!parse_flag_info(*needle, &it)) { + std::cerr << "Invalid usage for flag " << flag_name << std::endl; + return false; + } + } + + // Check that we parsed all required flags. + for (const auto& flag : get_flags()) { + if (!flag.required) { + continue; + } + + if (parsed_flags.count(&flag) == 0) { + std::cerr << "Missing required flag " << flag.name << std::endl; + return false; + } + } + + return true; +} + +// Just the public wrapper around the parse function. +bool Parse(const char** argv) { return FlagList::parse(argv); } + +} // namespace flags diff --git a/tools/util/flags.h b/tools/util/flags.h new file mode 100644 index 0000000000..e48982cd52 --- /dev/null +++ b/tools/util/flags.h @@ -0,0 +1,251 @@ +// Copyright (c) 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. + +#ifndef INCLUDE_SPIRV_TOOLS_UTIL_FLAGS_HPP_ +#define INCLUDE_SPIRV_TOOLS_UTIL_FLAGS_HPP_ + +#include +#include +#include +#include + +// This file provides some utils to define a command-line interface with +// required and optional flags. +// - Flag order is not checked. +// - Currently supported flag types: BOOLEAN, STRING +// - As with most nix tools, using '--' in the command-line means all following +// tokens will be considered positional +// arguments. +// Example: binary -g -- -g --some-other-flag +// - the first `-g` is a flag. +// - the second `-g` is not a flag. +// - `--some-other-flag` is not a flag. +// - Both long-form and short-form flags are supported, but boolean flags don't +// support split boolean literals (short and long form). +// Example: +// -g : allowed, sets g to true. +// --my-flag : allowed, sets --my-flag to true. +// --my-flag=true : allowed, sets --my-flag to true. +// --my-flag true : NOT allowed. +// -g true : NOT allowed. +// --my-flag=TRUE : NOT allowed. +// +// - This implementation also supports string flags: +// -o myfile.spv : allowed, sets -o to `myfile.spv`. +// --output=myfile.spv : allowed, sets --output to `myfile.spv`. +// --output myfile.spv : allowd, sets --output to `myfile.spv`. +// +// Note: then second token is NOT checked for hyphens. +// --output -file.spv +// flag name: `output` +// flag value: `-file.spv` +// +// - This implementation generates flag at compile time. Meaning flag names +// must be valid C++ identifiers. +// However, flags are usually using hyphens for word separation. Hence +// renaming is done behind the scenes. Example: +// // Declaring a long-form flag. +// FLAG_LONG_bool(my_flag, [...]) +// +// -> in the code: flags::my_flag.value() +// -> command-line: --my-flag +// +// - The only additional lexing done is around '='. Otherwise token list is +// processed as received in the Parse() +// function. +// Lexing the '=' sign: +// - This is only done when parsing a long-form flag name. +// - the first '=' found is considered a marker for long-form, splitting +// the token into 2. +// Example: --option=value=abc -> [--option, value=abc] +// +// In most cases, you want to define some flags, parse them, and query them. +// Here is a small code sample: +// +// ```c +// // Defines a '-h' boolean flag for help printing, optional. +// FLAG_SHORT_bool(h, /*default=*/ false, "Print the help.", false); +// // Defines a '--my-flag' string flag, required. +// FLAG_LONG_string(my_flag, /*default=*/ "", "A magic flag!", true); +// +// int main(int argc, const char** argv) { +// if (!flags::Parse(argv)) { +// return -1; +// } +// +// if (flags::h.value()) { +// printf("usage: my-bin --my-flag=\n"); +// return 0; +// } +// +// printf("flag value: %s\n", flags::my_flag.value().c_str()); +// for (const std::string& arg : flags::positional_arguments) { +// printf("arg: %s\n", arg.c_str()); +// } +// return 0; +// } +// ```c + +// Those macros can be used to define flags. +// - They should be used in the global scope. +// - Underscores in the flag variable name are replaced with hyphens ('-'). +// +// Example: +// FLAG_SHORT_bool(my_flag, false, "some help", false); +// - in the code: flags::my_flag +// - command line: --my-flag=true +// +#define FLAG_LONG_string(Name, Default, Required) \ + UTIL_FLAGS_FLAG_LONG(std::string, Name, Default, Required) +#define FLAG_LONG_bool(Name, Default, Required) \ + UTIL_FLAGS_FLAG_LONG(bool, Name, Default, Required) + +#define FLAG_SHORT_string(Name, Default, Required) \ + UTIL_FLAGS_FLAG_SHORT(std::string, Name, Default, Required) +#define FLAG_SHORT_bool(Name, Default, Required) \ + UTIL_FLAGS_FLAG_SHORT(bool, Name, Default, Required) + +namespace flags { + +// Parse the command-line arguments, checking flags, and separating positional +// arguments from flags. +// +// * argv: the argv array received in the main function. This utility expects +// the last pointer to +// be NULL, as it should if coming from the main() function. +// +// Returns `true` if the parsing succeeds, `false` otherwise. +bool Parse(const char** argv); + +} // namespace flags + +// ===================== BEGIN NON-PUBLIC SECTION ============================= +// All the code below belongs to the implementation, and there is no guaranteed +// around the API stability. Please do not use it directly. + +// Defines the static variable holding the flag, allowing access like +// flags::my_flag. +// By creating the FlagRegistration object, the flag can be added to +// the global list. +// The final `extern` definition is ONLY useful for clang-format: +// - if the macro doesn't ends with a semicolon, clang-format goes wild. +// - cannot disable clang-format for those macros on clang < 16. +// (https://github.com/llvm/llvm-project/issues/54522) +// - cannot allow trailing semi (-Wextra-semi). +#define UTIL_FLAGS_FLAG(Type, Prefix, Name, Default, Required, IsShort) \ + namespace flags { \ + Flag Name(Default); \ + namespace { \ + static FlagRegistration Name##_registration(Name, Prefix #Name, Required, \ + IsShort); \ + } \ + } \ + extern flags::Flag flags::Name + +#define UTIL_FLAGS_FLAG_LONG(Type, Name, Default, Required) \ + UTIL_FLAGS_FLAG(Type, "--", Name, Default, Required, false) +#define UTIL_FLAGS_FLAG_SHORT(Type, Name, Default, Required) \ + UTIL_FLAGS_FLAG(Type, "-", Name, Default, Required, true) + +namespace flags { + +// Just a wrapper around the flag value. +template +struct Flag { + public: + Flag(T&& default_value) : value_(default_value) {} + Flag(Flag&& other) = delete; + Flag(const Flag& other) = delete; + + const T& value() const { return value_; } + T& value() { return value_; } + + private: + T value_; +}; + +// To add support for new flag-types, this needs to be extended, and the visitor +// below. +using FlagType = std::variant>, + std::reference_wrapper>>; + +template +inline constexpr bool always_false_v = false; + +extern std::vector positional_arguments; + +// Static class keeping track of the flags/arguments values. +class FlagList { + struct FlagInfo { + FlagInfo(FlagType&& flag_, std::string&& name_, bool required_, + bool is_short_) + : flag(std::move(flag_)), + name(std::move(name_)), + required(required_), + is_short(is_short_) {} + + FlagType flag; + std::string name; + bool required; + bool is_short; + }; + + public: + template + static void register_flag(Flag& flag, std::string&& name, bool required, + bool is_short) { + get_flags().emplace_back(flag, std::move(name), required, is_short); + } + + static bool parse(const char** argv); + +#ifdef TESTING + // Flags are supposed to be constant for the whole app execution, hence the + // static storage. Gtest doesn't fork before running a test, meaning we have + // to manually clear the context at teardown. + static void reset() { + get_flags().clear(); + positional_arguments.clear(); + } +#endif + + private: + static std::vector& get_flags() { + static std::vector flags; + return flags; + } + + static bool parse_flag_info(FlagInfo& info, const char*** iterator); + static void print_usage(const char* binary_name, + const std::string& usage_format); +}; + +template +struct FlagRegistration { + FlagRegistration(Flag& flag, std::string&& name, bool required, + bool is_short) { + std::string fixed_name = name; + for (auto& c : fixed_name) { + if (c == '_') { + c = '-'; + } + } + + FlagList::register_flag(flag, std::move(fixed_name), required, is_short); + } +}; + +} // namespace flags + +#endif // INCLUDE_SPIRV_TOOLS_UTIL_FLAGS_HPP_ From 9d4c95a57448d855c8a292d4b30fdf4b4045588e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 27 Feb 2023 20:45:43 +0100 Subject: [PATCH 064/523] build: fix build.gn missing comma (#5125) Broke build using this file. --- BUILD.gn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD.gn b/BUILD.gn index b576be15c4..155a6b14cf 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1441,7 +1441,7 @@ source_set("spvtools_software_version") { source_set("spvtools_tools_util") { sources = [ - "tools/util/flags.cpp" + "tools/util/flags.cpp", "tools/util/cli_consumer.cpp", "tools/util/cli_consumer.h", ] From 9d71fb676491bc12be3398665236f407341b83c8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 28 Feb 2023 11:59:21 +0000 Subject: [PATCH 065/523] Roll external/googletest/ 3d787f5a0..c7d0bc830 (4 commits) (#5126) https://github.com/google/googletest/compare/3d787f5a0d58...c7d0bc8309fc $ git log 3d787f5a0..c7d0bc830 --date=short --no-merges --format='%ad %ae %s' 2023-02-27 phoebeliang Reorder printers list. 2023-02-27 absl-team Reformat to current g3doc style guide. No content changes. 2023-02-21 sergionso Fix error in_death_test_child_process: undeclared identifier 2023-02-02 benayang Update testing.md 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 f1c16b6c3c..7839e55b5f 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': 'c7b4db79f340f7a9981e8a484f6d5785e24242d1', - 'googletest_revision': '3d787f5a0d58cfc37a0563bb15647a0d8aa2c1bf', + 'googletest_revision': 'c7d0bc8309fc5b3bb73ee33e86fb6e3d760480aa', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From 970ba4e8b064baca82151d9574ee15bbe246e12d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Wed, 1 Mar 2023 18:50:42 +0100 Subject: [PATCH 066/523] linker: refactorize flag parsing (#5132) replace the old parser with the common utility. --- tools/link/linker.cpp | 107 ++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 56 deletions(-) diff --git a/tools/link/linker.cpp b/tools/link/linker.cpp index bdddeb899e..381d8b9b51 100644 --- a/tools/link/linker.cpp +++ b/tools/link/linker.cpp @@ -14,6 +14,7 @@ #include "spirv-tools/linker.hpp" +#include #include #include #include @@ -22,10 +23,11 @@ #include "source/table.h" #include "spirv-tools/libspirv.hpp" #include "tools/io.h" +#include "tools/util/flags.h" namespace { -const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6; +constexpr auto kDefaultEnvironment = "spv1.6"; void print_usage(const char* program) { std::string target_env_list = spvTargetEnvList(16, 80); @@ -67,65 +69,58 @@ Options (in lexicographical order): } // namespace -int main(int argc, char** argv) { - std::vector inFiles; - const char* outFile = nullptr; - spv_target_env target_env = kDefaultEnvironment; - spvtools::LinkerOptions options; +// clang-format off +FLAG_SHORT_bool( h, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( help, /* default_value= */ false, /* required= */false); +FLAG_LONG_bool( version, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( verify_ids, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( create_library, /* default_value= */ false, /* required= */ 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); +// clang-format on + +int main(int, const char* argv[]) { + if (!flags::Parse(argv)) { + return 1; + } + + if (flags::h.value() || flags::help.value()) { + print_usage(argv[0]); + return 0; + } - for (int argi = 1; argi < argc; ++argi) { - const char* cur_arg = argv[argi]; - if ('-' == cur_arg[0]) { - if (0 == strcmp(cur_arg, "-o")) { - if (argi + 1 < argc) { - if (!outFile) { - outFile = argv[++argi]; - } else { - fprintf(stderr, "error: More than one output file specified\n"); - return 1; - } - } else { - fprintf(stderr, "error: Missing argument to %s\n", cur_arg); - return 1; - } - } else if (0 == strcmp(cur_arg, "--allow-partial-linkage")) { - options.SetAllowPartialLinkage(true); - } else if (0 == strcmp(cur_arg, "--create-library")) { - options.SetCreateLibrary(true); - } else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) { - print_usage(argv[0]); - return 0; - } else if (0 == strcmp(cur_arg, "--target-env")) { - if (argi + 1 < argc) { - const auto env_str = argv[++argi]; - if (!spvParseTargetEnv(env_str, &target_env)) { - fprintf(stderr, "error: Unrecognized target env: %s\n", env_str); - return 1; - } - } else { - fprintf(stderr, "error: Missing argument to --target-env\n"); - return 1; - } - } else if (0 == strcmp(cur_arg, "--verify-ids")) { - options.SetVerifyIds(true); - } else if (0 == strcmp(cur_arg, "--version")) { - printf("%s\n", spvSoftwareVersionDetailsString()); - printf("Target: %s\n", spvTargetEnvDescription(target_env)); - return 0; - } else { - fprintf(stderr, "error: Unrecognized option: %s\n\n", argv[argi]); - print_usage(argv[0]); - return 1; - } - } else { - inFiles.push_back(cur_arg); + if (flags::version.value()) { + spv_target_env target_env; + bool success = spvParseTargetEnv(kDefaultEnvironment, &target_env); + assert(success && "Default environment should always parse."); + if (!success) { + fprintf(stderr, + "error: invalid default target environment. Please report this " + "issue."); + return 1; } + printf("%s\n", spvSoftwareVersionDetailsString()); + printf("Target: %s\n", spvTargetEnvDescription(target_env)); + return 0; } - if (!outFile) { - outFile = "out.spv"; + spv_target_env target_env; + if (!spvParseTargetEnv(flags::target_env.value().c_str(), &target_env)) { + fprintf(stderr, "error: Unrecognized target env: %s\n", + flags::target_env.value().c_str()); + return 1; } + const std::string outFile = + flags::o.value().empty() ? "out.spv" : flags::o.value(); + const std::vector& inFiles = flags::positional_arguments; + + spvtools::LinkerOptions options; + options.SetAllowPartialLinkage(flags::allow_partial_linkage.value()); + options.SetCreateLibrary(flags::create_library.value()); + options.SetVerifyIds(flags::verify_ids.value()); + if (inFiles.empty()) { fprintf(stderr, "error: No input file specified\n"); return 1; @@ -133,7 +128,7 @@ int main(int argc, char** argv) { std::vector> contents(inFiles.size()); for (size_t i = 0u; i < inFiles.size(); ++i) { - if (!ReadBinaryFile(inFiles[i], &contents[i])) return 1; + if (!ReadBinaryFile(inFiles[i].c_str(), &contents[i])) return 1; } const spvtools::MessageConsumer consumer = [](spv_message_level_t level, @@ -165,7 +160,7 @@ int main(int argc, char** argv) { spv_result_t status = Link(context, contents, &linkingResult, options); if (status != SPV_SUCCESS && status != SPV_WARNING) return 1; - if (!WriteFile(outFile, "wb", linkingResult.data(), + if (!WriteFile(outFile.c_str(), "wb", linkingResult.data(), linkingResult.size())) return 1; From 8cee461986c2bb77a114e1a3ca52fe05ad9fe217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 2 Mar 2023 15:16:32 +0100 Subject: [PATCH 067/523] tools: add uint32_t flags parsing (#5131) * tools: add uint32_t flags parsing This will be required to refactorize other tools. --- test/tools/flags_test.cpp | 129 ++++++++++++++++++++++++++++++++++++++ tools/util/flags.cpp | 64 +++++++++++++++---- tools/util/flags.h | 9 ++- 3 files changed, 188 insertions(+), 14 deletions(-) diff --git a/test/tools/flags_test.cpp b/test/tools/flags_test.cpp index d92f001027..43db99676a 100644 --- a/test/tools/flags_test.cpp +++ b/test/tools/flags_test.cpp @@ -284,3 +284,132 @@ TEST_F(FlagTest, MixedStringAndBool) { EXPECT_EQ(bar.value(), "def"); EXPECT_TRUE(g.value()); } + +TEST_F(FlagTest, UintFlagDefaultValue) { + FLAG_SHORT_uint(f, 18, false); + const char* argv[] = {"binary", nullptr}; + EXPECT_EQ(f.value(), 18); + + EXPECT_TRUE(flags::Parse(argv)); + EXPECT_EQ(f.value(), 18); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, UintFlagShortMissingValue) { + FLAG_SHORT_uint(f, 19, false); + const char* argv[] = {"binary", "-f", nullptr}; + EXPECT_EQ(f.value(), 19); + + EXPECT_FALSE(flags::Parse(argv)); +} + +TEST_F(FlagTest, UintFlagSet) { + FLAG_SHORT_uint(f, 20, false); + const char* argv[] = {"binary", "-f", "21", nullptr}; + EXPECT_EQ(f.value(), 20); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_EQ(f.value(), 21); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, UintLongFlagSetSplit) { + FLAG_LONG_uint(foo, 22, false); + const char* argv[] = {"binary", "--foo", "23", nullptr}; + EXPECT_EQ(foo.value(), 22); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_EQ(foo.value(), 23); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, UintLongFlagSetUnified) { + FLAG_LONG_uint(foo, 24, false); + const char* argv[] = {"binary", "--foo=25", nullptr}; + EXPECT_EQ(foo.value(), 24); + + EXPECT_TRUE(flags::Parse(argv)); + + EXPECT_EQ(foo.value(), 25); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, UintLongFlagSetEmptyIsWrong) { + FLAG_LONG_uint(foo, 26, false); + const char* argv[] = {"binary", "--foo=", nullptr}; + EXPECT_EQ(foo.value(), 26); + + EXPECT_FALSE(flags::Parse(argv)); +} + +TEST_F(FlagTest, UintLongFlagSetNegativeFails) { + FLAG_LONG_uint(foo, 26, false); + const char* argv[] = {"binary", "--foo=-2", nullptr}; + EXPECT_EQ(foo.value(), 26); + + EXPECT_FALSE(flags::Parse(argv)); +} + +TEST_F(FlagTest, UintLongFlagSetOverflowFails) { + FLAG_LONG_uint(foo, 27, false); + const char* argv[] = { + "binary", "--foo=99999999999999999999999999999999999999999999999999999", + nullptr}; + EXPECT_EQ(foo.value(), 27); + + EXPECT_FALSE(flags::Parse(argv)); +} + +TEST_F(FlagTest, UintLongFlagSetInvalidCharTrailing) { + FLAG_LONG_uint(foo, 28, false); + const char* argv[] = {"binary", "--foo=12A", nullptr}; + EXPECT_EQ(foo.value(), 28); + + EXPECT_FALSE(flags::Parse(argv)); +} + +TEST_F(FlagTest, UintLongFlagSetSpaces) { + FLAG_LONG_uint(foo, 29, false); + const char* argv[] = {"binary", "--foo= 12", nullptr}; + EXPECT_EQ(foo.value(), 29); + + EXPECT_TRUE(flags::Parse(argv)); + EXPECT_EQ(foo.value(), 12); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} + +TEST_F(FlagTest, UintLongFlagSpacesOnly) { + FLAG_LONG_uint(foo, 30, false); + const char* argv[] = {"binary", "--foo= ", nullptr}; + EXPECT_EQ(foo.value(), 30); + + EXPECT_FALSE(flags::Parse(argv)); +} + +TEST_F(FlagTest, UintLongFlagSplitNumber) { + FLAG_LONG_uint(foo, 31, false); + const char* argv[] = {"binary", "--foo= 2 2", nullptr}; + EXPECT_EQ(foo.value(), 31); + + EXPECT_FALSE(flags::Parse(argv)); +} + +TEST_F(FlagTest, UintLongFlagHex) { + FLAG_LONG_uint(foo, 32, false); + const char* argv[] = {"binary", "--foo=0xA", nullptr}; + EXPECT_EQ(foo.value(), 32); + + EXPECT_FALSE(flags::Parse(argv)); +} + +TEST_F(FlagTest, UintLongFlagZeros) { + FLAG_LONG_uint(foo, 33, false); + const char* argv[] = {"binary", "--foo=0000", nullptr}; + EXPECT_EQ(foo.value(), 33); + + EXPECT_TRUE(flags::Parse(argv)); + EXPECT_EQ(foo.value(), 0); + EXPECT_EQ(flags::positional_arguments.size(), 0); +} diff --git a/tools/util/flags.cpp b/tools/util/flags.cpp index c773347b94..11b8967167 100644 --- a/tools/util/flags.cpp +++ b/tools/util/flags.cpp @@ -14,6 +14,7 @@ #include "flags.h" +#include #include #include #include @@ -48,8 +49,8 @@ inline std::string get_flag_name(const std::string& flag, bool is_short_flag) { // Parse a boolean flag. Returns `true` if the parsing succeeded, `false` // otherwise. -bool parse_flag(Flag& flag, bool is_short_flag, - const std::string& token) { +bool parse_bool_flag(Flag& flag, bool is_short_flag, + const std::string& token) { if (is_short_flag) { flag.value() = true; return true; @@ -76,29 +77,64 @@ bool parse_flag(Flag& flag, bool is_short_flag, return false; } -// Parse a string flag. Moved the iterator to the last flag's token if it's a -// multi-token flag. Returns `true` if the parsing succeeded. +// Parse a uint32_t flag value. +bool parse_flag_value(Flag& flag, const std::string& value) { + std::regex unsigned_pattern("^ *[0-9]+ *$"); + if (!std::regex_match(value, unsigned_pattern)) { + std::cerr << "'" << value << "' is not a unsigned number." << std::endl; + return false; + } + + errno = 0; + char* end_ptr = nullptr; + const uint64_t number = strtoull(value.c_str(), &end_ptr, 10); + if (end_ptr == nullptr || end_ptr != value.c_str() + value.size() || + errno == EINVAL) { + std::cerr << "'" << value << "' is not a unsigned number." << std::endl; + return false; + } + + if (errno == ERANGE || number > static_cast(UINT32_MAX)) { + std::cerr << "'" << value << "' cannot be represented as a 32bit unsigned." + << std::endl; + return false; + } + + flag.value() = static_cast(number); + return true; +} + +// "Parse" a string flag value (assigns it, cannot fail). +bool parse_flag_value(Flag& flag, const std::string& value) { + flag.value() = value; + return true; +} + +// Parse a potential multi-token flag. Moves the iterator to the last flag's +// token if it's a multi-token flag. Returns `true` if the parsing succeeded. // The iterator is moved to the last parsed token. -bool parse_flag(Flag& flag, bool is_short_flag, - token_iterator_t* iterator) { +template +bool parse_flag(Flag& flag, bool is_short_flag, const char*** iterator) { const std::string raw_flag(**iterator); + std::string raw_value; const size_t equal_index = raw_flag.find('='); + if (is_short_flag || equal_index == std::string::npos) { if ((*iterator)[1] == nullptr) { return false; } // This is a bi-token flag. Moving iterator to the last parsed token. - flag.value() = (*iterator)[1]; + raw_value = (*iterator)[1]; *iterator += 1; - return true; + } else { + // This is a mono-token flag, no need to move the iterator. + raw_value = raw_flag.substr(equal_index + 1); } - // This is a mono-token flag, no need to move the iterator. - const std::string value = raw_flag.substr(equal_index + 1); - flag.value() = value; - return true; + return parse_flag_value(flag, raw_value); } + } // namespace // This is the function to expand if you want to support a new type. @@ -109,9 +145,11 @@ bool FlagList::parse_flag_info(FlagInfo& info, token_iterator_t* iterator) { [&](auto&& item) { using T = std::decay_t; if constexpr (std::is_same_v>) { - success = parse_flag(item.get(), info.is_short, **iterator); + success = parse_bool_flag(item.get(), info.is_short, **iterator); } else if constexpr (std::is_same_v>) { success = parse_flag(item.get(), info.is_short, iterator); + } else if constexpr (std::is_same_v>) { + success = parse_flag(item.get(), info.is_short, iterator); } else { static_assert(always_false_v, "Unsupported flag type."); } diff --git a/tools/util/flags.h b/tools/util/flags.h index e48982cd52..c8abfd5ac5 100644 --- a/tools/util/flags.h +++ b/tools/util/flags.h @@ -15,6 +15,8 @@ #ifndef INCLUDE_SPIRV_TOOLS_UTIL_FLAGS_HPP_ #define INCLUDE_SPIRV_TOOLS_UTIL_FLAGS_HPP_ +#include + #include #include #include @@ -110,11 +112,15 @@ UTIL_FLAGS_FLAG_LONG(std::string, Name, Default, Required) #define FLAG_LONG_bool(Name, Default, Required) \ UTIL_FLAGS_FLAG_LONG(bool, Name, Default, Required) +#define FLAG_LONG_uint(Name, Default, Required) \ + UTIL_FLAGS_FLAG_LONG(uint32_t, Name, Default, Required) #define FLAG_SHORT_string(Name, Default, Required) \ UTIL_FLAGS_FLAG_SHORT(std::string, Name, Default, Required) #define FLAG_SHORT_bool(Name, Default, Required) \ UTIL_FLAGS_FLAG_SHORT(bool, Name, Default, Required) +#define FLAG_SHORT_uint(Name, Default, Required) \ + UTIL_FLAGS_FLAG_SHORT(uint32_t, Name, Default, Required) namespace flags { @@ -178,7 +184,8 @@ struct Flag { // To add support for new flag-types, this needs to be extended, and the visitor // below. using FlagType = std::variant>, - std::reference_wrapper>>; + std::reference_wrapper>, + std::reference_wrapper>>; template inline constexpr bool always_false_v = false; From d6c707676d8adeaa44dd50b4faf064a5cf676308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 2 Mar 2023 15:17:34 +0100 Subject: [PATCH 068/523] linter: refactorize linter flag parsing (#5134) Change custom flag parsing to the built-in one. --- tools/lint/lint.cpp | 71 ++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/tools/lint/lint.cpp b/tools/lint/lint.cpp index d37df830f1..00c6cd2048 100644 --- a/tools/lint/lint.cpp +++ b/tools/lint/lint.cpp @@ -18,58 +18,57 @@ #include "spirv-tools/linter.hpp" #include "tools/io.h" #include "tools/util/cli_consumer.h" - -const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6; +#include "tools/util/flags.h" namespace { -// Status and actions to perform after parsing command-line arguments. -enum LintActions { LINT_CONTINUE, LINT_STOP }; -struct LintStatus { - LintActions action; - int code; -}; +constexpr auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6; +constexpr auto kHelpTextFmt = + R"(%s - Lint a SPIR-V binary module. -// Parses command-line flags. |argc| contains the number of command-line flags. -// |argv| points to an array of strings holding the flags. -// -// On return, this function stores the name of the input program in |in_file|. -// The return value indicates whether optimization should continue and a status -// code indicating an error or success. -LintStatus ParseFlags(int argc, const char** argv, const char** in_file) { - // TODO (dongja): actually parse flags, etc. - if (argc != 2) { - spvtools::Error(spvtools::utils::CLIMessageConsumer, nullptr, {}, - "expected exactly one argument: in_file"); - return {LINT_STOP, 1}; - } +Usage: %s [options] - *in_file = argv[1]; +Options: + + -h, --help Print this help. + --version Display assembler version information. +)"; - return {LINT_CONTINUE, 0}; -} } // namespace -int main(int argc, const char** argv) { - const char* in_file = nullptr; +// clang-format off +FLAG_SHORT_bool( h, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( help, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( version, /* default_value= */ false, /* required= */ false); +// clang-format on - spv_target_env target_env = kDefaultEnvironment; +int main(int, const char** argv) { + if (!flags::Parse(argv)) { + return 1; + } - spvtools::Linter linter(target_env); - linter.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); + if (flags::h.value() || flags::help.value()) { + printf(kHelpTextFmt, argv[0], argv[0]); + return 0; + } - LintStatus status = ParseFlags(argc, argv, &in_file); + if (flags::version.value()) { + printf("%s\n", spvSoftwareVersionDetailsString()); + return 0; + } - if (status.action == LINT_STOP) { - return status.code; + if (flags::positional_arguments.size() != 1) { + spvtools::Error(spvtools::utils::CLIMessageConsumer, nullptr, {}, + "expected exactly one input file."); + return 1; } + spvtools::Linter linter(kDefaultEnvironment); + linter.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); std::vector binary; - if (!ReadBinaryFile(in_file, &binary)) { + if (!ReadBinaryFile(flags::positional_arguments[0].c_str(), &binary)) { return 1; } - bool ok = linter.Run(binary.data(), binary.size()); - - return ok ? 0 : 1; + return linter.Run(binary.data(), binary.size()) ? 0 : 1; } From 6c714f191e3b6cfbd886c1b1e766e8a4893be481 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 2 Mar 2023 19:53:51 +0000 Subject: [PATCH 069/523] Roll external/googletest/ c7d0bc830..2d4f20876 (3 commits) (#5130) * Roll external/googletest/ c7d0bc830..2d4f20876 (3 commits) https://github.com/google/googletest/compare/c7d0bc8309fc...2d4f208765af $ git log c7d0bc830..2d4f20876 --date=short --no-merges --format='%ad %ae %s' 2023-02-28 absl-team Rephrase the description of TEST_F() arguments for clarity. 2023-02-27 absl-team Eliminate argv list action parameter. 2023-02-19 39726720+VuPhamVan Fix typo Created with: roll-dep external/googletest * Roll external/spirv-headers/ aa331ab0f..295cf5fb3 (6 commits) https://github.com/KhronosGroup/SPIRV-Headers/compare/aa331ab0ffcb...295cf5fb3bfe $ git log aa331ab0f..295cf5fb3 --date=short --no-merges --format='%ad %ae %s' 2023-03-01 abhishek2.tiwari update parameter name to match spec in grammar file 2023-02-23 abhishek2.tiwari move FPGAKernelAttributesv2INTEL to capability section in all files 2023-02-08 abhishek2.tiwari correct file entry position for FPGAKernelAttributesv2INTEL 2023-02-07 abhishek2.tiwari add FPGAKernelAttributesv2INTEL to all files 2023-01-27 abhishek2.tiwari address review comment 2023-01-26 abhishek2.tiwari add RegisterMapInterfaceINTEL 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 7839e55b5f..00c9d44417 100644 --- a/DEPS +++ b/DEPS @@ -5,13 +5,13 @@ vars = { 'effcee_revision': 'c7b4db79f340f7a9981e8a484f6d5785e24242d1', - 'googletest_revision': 'c7d0bc8309fc5b3bb73ee33e86fb6e3d760480aa', + 'googletest_revision': '2d4f208765af7fa376b878860a7677ecc0bc390a', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', 're2_revision': '3a8436ac436124a57a4e22d5c8713a2d42b381d7', - 'spirv_headers_revision': 'aa331ab0ffcb3a67021caa1a0c1c9017712f2f31', + 'spirv_headers_revision': '295cf5fb3bfe2454360e82b26bae7fc0de699abe', } deps = { From 5fe3bbe77dc462ad6060846894f850f7d054791a Mon Sep 17 00:00:00 2001 From: David Neto Date: Fri, 3 Mar 2023 09:30:13 -0500 Subject: [PATCH 070/523] Update Effcee so it doesn't hardcode C++11 (#5137) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 00c9d44417..6dc3f03fa0 100644 --- a/DEPS +++ b/DEPS @@ -3,7 +3,7 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'effcee_revision': 'c7b4db79f340f7a9981e8a484f6d5785e24242d1', + 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', 'googletest_revision': '2d4f208765af7fa376b878860a7677ecc0bc390a', From bd83b772c3c1bb7dac7f8feaf217378923df863b Mon Sep 17 00:00:00 2001 From: Laura Hermanns Date: Fri, 3 Mar 2023 10:52:49 -0500 Subject: [PATCH 071/523] Fix operand index out of bounds when folding OpCompositeExtract. (#5107) GetExtractOperandsForElementOfCompositeConstruct() states "Returns the empty vector if |result_index| is out-of-bounds", but violates that contract for non-vector result types. --- source/opt/folding_rules.cpp | 7 +++++-- test/opt/fold_test.cpp | 11 ++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/source/opt/folding_rules.cpp b/source/opt/folding_rules.cpp index 1a4c03d7e3..a2260ccb22 100644 --- a/source/opt/folding_rules.cpp +++ b/source/opt/folding_rules.cpp @@ -1656,8 +1656,11 @@ std::vector GetExtractOperandsForElementOfCompositeConstruct( analysis::Type* result_type = type_mgr->GetType(inst->type_id()); if (result_type->AsVector() == nullptr) { - uint32_t id = inst->GetSingleWordInOperand(result_index); - return {Operand(SPV_OPERAND_TYPE_ID, {id})}; + if (result_index < inst->NumInOperands()) { + uint32_t id = inst->GetSingleWordInOperand(result_index); + return {Operand(SPV_OPERAND_TYPE_ID, {id})}; + } + return {}; } // If the result type is a vector, then vector operands are concatenated. diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index cc9bcd6f9e..111973b26a 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -7372,7 +7372,16 @@ ::testing::Values( "%4 = OpCompositeInsert %struct_v2int_int_int %int_1 %struct_v2int_int_int_null 2\n" + "OpReturn\n" + "OpFunctionEnd", - 4, false) + 4, false), + // Test case 17: Don't fold when index into composite is out of bounds. + InstructionFoldingCase( + Header() + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%4 = OpCompositeExtract %int %struct_v2int_int_int 3\n" + + "OpReturn\n" + + "OpFunctionEnd", + 4, false) )); INSTANTIATE_TEST_SUITE_P(DotProductMatchingTest, MatchingInstructionFoldingTest, From 3eff21366e541ae378dcca15baf0e060a53a0184 Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Fri, 3 Mar 2023 16:53:08 +0100 Subject: [PATCH 072/523] Fix MinGW build error (#4935) (#5127) This commit fixes the following build error when the source code is build with MinGW gcc 12 and compiler switch '-Werror=maybe-uninitialized' is added: 'file.{anonymous}::OutputFile::old_mode_' may be used uninitialized in this function [-Werror=maybe-uninitialized] --- tools/io.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/io.h b/tools/io.h index 9dc834edfb..8bbee3a0df 100644 --- a/tools/io.h +++ b/tools/io.h @@ -127,7 +127,7 @@ class OutputFile { public: // Opens |filename| in the given mode. If |filename| is nullptr, the empty // string or "-", stdout will be set to the given mode. - OutputFile(const char* filename, const char* mode) { + OutputFile(const char* filename, const char* mode) : old_mode_(0) { const bool use_stdout = !filename || (filename[0] == '-' && filename[1] == '\0'); if (use_stdout) { From e0df12997fe799dd6b50a6b0f886391552b5c6dc Mon Sep 17 00:00:00 2001 From: Ralf Habacker Date: Fri, 3 Mar 2023 16:53:23 +0100 Subject: [PATCH 073/523] Fix using invalid install path for cmake support files with MINGW platform (#5128) (#5129) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c7b071af3..75830b44c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -270,7 +270,7 @@ else() endif() if(ENABLE_SPIRV_TOOLS_INSTALL) - if(WIN32) + if(WIN32 AND NOT MINGW) macro(spvtools_config_package_dir TARGET PATH) set(${PATH} ${TARGET}/cmake) endmacro() From 7cb5898e1df5ef4ff043cf90a30f443230a6ac62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Fri, 3 Mar 2023 16:55:00 +0100 Subject: [PATCH 074/523] diff: refactorize flag parsing (#5133) * diff: refactorize flag parsing Remove custom flag parsing to use the common one. * remove superfluous ; --- tools/diff/diff.cpp | 163 ++++++++++++++++++-------------------------- 1 file changed, 67 insertions(+), 96 deletions(-) diff --git a/tools/diff/diff.cpp b/tools/diff/diff.cpp index d3cad04b11..2217896c3b 100644 --- a/tools/diff/diff.cpp +++ b/tools/diff/diff.cpp @@ -17,14 +17,25 @@ #endif #include "source/diff/diff.h" - #include "source/opt/build_module.h" #include "source/opt/ir_context.h" #include "spirv-tools/libspirv.hpp" #include "tools/io.h" #include "tools/util/cli_consumer.h" +#include "tools/util/flags.h" + +namespace { + +constexpr auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6; -static void print_usage(char* argv0) { +constexpr bool kColorIsPossible = +#if SPIRV_COLOR_TERMINAL + true; +#else + false; +#endif + +void print_usage(const char* argv0) { printf(R"(%s - Compare two SPIR-V files Usage: %s @@ -38,11 +49,12 @@ logical transformation from src to dst, in src's id-space. -h, --help Print this help. --version Display diff version information. - --color Force color output. The default when printing to a terminal. - Overrides a previous --no-color option. - --no-color Don't print in color. Overrides a previous --color option. - The default when output goes to something other than a - terminal (e.g. a pipe, or a shell redirection). + --color Force color output. The default when printing to a terminal. + If both --color and --no-color is present, --no-color prevails. + --no-color Don't print in color. The default when output goes to + something other than a terminal (e.g. a pipe, or a shell + redirection). + If both --color and --no-color is present, --no-color prevails. --no-indent Don't indent instructions. @@ -58,9 +70,7 @@ logical transformation from src to dst, in src's id-space. argv0, argv0); } -static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6; - -static bool is_assembly(const char* path) { +bool is_assembly(const char* path) { const char* suffix = strrchr(path, '.'); if (suffix == nullptr) { return false; @@ -69,7 +79,7 @@ static bool is_assembly(const char* path) { return strcmp(suffix, ".spvasm") == 0; } -static std::unique_ptr load_module(const char* path) { +std::unique_ptr load_module(const char* path) { if (is_assembly(path)) { std::vector contents; if (!ReadTextFile(path, &contents)) return {}; @@ -89,101 +99,62 @@ static std::unique_ptr load_module(const char* path) { contents.data(), contents.size()); } -int main(int argc, char** argv) { - const char* src_file = nullptr; - const char* dst_file = nullptr; - bool color_is_possible = -#if SPIRV_COLOR_TERMINAL - true; -#else - false; -#endif - bool force_color = false; - bool force_no_color = false; - bool allow_indent = true; - bool no_header = false; - bool dump_id_map = false; - bool ignore_set_binding = false; - bool ignore_location = false; - - for (int argi = 1; argi < argc; ++argi) { - if ('-' == argv[argi][0]) { - switch (argv[argi][1]) { - case 'h': - print_usage(argv[0]); - return 0; - case '-': { - // Long options - if (strcmp(argv[argi], "--no-color") == 0) { - force_no_color = true; - force_color = false; - } else if (strcmp(argv[argi], "--color") == 0) { - force_no_color = false; - force_color = true; - } else if (strcmp(argv[argi], "--no-indent") == 0) { - allow_indent = false; - } else if (strcmp(argv[argi], "--no-header") == 0) { - no_header = true; - } else if (strcmp(argv[argi], "--with-id-map") == 0) { - dump_id_map = true; - } else if (strcmp(argv[argi], "--ignore-set-binding") == 0) { - ignore_set_binding = true; - } else if (strcmp(argv[argi], "--ignore-location") == 0) { - ignore_location = true; - } else if (strcmp(argv[argi], "--help") == 0) { - print_usage(argv[0]); - return 0; - } else if (strcmp(argv[argi], "--version") == 0) { - printf("%s\n", spvSoftwareVersionDetailsString()); - printf("Target: %s\n", - spvTargetEnvDescription(kDefaultEnvironment)); - return 0; - } else { - print_usage(argv[0]); - return 1; - } - } break; - default: - print_usage(argv[0]); - return 1; - } - } else { - if (src_file == nullptr) { - src_file = argv[argi]; - } else if (dst_file == nullptr) { - dst_file = argv[argi]; - } else { - fprintf(stderr, "error: More than two input files specified\n"); - return 1; - } - } +} // namespace + +// clang-format off +FLAG_SHORT_bool(h, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( help, /* default_value= */ false, /* required= */false); +FLAG_LONG_bool( version, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( color, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( no_color, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( no_indent, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( no_header, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( with_id_map, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( ignore_set_binding, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( ignore_location, /* default_value= */ false, /* required= */ false); +// clang-format on + +int main(int, const char* argv[]) { + if (!flags::Parse(argv)) { + return 1; } - if (src_file == nullptr || dst_file == nullptr) { + if (flags::h.value() || flags::help.value()) { print_usage(argv[0]); - return 1; + return 0; } - spvtools::diff::Options options; + if (flags::version.value()) { + printf("%s\n", spvSoftwareVersionDetailsString()); + printf("Target: %s\n", spvTargetEnvDescription(kDefaultEnvironment)); + return 0; + } - if (allow_indent) options.indent = true; - if (no_header) options.no_header = true; - if (dump_id_map) options.dump_id_map = true; - if (ignore_set_binding) options.ignore_set_binding = true; - if (ignore_location) options.ignore_location = true; + if (flags::positional_arguments.size() != 2) { + fprintf(stderr, "error: two input files required.\n"); + return 1; + } - if (color_is_possible && !force_no_color) { - bool output_is_tty = true; #if defined(_POSIX_VERSION) - output_is_tty = isatty(fileno(stdout)); + const bool output_is_tty = isatty(fileno(stdout)); +#else + const bool output_is_tty = true; #endif - if (output_is_tty || force_color) { - options.color_output = true; - } - } - std::unique_ptr src = load_module(src_file); - std::unique_ptr dst = load_module(dst_file); + const std::string& src_file = flags::positional_arguments[0]; + const std::string& dst_file = flags::positional_arguments[1]; + + spvtools::diff::Options options; + options.color_output = (output_is_tty || flags::color.value()) && + !flags::no_color.value() && kColorIsPossible; + options.indent = !flags::no_indent.value(); + options.no_header = flags::no_header.value(); + options.dump_id_map = flags::with_id_map.value(); + options.ignore_set_binding = flags::ignore_set_binding.value(); + options.ignore_location = flags::ignore_location.value(); + + std::unique_ptr src = load_module(src_file.c_str()); + std::unique_ptr dst = load_module(dst_file.c_str()); if (!src) { fprintf(stderr, "error: Loading src file\n"); From 016bb3ae7f2bea7c86c25fa1d6d4df47b78700fd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 4 Mar 2023 17:40:04 +0000 Subject: [PATCH 075/523] roll deps (#5139) * Roll external/googletest/ 2d4f20876..cead3d57c (1 commit) https://github.com/google/googletest/compare/2d4f208765af...cead3d57c93f $ git log 2d4f20876..cead3d57c --date=short --no-merges --format='%ad %ae %s' 2023-03-03 absl-team Internal Code Change Created with: roll-dep external/googletest * Roll external/re2/ 3a8436ac4..f0402c039 (1 commit) https://github.com/google/re2/compare/3a8436ac4361...f0402c0397cd $ git log 3a8436ac4..f0402c039 --date=short --no-merges --format='%ad %ae %s' 2023-03-03 junyer Update a comment in `DFA::WorkqToCachedState()`. 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 6dc3f03fa0..fc1df14b1d 100644 --- a/DEPS +++ b/DEPS @@ -5,12 +5,12 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': '2d4f208765af7fa376b878860a7677ecc0bc390a', + 'googletest_revision': 'cead3d57c93ff8c4e5c1bbae57a5c0b0b0f6e168', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', - 're2_revision': '3a8436ac436124a57a4e22d5c8713a2d42b381d7', + 're2_revision': 'f0402c0397cd4cfba17203abd5b617558316af0c', 'spirv_headers_revision': '295cf5fb3bfe2454360e82b26bae7fc0de699abe', } From 3033cf428e6de3e5766f85caa9dbaab0f57a51ea Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 7 Mar 2023 14:35:53 +0000 Subject: [PATCH 076/523] Roll external/googletest/ cead3d57c..e1ee0fa3e (9 commits) (#5140) https://github.com/google/googletest/compare/cead3d57c93f...e1ee0fa3e121 $ git log cead3d57c..e1ee0fa3e --date=short --no-merges --format='%ad %ae %s' 2023-03-06 dinor Fix indentation syntax error in feature request issue template 2023-03-03 tomhughes Fix compilation with -Wundef. 2023-03-03 tomhughes Always specify definitions for internal macros 2023-03-03 tomhughes Remove GTEST_FOR_GOOGLE_ macro 2023-03-03 tomhughes Replace "#if GTEST_HAS_ABSL" with "#ifdef GTEST_HAS_ABSL" 2023-03-03 tomhughes Use "#ifdef" with public macros 2023-03-03 tomhughes Only define GTEST_IS_THREADSAFE to 1, not 0 2023-03-03 tomhughes Always specify definitions for internal macros 2023-03-03 tomhughes Use "#ifdef GTEST_OS_..." instead of "#if GTEST_OS_..." 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 fc1df14b1d..9f5d7507d1 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': 'cead3d57c93ff8c4e5c1bbae57a5c0b0b0f6e168', + 'googletest_revision': 'e1ee0fa3e121e819c7a76d4d3b417de8f73ebfd7', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From 690a9a4060d07e662da2ba97a26f1630e433c9e5 Mon Sep 17 00:00:00 2001 From: James Price Date: Tue, 7 Mar 2023 16:44:56 -0500 Subject: [PATCH 077/523] Add explicit deduction guide for FlagRegistration (#5141) This fixes a -Wctad-maybe-unsupported error. --- tools/util/flags.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/util/flags.h b/tools/util/flags.h index c8abfd5ac5..20bb3693ba 100644 --- a/tools/util/flags.h +++ b/tools/util/flags.h @@ -253,6 +253,10 @@ struct FlagRegistration { } }; +// Explicit deduction guide to avoid `-Wctad-maybe-unsupported`. +template +FlagRegistration(Flag&, std::string&&, bool, bool) -> FlagRegistration; + } // namespace flags #endif // INCLUDE_SPIRV_TOOLS_UTIL_FLAGS_HPP_ From db0c3d83dc6c97f4cc5e11fb6dcba318578f290b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 8 Mar 2023 12:11:38 +0000 Subject: [PATCH 078/523] Roll external/googletest/ e1ee0fa3e..a798c2f10 (4 commits) (#5142) https://github.com/google/googletest/compare/e1ee0fa3e121...a798c2f10200 $ git log e1ee0fa3e..a798c2f10 --date=short --no-merges --format='%ad %ae %s' 2023-03-07 tomhughes Add -Wundef to the CI scripts when building with Bazel 2023-03-07 tomhughes Fix compilation of googletest-printers-test.cc when using -Wundef 2023-03-07 absl-team Suppress std::string DLL interface warning introduced in commit f063cd25c90cbd4089a0ff96f5991df4f2721338 2023-03-07 absl-team Internal Code Change 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 9f5d7507d1..257f545541 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': 'e1ee0fa3e121e819c7a76d4d3b417de8f73ebfd7', + 'googletest_revision': 'a798c2f10200b6293a5cc236b5f41b26c1ae7378', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From 42267721e1d67ccc9fada23899357bb9b25ace23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Wed, 8 Mar 2023 16:12:41 +0100 Subject: [PATCH 079/523] build: tool to generate a CHANGELOG from tags (#5136) This small utility parses the CHANGES file to generate a CHANGELOG that can be used for GitHub releases. This will be used by the GitHub workflow to make releases automatic. Given a CHANGES file path, a tag, the script extract the editorialized changelog, and writes it to a given output file. --- utils/generate_changelog.py | 98 +++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 utils/generate_changelog.py diff --git a/utils/generate_changelog.py b/utils/generate_changelog.py new file mode 100644 index 0000000000..54db728285 --- /dev/null +++ b/utils/generate_changelog.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python + +# 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. + +# Args: +# Updates an output file with changelog from the given CHANGES file and tag. +# - search for first line matching in file +# - search for the next line with a tag +# - writes all the lines in between those 2 tags into + +import errno +import os +import os.path +import re +import subprocess +import logging +import sys + +# Regex to match the SPIR-V version tag. +# Example of matching tags: +# - v2020.1 +# - v2020.1-dev +# - v2020.1.rc1 +VERSION_REGEX = re.compile(r'^(v\d+\.\d+) +[0-9]+-[0-9]+-[0-9]+$') + +def mkdir_p(directory): + """Make the directory, and all its ancestors as required. Any of the + directories are allowed to already exist.""" + + if directory == "": + # We're being asked to make the current directory. + return + + try: + os.makedirs(directory) + except OSError as e: + if e.errno == errno.EEXIST and os.path.isdir(directory): + pass + else: + raise + +def main(): + FORMAT = '%(asctime)s %(message)s' + logging.basicConfig(format="[%(asctime)s][%(levelname)-8s] %(message)s", datefmt="%H:%M:%S") + if len(sys.argv) != 4: + logging.error("usage: {} ".format(sys.argv[0])) + sys.exit(1) + + changes_path = sys.argv[1] + start_tag = sys.argv[2] + output_file_path = sys.argv[3] + + changelog = [] + has_found_start = False + with open(changes_path, "r") as file: + for line in file.readlines(): + m = VERSION_REGEX.match(line) + if m: + print(m.groups()[0]) + print(start_tag) + if has_found_start: + break; + if start_tag == m.groups()[0]: + has_found_start = True + continue + + if has_found_start: + changelog.append(line) + + if not has_found_start: + logging.error("No tag matching {} found.".format(start_tag)) + sys.exit(1) + + content = "".join(changelog) + if os.path.isfile(output_file_path): + with open(output_file_path, 'r') as f: + if content == f.read(): + sys.exit(0) + + mkdir_p(os.path.dirname(output_file_path)) + with open(output_file_path, 'w') as f: + f.write(content) + sys.exit(0) + +if __name__ == '__main__': + main() From c069a5c7ee275d193c247f86c5735747b7081dca Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 9 Mar 2023 11:06:41 +0100 Subject: [PATCH 080/523] roll deps (#5144) * Roll external/googletest/ a798c2f10..48a1b1105 (2 commits) https://github.com/google/googletest/compare/a798c2f10200...48a1b110583d $ git log a798c2f10..48a1b1105 --date=short --no-merges --format='%ad %ae %s' 2023-03-08 absl-team Add a comment to clarify Fuchsia process launcher requirement. 2023-03-07 absl-team Apply clang-tidy fixes Created with: roll-dep external/googletest * Roll external/spirv-headers/ 295cf5fb3..1feaf4414 (9 commits) https://github.com/KhronosGroup/SPIRV-Headers/compare/295cf5fb3bfe...1feaf4414eb2 $ git log 295cf5fb3..1feaf4414 --date=short --no-merges --format='%ad %ae %s' 2023-03-08 arvind.sudarsanam Fix error in merge conflict resolution 2023-03-06 ben.ashbaugh headers support for SPV_INTEL_bfloat16_conversion 2023-03-03 arvind.sudarsanam Add parameters 2023-03-03 arvind.sudarsanam Remove redundant extensions entry 2023-03-02 arvind.sudarsanam Add support for SPV_INTEL_fpga_latency_control extension 2023-03-01 wooykim SPV_QCOM_image_processing 2023-03-01 wooykim SPV_QCOM_image_processing 2023-02-14 wooykim SPV_QCOM_image_processing 2023-02-14 wooykim SPV_QCOM_image_processing 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 257f545541..363037deac 100644 --- a/DEPS +++ b/DEPS @@ -5,13 +5,13 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': 'a798c2f10200b6293a5cc236b5f41b26c1ae7378', + 'googletest_revision': '48a1b110583dd55e5076952b2acd772d9aaf6372', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', 're2_revision': 'f0402c0397cd4cfba17203abd5b617558316af0c', - 'spirv_headers_revision': '295cf5fb3bfe2454360e82b26bae7fc0de699abe', + 'spirv_headers_revision': '1feaf4414eb2b353764d01d88f8aa4bcc67b60db', } deps = { From b029037aaad8f616ebc9475b0c82adcf2892b7a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 9 Mar 2023 18:24:20 +0100 Subject: [PATCH 081/523] Revert changes around CHANGES file. (#5143) * Revert "build: allow update_build to generate fake version (#5098)" This reverts commit 7823b8ff4a58ce7578c41f0a9f0488d84dfa8210. * Revert "build: stop parsing CHANGES file. (#5067)" This reverts commit fcfc3c580c75be90a33711dd894dec58ebde9eec. --- Android.mk | 4 +- BUILD.bazel | 5 +- BUILD.gn | 4 +- source/CMakeLists.txt | 5 +- utils/update_build_version.py | 110 ++++++++++++---------------------- 5 files changed, 49 insertions(+), 79 deletions(-) diff --git a/Android.mk b/Android.mk index 8a70206629..a4e7615fad 100644 --- a/Android.mk +++ b/Android.mk @@ -311,9 +311,9 @@ define gen_spvtools_build_version_inc $(call generate-file-dir,$(1)/dummy_filename) $(1)/build-version.inc: \ $(LOCAL_PATH)/utils/update_build_version.py \ - $(LOCAL_PATH) + $(LOCAL_PATH)/CHANGES @$(HOST_PYTHON) $(LOCAL_PATH)/utils/update_build_version.py \ - $(LOCAL_PATH) $(1)/build-version.inc + $(LOCAL_PATH)/CHANGES $(1)/build-version.inc @echo "[$(TARGET_ARCH_ABI)] Generate : build-version.inc <= CHANGES" $(LOCAL_PATH)/source/software_version.cpp: $(1)/build-version.inc endef diff --git a/BUILD.bazel b/BUILD.bazel index 759f043a8c..141509def2 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -104,9 +104,10 @@ py_binary( genrule( name = "build_version_inc", + srcs = ["CHANGES"], outs = ["build-version.inc"], - cmd = "SOURCE_DATE_EPOCH=0 $(location :update_build_version) $(RULEDIR) $(location build-version.inc)", - cmd_bat = "set SOURCE_DATE_EPOCH=0 && $(location :update_build_version) $(RULEDIR) $(location build-version.inc)", + cmd = "SOURCE_DATE_EPOCH=0 $(location :update_build_version) $(location CHANGES) $(location build-version.inc)", + cmd_bat = "set SOURCE_DATE_EPOCH=0 && $(location :update_build_version) $(location CHANGES) $(location build-version.inc)", # This is explicitly tools and not exec_tools because we run it locally (on the host platform) instead of # (potentially remotely) on the execution platform. tools = [":update_build_version"], diff --git a/BUILD.gn b/BUILD.gn index 155a6b14cf..c56bea8139 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -262,12 +262,12 @@ action("spvtools_generators_inc") { action("spvtools_build_version") { script = "utils/update_build_version.py" - repo_path = "." + changes_file = "CHANGES" inc_file = "${target_gen_dir}/build-version.inc" outputs = [ inc_file ] args = [ - rebase_path(repo_path, root_build_dir), + rebase_path(changes_file, root_build_dir), rebase_path(inc_file, root_build_dir), ] } diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index b5924f516e..acfa0c123b 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -195,11 +195,14 @@ set(SPIRV_TOOLS_BUILD_VERSION_INC ${spirv-tools_BINARY_DIR}/build-version.inc) set(SPIRV_TOOLS_BUILD_VERSION_INC_GENERATOR ${spirv-tools_SOURCE_DIR}/utils/update_build_version.py) +set(SPIRV_TOOLS_CHANGES_FILE + ${spirv-tools_SOURCE_DIR}/CHANGES) add_custom_command(OUTPUT ${SPIRV_TOOLS_BUILD_VERSION_INC} COMMAND ${PYTHON_EXECUTABLE} ${SPIRV_TOOLS_BUILD_VERSION_INC_GENERATOR} - ${spirv-tools_SOURCE_DIR} ${SPIRV_TOOLS_BUILD_VERSION_INC} + ${SPIRV_TOOLS_CHANGES_FILE} ${SPIRV_TOOLS_BUILD_VERSION_INC} DEPENDS ${SPIRV_TOOLS_BUILD_VERSION_INC_GENERATOR} + ${SPIRV_TOOLS_CHANGES_FILE} COMMENT "Update build-version.inc in the SPIRV-Tools build directory (if necessary).") # Convenience target for standalone generation of the build-version.inc file. # This is not required for any dependence chain. diff --git a/utils/update_build_version.py b/utils/update_build_version.py index 871036f24d..5a78ada261 100755 --- a/utils/update_build_version.py +++ b/utils/update_build_version.py @@ -17,13 +17,16 @@ # Updates an output file with version info unless the new content is the same # as the existing content. # -# Args: +# Args: # # The output file will contain a line of text consisting of two C source syntax # string literals separated by a comma: -# - The software version deduced from the last release tag. +# - The software version deduced from the given CHANGES file. # - A longer string with the project name, the software version number, and -# git commit information for this release. +# git commit information for the CHANGES file's directory. The commit +# information is the output of "git describe" if that succeeds, or "git +# rev-parse HEAD" if that succeeds, or otherwise a message containing the +# phrase "unknown hash". # The string contents are escaped as necessary. import datetime @@ -36,13 +39,6 @@ import sys import time -# Regex to match the SPIR-V version tag. -# Example of matching tags: -# - v2020.1 -# - v2020.1-dev -# - v2020.1.rc1 -VERSION_REGEX = re.compile(r'^v(\d+)\.(\d+)(-dev|rc\d+)?$') - # Format of the output generated by this script. Example: # "v2023.1", "SPIRV-Tools v2023.1 0fc5526f2b01a0cc89192c10cf8bef77f1007a62, 2023-01-18T14:51:49" OUTPUT_FORMAT = '"{version_tag}", "SPIRV-Tools {version_tag} {description}"\n' @@ -86,66 +82,38 @@ def command_output(cmd, directory): return False, None return p.returncode == 0, stdout -def deduce_last_release(repo_path): - """Returns a software version number parsed from git tags.""" +def deduce_software_version(changes_file): + """Returns a tuple (success, software version number) parsed from the + given CHANGES file. - success, tag_list = command_output(['git', 'tag', '--sort=-v:refname'], repo_path) - if not success: - return False, None - - latest_version_tag = None - for tag in tag_list.decode().splitlines(): - if VERSION_REGEX.match(tag): - latest_version_tag = tag - break - - if latest_version_tag is None: - logging.error("No tag matching version regex matching.") - return False, None - return True, latest_version_tag - -def get_last_release_tuple(repo_path): - success, version = deduce_last_release(repo_path) - if not success: - return False, None - - m = VERSION_REGEX.match(version) - if len(m.groups()) != 3: - return False, None - return True, (int(m.groups()[0]), int(m.groups()[1])) + Success is set to True if the software version could be deduced. + Software version is undefined if success if False. + Function expects the CHANGES file to describes most recent versions first. + """ -def deduce_current_release(repo_path): - status, version_tuple = get_last_release_tuple(repo_path) - if not status: + # Match the first well-formed version-and-date line + # Allow trailing whitespace in the checked-out source code has + # unexpected carriage returns on a linefeed-only system such as + # Linux. + pattern = re.compile(r'^(v\d+\.\d+(-dev)?) \d\d\d\d-\d\d-\d\d\s*$') + with open(changes_file, mode='r') as f: + for line in f.readlines(): + match = pattern.match(line) + if match: + return True, match.group(1) return False, None - last_release_tag = "v{}.{}-dev".format(*version_tuple) - success, tag_list = command_output(['git', 'tag', '--contains'], repo_path) - if success: - if last_release_tag in set(tag_list.decode().splitlines()): - return True, last_release_tag - else: - logging.warning("Could not check tags for commit. Assuming -dev version.") - - now_year = datetime.datetime.now().year - if version_tuple[0] == now_year: - version_tuple = (now_year, version_tuple[1] + 1) - else: - version_tuple = (now_year, 1) - - return True, "v{}.{}-dev".format(*version_tuple) -def get_description_for_head(repo_path): +def describe(repo_path): """Returns a string describing the current Git HEAD version as descriptively - as possible, in order of priority: - - git describe output - - git rev-parse HEAD output - - "unknown-hash, " - """ + as possible. + + 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: - success, output = command_output(['git', 'rev-parse', 'HEAD'], repo_path) + output = command_output(['git', 'rev-parse', 'HEAD'], repo_path) if success: # decode() is needed here for Python3 compatibility. In Python2, @@ -161,12 +129,9 @@ def get_description_for_head(repo_path): # reproducible builds, allow the builder to override the wall # clock time with environment variable SOURCE_DATE_EPOCH # containing a (presumably) fixed timestamp. - if 'SOURCE_DATE_EPOCH' in os.environ: - timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) - iso_date = datetime.datetime.utcfromtimestamp(timestamp).isoformat() - else: - iso_date = datetime.datetime.now().isoformat() - return "unknown_hash, {}".format(iso_date) + timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) + iso_date = datetime.datetime.utcfromtimestamp(timestamp).isoformat() + return "unknown hash, {}".format(iso_date) def main(): FORMAT = '%(asctime)s %(message)s' @@ -175,15 +140,16 @@ def main(): logging.error("usage: {} ".format(sys.argv[0])) sys.exit(1) - repo_path = os.path.realpath(sys.argv[1]) + changes_file_path = os.path.realpath(sys.argv[1]) output_file_path = sys.argv[2] - success, version = deduce_current_release(repo_path) + success, version = deduce_software_version(changes_file_path) if not success: - logging.warning("Could not deduce latest release version from history.") - version = "unknown_version" + logging.error("Could not deduce latest release version from {}.".format(changes_file_path)) + sys.exit(1) - description = get_description_for_head(repo_path) + repo_path = os.path.dirname(changes_file_path) + description = describe(repo_path) content = OUTPUT_FORMAT.format(version_tag=version, description=description) # Escape file content. From 01828dac778d08f4ebafd2e06bd419f6c84e5984 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 10 Mar 2023 11:43:34 +0100 Subject: [PATCH 082/523] Roll external/googletest/ 48a1b1105..50e07d1c9 (1 commit) (#5148) https://github.com/google/googletest/compare/48a1b110583d...50e07d1c9287 $ git log 48a1b1105..50e07d1c9 --date=short --no-merges --format='%ad %ae %s' 2023-03-09 absl-team Apply clang-tidy fixes 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 363037deac..3a4cc2cfd3 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': '48a1b110583dd55e5076952b2acd772d9aaf6372', + 'googletest_revision': '50e07d1c92875e66138d5d5ee3bb46ef237115bb', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From fba26fd60677c2f5bbb37eb36cefef263f3717b0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 11 Mar 2023 12:15:52 +0000 Subject: [PATCH 083/523] roll deps (#5152) * Roll external/googletest/ 50e07d1c9..038e392eb (1 commit) https://github.com/google/googletest/compare/50e07d1c9287...038e392ebd80 $ git log 50e07d1c9..038e392eb --date=short --no-merges --format='%ad %ae %s' 2023-03-10 lawrencews [gtest] Drop custom-rolled heterogeneous comparator functors in favor of C++ standard ones Created with: roll-dep external/googletest * Roll external/re2/ f0402c039..b059ae85c (1 commit) https://github.com/google/re2/compare/f0402c0397cd...b059ae85c83c $ git log f0402c039..b059ae85c --date=short --no-merges --format='%ad %ae %s' 2023-03-10 junyer Move inst_ out of the blob of memory for a State. 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 3a4cc2cfd3..3f1af149e7 100644 --- a/DEPS +++ b/DEPS @@ -5,12 +5,12 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': '50e07d1c92875e66138d5d5ee3bb46ef237115bb', + 'googletest_revision': '038e392ebd8081c756e180475cc361f711fb438d', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', - 're2_revision': 'f0402c0397cd4cfba17203abd5b617558316af0c', + 're2_revision': 'b059ae85c83ca6b1f29dba20e92e4acb85cb5b29', 'spirv_headers_revision': '1feaf4414eb2b353764d01d88f8aa4bcc67b60db', } From 44d72a9b36702f093dd20815561a56778b2d181e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 13 Mar 2023 11:33:58 +0100 Subject: [PATCH 084/523] Prepare release v2023.2 (#5151) --- CHANGES | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index f24da418e8..dbe31a0c03 100644 --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,22 @@ Revision history for SPIRV-Tools -v2023.2-dev 2023-01-17 - - Start v2023.2-dev +v2023.2 2023-03-10 + - General + - build: move from c++11 to c++17 (#4983) + - tools: refactorize tools flags parsing. (#5111) + - Add C interface for Optimizer (#5030) + - libspirv.cpp: adds c++ api for spvBinaryParse (#5109) + - build: change the way we set cxx version for bazel. (#5114) + - Optimizer + - Fix null pointer in FoldInsertWithConstants. (#5093) + - Fix removal of dependent non-semantic instructions (#5122) + - Remove duplicate lists of constant and type opcodes (#5106) + - opt: fix spirv ABI on Linux again. (#5113) + - Validator + - Validate decoration of structs with RuntimeArray (#5094) + - Validate operand type before operating on it (#5092) + - spirv-val: Conditional Branch without an exit is invalid in loop header (#5069) + - spirv-val: Initial SPV_EXT_mesh_shader builtins (#5080) v2023.1 2023-01-17 - General From 7cefd5f5f806e90a054964ad8ec8586f5c277131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 13 Mar 2023 16:18:01 +0100 Subject: [PATCH 085/523] Change default permissions for workflows (#5149) * change default workflow permission to read-all Fixes #5147 * permission: content read-only * remove bad changes --- .github/workflows/autoroll.yml | 5 ++++- .github/workflows/bazel.yml | 2 ++ .github/workflows/wasm.yml | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/autoroll.yml b/.github/workflows/autoroll.yml index a33034b38d..ec64d40a67 100644 --- a/.github/workflows/autoroll.yml +++ b/.github/workflows/autoroll.yml @@ -1,4 +1,6 @@ name: Update dependencies +permissions: + contents: read on: schedule: @@ -7,6 +9,8 @@ on: jobs: update-dependencies: + permissions: + contents: write name: Update dependencies runs-on: ubuntu-latest @@ -38,7 +42,6 @@ jobs: echo "changed=true" >> $GITHUB_OUTPUT fi id: update_dependencies - - name: Push changes and create PR if: steps.update_dependencies.outputs.changed == 'true' run: | diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index dfb5e5ae32..88700c44c2 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -1,4 +1,6 @@ name: Build and Test with Bazel +permissions: + contents: read on: push: diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index fa8951a16e..62c9af3842 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -1,4 +1,6 @@ name: Wasm Build +permissions: + contents: read on: [push, pull_request] From fcd53c8ed21483bc71f2ab9962c3d75310c84450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 13 Mar 2023 16:39:42 +0100 Subject: [PATCH 086/523] Add spirv-dump tool (#5146) * dump: add tool skeleton. This tool aims to be used a bit like objdump (hence the name). Allowing the user to dump some info from a spirv-binary. * add test structure for spirv-dump * add spirv-dump to bazel build file * fix licenses * fix compilation with ubsan * remove fdiagnostics * rename dump to objdump * move tests to test/tools * rename dump to objdump for bazel --- BUILD.bazel | 17 ++++ test/tools/CMakeLists.txt | 1 + test/tools/objdump/CMakeLists.txt | 23 +++++ test/tools/objdump/extract_source_test.cpp | 63 ++++++++++++++ tools/CMakeLists.txt | 13 ++- tools/objdump/extract_source.cpp | 56 +++++++++++++ tools/objdump/extract_source.h | 38 +++++++++ tools/objdump/objdump.cpp | 97 ++++++++++++++++++++++ 8 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 test/tools/objdump/CMakeLists.txt create mode 100644 test/tools/objdump/extract_source_test.cpp create mode 100644 tools/objdump/extract_source.cpp create mode 100644 tools/objdump/extract_source.h create mode 100644 tools/objdump/objdump.cpp diff --git a/BUILD.bazel b/BUILD.bazel index 141509def2..0afcfa9db9 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -304,6 +304,23 @@ cc_binary( ], ) +cc_binary( + name = "spirv-objdump", + srcs = [ + "tools/objdump/objdump.cpp", + "tools/objdump/extract_source.cpp", + "tools/objdump/extract_source.h", + ], + copts = COMMON_COPTS, + visibility = ["//visibility:public"], + deps = [ + ":tools_io", + ":tools_util", + ":spirv_tools_internal", + ":spirv_tools_opt_internal", + ], +) + cc_binary( name = "spirv-val", srcs = [ diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 0520bd7519..4898e576cc 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -26,3 +26,4 @@ add_spvtools_unittest( DEFINES TESTING=1) add_subdirectory(opt) +add_subdirectory(objdump) diff --git a/test/tools/objdump/CMakeLists.txt b/test/tools/objdump/CMakeLists.txt new file mode 100644 index 0000000000..46fae21a00 --- /dev/null +++ b/test/tools/objdump/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (c) 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. + +add_spvtools_unittest( + TARGET spirv_unit_test_tools_objdump + SRCS + extract_source_test.cpp + ${spirv-tools_SOURCE_DIR}/tools/util/flags.cpp + ${spirv-tools_SOURCE_DIR}/tools/util/cli_consumer.cpp + ${spirv-tools_SOURCE_DIR}/tools/objdump/extract_source.cpp + LIBS ${SPIRV_TOOLS_FULL_VISIBILITY} SPIRV-Tools-opt + DEFINES TESTING=1) diff --git a/test/tools/objdump/extract_source_test.cpp b/test/tools/objdump/extract_source_test.cpp new file mode 100644 index 0000000000..3fe633bc36 --- /dev/null +++ b/test/tools/objdump/extract_source_test.cpp @@ -0,0 +1,63 @@ +// Copyright (c) 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. + +#include "tools/objdump/extract_source.h" + +#include + +#include + +#include "source/opt/build_module.h" +#include "source/opt/ir_context.h" +#include "spirv-tools/libspirv.hpp" +#include "tools/util/cli_consumer.h" + +namespace { + +constexpr auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6; + +std::pair> extractSource( + const std::string& spv_source) { + std::unique_ptr ctx = spvtools::BuildModule( + kDefaultEnvironment, spvtools::utils::CLIMessageConsumer, spv_source, + spvtools::SpirvTools::kDefaultAssembleOption | + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + std::vector binary; + ctx->module()->ToBinary(&binary, /* skip_nop = */ false); + std::unordered_map output; + bool result = extract_source_from_module(binary, &output); + return std::make_pair(result, std::move(output)); +} + +} // namespace + +TEST(ExtractSourceTest, no_debug) { + std::string source = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 + %void = OpTypeVoid + %2 = OpTypeFunction %void + %bool = OpTypeBool + %4 = OpUndef %bool + %5 = OpFunction %void None %2 + %6 = OpLabel + OpReturn + OpFunctionEnd + )"; + + auto[success, result] = extractSource(source); + ASSERT_TRUE(success); + ASSERT_TRUE(result.size() == 0); +} diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 6bf7a1190c..4644a52595 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -16,6 +16,7 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES}) add_subdirectory(lesspipe) endif() add_subdirectory(emacs) +#add_subdirectory(objdump) # Add a SPIR-V Tools command line tool. Signature: # add_spvtools_tool( @@ -65,8 +66,18 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES}) LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}) target_include_directories(spirv-cfg PRIVATE ${spirv-tools_SOURCE_DIR} ${SPIRV_HEADER_INCLUDE_DIR}) + + add_spvtools_tool(TARGET spirv-objdump + SRCS objdump/objdump.cpp + objdump/extract_source.cpp + util/cli_consumer.cpp + ${COMMON_TOOLS_SRCS} + LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}) + target_include_directories(spirv-objdump PRIVATE ${spirv-tools_SOURCE_DIR} + ${SPIRV_HEADER_INCLUDE_DIR}) + set(SPIRV_INSTALL_TARGETS spirv-as spirv-dis spirv-val spirv-opt - spirv-cfg spirv-link spirv-lint) + spirv-cfg spirv-link spirv-lint spirv-objdump) if(NOT (${CMAKE_SYSTEM_NAME} STREQUAL "iOS")) set(SPIRV_INSTALL_TARGETS ${SPIRV_INSTALL_TARGETS} spirv-reduce) endif() diff --git a/tools/objdump/extract_source.cpp b/tools/objdump/extract_source.cpp new file mode 100644 index 0000000000..3722cf1080 --- /dev/null +++ b/tools/objdump/extract_source.cpp @@ -0,0 +1,56 @@ +// Copyright (c) 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. + +#include "extract_source.h" + +#include +#include +#include + +#include "source/opt/log.h" +#include "spirv-tools/libspirv.hpp" +#include "tools/util/cli_consumer.h" + +namespace { +constexpr auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6; +} // namespace + +bool extract_source_from_module( + const std::vector& binary, + std::unordered_map* output) { + auto context = spvtools::SpirvTools(kDefaultEnvironment); + context.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); + + spvtools::HeaderParser headerParser = + [](const spv_endianness_t endianess, + const spv_parsed_header_t& instruction) { + (void)endianess; + (void)instruction; + return SPV_SUCCESS; + }; + + spvtools::InstructionParser instructionParser = + [](const spv_parsed_instruction_t& instruction) { + (void)instruction; + return SPV_SUCCESS; + }; + + if (!context.Parse(binary, headerParser, instructionParser)) { + return false; + } + + // FIXME + (void)output; + return true; +} diff --git a/tools/objdump/extract_source.h b/tools/objdump/extract_source.h new file mode 100644 index 0000000000..1a8af21628 --- /dev/null +++ b/tools/objdump/extract_source.h @@ -0,0 +1,38 @@ +// Copyright (c) 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. + +#ifndef INCLUDE_SPIRV_TOOLS_EXTRACT_SOURCE_HPP_ +#define INCLUDE_SPIRV_TOOLS_EXTRACT_SOURCE_HPP_ + +#include +#include +#include + +// Parse a SPIR-V module, and extracts all HLSL source code from it. +// This function doesn't lift the SPIR-V code, but only relies on debug symbols. +// This means if the compiler didn't include some files, they won't show up. +// +// Returns a map of extracted from it. +// - `binary`: a vector containing the whole SPIR-V binary to extract source +// from. +// - `output`: mapping, mapping each filename +// (if defined) to its code. +// +// Returns `true` if the extraction succeeded, `false` otherwise. +// `output` value is undefined if `false` is returned. +bool extract_source_from_module( + const std::vector& binary, + std::unordered_map* output); + +#endif // INCLUDE_SPIRV_TOOLS_EXTRACT_SOURCE_HPP_ diff --git a/tools/objdump/objdump.cpp b/tools/objdump/objdump.cpp new file mode 100644 index 0000000000..520ff19f20 --- /dev/null +++ b/tools/objdump/objdump.cpp @@ -0,0 +1,97 @@ +// Copyright (c) 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. + +#include "extract_source.h" +#include "source/opt/log.h" +#include "tools/io.h" +#include "tools/util/cli_consumer.h" +#include "tools/util/flags.h" + +namespace { + +constexpr auto kHelpTextFmt = + R"(%s - Dumps information from a SPIR-V binary. + +Usage: %s [options] + +one of the following switches must be given: + --source Extract source files obtained from debug symbols, output to stdout. + --entrypoint Extracts the entrypoint name of the module, output to stdout. + --compiler-cmd Extracts the command line used to compile this module, output to stdout. + + +General options: + -h, --help Print this help. + --version Display assembler version information. + -f,--force Allow output file overwrite. + +Source dump options: + --list Do not extract source code, only print filenames to stdout. + --outdir Where shall the exrtacted HLSL/HLSL files be written to? + File written to stdout if '-' is given. Default is `-`. +)"; + +} // namespace + +// clang-format off +FLAG_SHORT_bool( h, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( help, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( version, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( source, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( entrypoint, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( compiler_cmd, /* default_value= */ false, /* required= */ false); +FLAG_SHORT_bool( f, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( force, /* default_value= */ false, /* required= */ false); +FLAG_LONG_string( outdir, /* default_value= */ "-", /* required= */ false); +FLAG_LONG_bool( list, /* default_value= */ false, /* required= */ false); +// clang-format on + +int main(int, const char** argv) { + if (!flags::Parse(argv)) { + return 1; + } + if (flags::h.value() || flags::help.value()) { + printf(kHelpTextFmt, argv[0], argv[0]); + return 0; + } + if (flags::version.value()) { + printf("%s\n", spvSoftwareVersionDetailsString()); + return 0; + } + + if (flags::positional_arguments.size() != 1) { + spvtools::Error(spvtools::utils::CLIMessageConsumer, nullptr, {}, + "expected exactly one input file."); + return 1; + } + if (flags::source.value() || flags::entrypoint.value() || + flags::compiler_cmd.value()) { + spvtools::Error(spvtools::utils::CLIMessageConsumer, nullptr, {}, + "not implemented yet."); + return 1; + } + + std::vector binary; + if (!ReadBinaryFile(flags::positional_arguments[0].c_str(), &binary)) { + return 1; + } + + if (flags::source.value()) { + std::unordered_map output; + return extract_source_from_module(binary, &output) ? 0 : 1; + } + + // FIXME: implement logic. + return 0; +} From 25b7608cbed7681c0ff6f32da4934e9f666b7f4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 13 Mar 2023 16:55:55 +0100 Subject: [PATCH 087/523] Add workflow for github releases. (#5145) * prepare workflow * remove release branch --- .github/workflows/release.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..787f49b0aa --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,21 @@ +name: Create a release branch from release tag + +on: + push: + tags: + - 'v[0-9]+.[0-9]+' + - '!v[0-9]+.[0-9]+.rc*' + +jobs: + prepare-release-job: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Prepare CHANGELOG for version + run: | + python utils/generate_changelog.py CHANGES ${{ github.ref_name }} VERSION_CHANGELOG + - name: Create release + run: | + gh release create -F VERSION_CHANGELOG ${{ github.ref_name }} + env: + GITHUB_TOKEN: ${{ github.token }} From a1f5556517e5d1d24b5282295e067db3634f96d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Mar 2023 16:08:19 +0000 Subject: [PATCH 088/523] build(deps): bump y18n from 4.0.0 to 4.0.3 in /tools/sva (#5155) Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.3. - [Release notes](https://github.com/yargs/y18n/releases) - [Changelog](https://github.com/yargs/y18n/blob/y18n-v4.0.3/CHANGELOG.md) - [Commits](https://github.com/yargs/y18n/compare/v4.0.0...y18n-v4.0.3) --- updated-dependencies: - dependency-name: y18n 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 e7b735e0e6..2dc95d8a48 100644 --- a/tools/sva/yarn.lock +++ b/tools/sva/yarn.lock @@ -1700,9 +1700,9 @@ write@1.0.3: mkdirp "^0.5.1" "y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" - integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== yallist@^2.1.2: version "2.1.2" From a45a4cd2185d53a08ed0a8010e7553fae0d372bb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 13 Mar 2023 18:04:00 +0000 Subject: [PATCH 089/523] Roll external/googletest/ 038e392eb..391ce627d (1 commit) (#5153) https://github.com/google/googletest/compare/038e392ebd80...391ce627def2 $ git log 038e392eb..391ce627d --date=short --no-merges --format='%ad %ae %s' 2023-03-11 absl-team Internal Code Change 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 3f1af149e7..717af7c30f 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': '038e392ebd8081c756e180475cc361f711fb438d', + 'googletest_revision': '391ce627def20c1e8a54d10b12949b15086473dd', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From 25f6c0cea5a573a1c9ebe334a44b096a30708fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 13 Mar 2023 19:04:19 +0100 Subject: [PATCH 090/523] Revert "Add workflow for github releases. (#5145)" (#5156) This reverts commit 25b7608cbed7681c0ff6f32da4934e9f666b7f4c. --- .github/workflows/release.yml | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 787f49b0aa..0000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Create a release branch from release tag - -on: - push: - tags: - - 'v[0-9]+.[0-9]+' - - '!v[0-9]+.[0-9]+.rc*' - -jobs: - prepare-release-job: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Prepare CHANGELOG for version - run: | - python utils/generate_changelog.py CHANGES ${{ github.ref_name }} VERSION_CHANGELOG - - name: Create release - run: | - gh release create -F VERSION_CHANGELOG ${{ github.ref_name }} - env: - GITHUB_TOKEN: ${{ github.token }} From 9743701ed5e497805a5ab8bb9c8fb3843b200e8c Mon Sep 17 00:00:00 2001 From: Alan Zhao Date: Wed, 15 Mar 2023 05:15:29 -0700 Subject: [PATCH 091/523] Explicitly #include in spirv_target_env.cpp (#5159) spirv_target_env.cpp uses std::pair, which is defined in utility. Right now, this compiles because utility is provided via transitive includes in other C++ standard library headers provided by the implementation. However, these transitive includes are not guaranteed to exist, and won't exist in certain cases (e.g. compiling against LLVM's libc++ with modules enabled.) --- source/spirv_target_env.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/spirv_target_env.cpp b/source/spirv_target_env.cpp index 9a03817426..585f8b65a2 100644 --- a/source/spirv_target_env.cpp +++ b/source/spirv_target_env.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include "source/spirv_constant.h" #include "spirv-tools/libspirv.h" From 8e6563b91361f0cba15bf38b549d30c6d767d849 Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Sat, 18 Mar 2023 10:01:50 +0900 Subject: [PATCH 092/523] spirv-val: Label new Vulkan VUID 07951 (#5154) --- source/val/validate_scopes.cpp | 2 +- source/val/validation_state.cpp | 4 ++-- test/val/val_barriers_test.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/val/validate_scopes.cpp b/source/val/validate_scopes.cpp index fa1dad9ec9..fa93e5b694 100644 --- a/source/val/validate_scopes.cpp +++ b/source/val/validate_scopes.cpp @@ -240,7 +240,7 @@ spv_result_t ValidateMemoryScope(ValidationState_t& _, const Instruction* inst, !_.HasCapability(spv::Capability::SubgroupBallotKHR) && !_.HasCapability(spv::Capability::SubgroupVoteKHR)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << _.VkErrorID(6997) << spvOpcodeString(opcode) + << _.VkErrorID(7951) << spvOpcodeString(opcode) << ": in Vulkan 1.0 environment Memory Scope is can not be " "Subgroup without SubgroupBallotKHR or SubgroupVoteKHR " "declared"; diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index c95eec366b..e43517850a 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -2163,8 +2163,6 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-PushConstant-06808); case 6925: return VUID_WRAP(VUID-StandaloneSpirv-Uniform-06925); - case 6997: - return VUID_WRAP(VUID-StandaloneSpirv-SubgroupVoteKHR-06997); case 7102: return VUID_WRAP(VUID-StandaloneSpirv-MeshEXT-07102); case 7320: @@ -2179,6 +2177,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-Base-07652); case 7703: return VUID_WRAP(VUID-StandaloneSpirv-Component-07703); + case 7951: + return VUID_WRAP(VUID-StandaloneSpirv-SubgroupVoteKHR-07951); default: return ""; // unknown id } diff --git a/test/val/val_barriers_test.cpp b/test/val/val_barriers_test.cpp index c86cdc1382..f160904078 100644 --- a/test/val/val_barriers_test.cpp +++ b/test/val/val_barriers_test.cpp @@ -361,7 +361,7 @@ OpControlBarrier %subgroup %subgroup %none CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-StandaloneSpirv-SubgroupVoteKHR-06997")); + AnyVUID("VUID-StandaloneSpirv-SubgroupVoteKHR-07951")); EXPECT_THAT( getDiagnosticString(), HasSubstr( @@ -775,7 +775,7 @@ OpMemoryBarrier %subgroup %acquire_release_uniform_workgroup CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-StandaloneSpirv-SubgroupVoteKHR-06997")); + AnyVUID("VUID-StandaloneSpirv-SubgroupVoteKHR-07951")); EXPECT_THAT( getDiagnosticString(), HasSubstr( From 44bc9bd2af79568215f4fd6f12bde4de7c37586d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Petit?= Date: Sat, 18 Mar 2023 01:05:12 +0000 Subject: [PATCH 093/523] build: cmake: support passing a custom source folder for GoogleTest (#5157) --- external/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 676ee979ea..81011f1a20 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -56,7 +56,9 @@ if (NOT ${SPIRV_SKIP_TESTS}) if (TARGET gmock) message(STATUS "Google Mock already configured") else() - set(GMOCK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/googletest) + if (NOT GMOCK_DIR) + set(GMOCK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/googletest) + endif() if(EXISTS ${GMOCK_DIR}) if(MSVC) # Our tests use ::testing::Combine. Work around a compiler @@ -73,7 +75,7 @@ if (NOT ${SPIRV_SKIP_TESTS}) # gtest requires special defines for building as a shared # library, simply always build as static. push_variable(BUILD_SHARED_LIBS 0) - add_subdirectory(${GMOCK_DIR} EXCLUDE_FROM_ALL) + add_subdirectory(${GMOCK_DIR} ${CMAKE_CURRENT_BINARY_DIR}/googletest EXCLUDE_FROM_ALL) pop_variable(BUILD_SHARED_LIBS) endif() endif() From ae435df4a6a9e36a9aaa928d1e8cbfbfdd2d9053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 20 Mar 2023 10:13:19 +0100 Subject: [PATCH 094/523] git: add release workflow (#5158) --- .github/workflows/release.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..ada943169e --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,24 @@ +name: Create a release branch from release tag +permissions: + contents: write + +on: + push: + tags: + - 'v[0-9]+.[0-9]+' + - '!v[0-9]+.[0-9]+.rc*' + +jobs: + prepare-release-job: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Prepare CHANGELOG for version + run: | + python utils/generate_changelog.py CHANGES "${{ github.ref_name }}" VERSION_CHANGELOG + - name: Create release + run: | + gh release create -t "Release ${{ github.ref_name }}" -F VERSION_CHANGELOG "${{ github.ref_name }}" + env: + GITHUB_TOKEN: ${{ github.token }} + From 9c9144b65c3f70c0a146afec7a5623c024b2c3ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 20 Mar 2023 14:06:58 +0100 Subject: [PATCH 095/523] ci: fix dependency updater bot (#5165) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thought `content` permission was enough to create (not merge) PRs, but turns out the `pull-request` permission is also required. This should unblock the bot. Signed-off-by: Nathan Gauër --- .github/workflows/autoroll.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/autoroll.yml b/.github/workflows/autoroll.yml index ec64d40a67..4520309d45 100644 --- a/.github/workflows/autoroll.yml +++ b/.github/workflows/autoroll.yml @@ -11,6 +11,7 @@ jobs: update-dependencies: permissions: contents: write + pull-requests: write name: Update dependencies runs-on: ubuntu-latest From f56f2b6fd22d4f17a283734d12a081344d6e1dfa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 09:57:12 -0400 Subject: [PATCH 096/523] roll deps (#5166) * Roll external/googletest/ 391ce627d..471087fbf (6 commits) https://github.com/google/googletest/compare/391ce627def2...471087fbfcbc $ git log 391ce627d..471087fbf --date=short --no-merges --format='%ad %ae %s' 2023-03-20 absl-team Introduce std::make_unique and bool literals where possible 2023-03-20 absl-team Remove unused using-declarations in sample unit tests 2023-03-19 absl-team Fix typo in test case name. 2023-03-16 deannagarcia Move transitive dependencies of googletest to googletest_deps.bzl to allow other bazel projects to depend on that rule instead of googletests' transitive dependencies directly. 2023-03-02 sergionso Environment variables are accessible in UWP/WinRT apps 2023-03-06 nikiforov.al __cpp_char8_t does not cover std::u8string implementation, but __cpp_lib_char8_t does Created with: roll-dep external/googletest * Roll external/re2/ b059ae85c..11073deb7 (1 commit) https://github.com/google/re2/compare/b059ae85c83c...11073deb73b3 $ git log b059ae85c..11073deb7 --date=short --no-merges --format='%ad %ae %s' 2023-03-20 junyer Add Clang 16 to the build matrix. 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 717af7c30f..efcf884670 100644 --- a/DEPS +++ b/DEPS @@ -5,12 +5,12 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': '391ce627def20c1e8a54d10b12949b15086473dd', + 'googletest_revision': '471087fbfcbc3c66071189a67c313eb1d525ee51', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', - 're2_revision': 'b059ae85c83ca6b1f29dba20e92e4acb85cb5b29', + 're2_revision': '11073deb73b3d01018308863c0bcdfd0d51d3e70', 'spirv_headers_revision': '1feaf4414eb2b353764d01d88f8aa4bcc67b60db', } From 4dc3edeb94d96fe2760f28f6a0caff7563e5cc0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 20 Mar 2023 19:05:41 +0100 Subject: [PATCH 097/523] build: set std=c++17 for BUILD.gn (#5162) --- BUILD.gn | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/BUILD.gn b/BUILD.gn index c56bea8139..44954b2df1 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -374,6 +374,12 @@ config("spvtools_internal_config") { # Make MSVC report the correct value for __cplusplus cflags += [ "/Zc:__cplusplus" ] } + + if (!is_win) { + cflags += [ "-std=c++17" ] + } else { + cflags += [ "/std:c++17" ] + } } source_set("spvtools_headers") { From 90f6a2875fe606dc5f375e8c7da0af30f29bad06 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 21 Mar 2023 10:34:03 -0400 Subject: [PATCH 098/523] Roll external/googletest/ 471087fbf..fa8720982 (2 commits) (#5167) https://github.com/google/googletest/compare/471087fbfcbc...fa87209829d4 $ git log 471087fbf..fa8720982 --date=short --no-merges --format='%ad %ae %s' 2023-03-20 phoebeliang Revise documentation to include AbslStringify 2023-02-17 darryl Set CMP0069 policy to avoid warnings 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 efcf884670..4b39f3fbbb 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': '471087fbfcbc3c66071189a67c313eb1d525ee51', + 'googletest_revision': 'fa87209829d47f3fd7c6faf4e99d7d8799e3563d', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From 1a52c14ee3079e000cede82de8048017f2b243f7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 22 Mar 2023 09:23:27 -0400 Subject: [PATCH 099/523] Roll external/googletest/ fa8720982..974e18ee6 (2 commits) (#5168) https://github.com/google/googletest/compare/fa87209829d4...974e18ee6f14 $ git log fa8720982..974e18ee6 --date=short --no-merges --format='%ad %ae %s' 2023-03-21 absl-team Fix minor bug -- if ExecDeathTestChildMain() ever returns, we should exit with a non-zero status. 2023-03-21 absl-team Internal Code Change 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 4b39f3fbbb..e07f0ef3cf 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': 'fa87209829d47f3fd7c6faf4e99d7d8799e3563d', + 'googletest_revision': '974e18ee6f146a2418f9cea83170c640e7d622d6', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From 5aab2a8fef46c5e4a2825aedd0715f19ee124a97 Mon Sep 17 00:00:00 2001 From: davidroygsu <124539273+davidroygsu@users.noreply.github.com> Date: Wed, 22 Mar 2023 10:44:55 -0400 Subject: [PATCH 100/523] Include stdint.h (#5164) --- tools/objdump/extract_source.h | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/objdump/extract_source.h b/tools/objdump/extract_source.h index 1a8af21628..a163be200b 100644 --- a/tools/objdump/extract_source.h +++ b/tools/objdump/extract_source.h @@ -15,6 +15,7 @@ #ifndef INCLUDE_SPIRV_TOOLS_EXTRACT_SOURCE_HPP_ #define INCLUDE_SPIRV_TOOLS_EXTRACT_SOURCE_HPP_ +#include #include #include #include From 5f4e694e1022b7a6721ba14375b349e3dafcad4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Wed, 22 Mar 2023 23:57:18 +0100 Subject: [PATCH 101/523] Implement source extraction logic for spirv-objdump (#5150) * dump: add ability to extract HLSL from module Only adds the code to extract the source from the module. The extracted files are written to the given directory. Android NDK21 has C++17 support, but no std::filesystem support. (NDK22). As for now, the tool is not built on Android. Might be something to revisit is the need to have this tool on Android arises. --- BUILD.bazel | 1 + test/tools/CMakeLists.txt | 4 +- test/tools/objdump/extract_source_test.cpp | 208 ++++++++++++++++++++- tools/CMakeLists.txt | 24 +-- tools/objdump/extract_source.cpp | 183 ++++++++++++++++-- tools/objdump/extract_source.h | 2 +- tools/objdump/objdump.cpp | 93 ++++++++- 7 files changed, 478 insertions(+), 37 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index 0afcfa9db9..ae7f35c6d3 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -318,6 +318,7 @@ cc_binary( ":tools_util", ":spirv_tools_internal", ":spirv_tools_opt_internal", + "@spirv_headers//:spirv_cpp_headers", ], ) diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 4898e576cc..4c8989fe3b 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -26,4 +26,6 @@ add_spvtools_unittest( DEFINES TESTING=1) add_subdirectory(opt) -add_subdirectory(objdump) +if(NOT (${CMAKE_SYSTEM_NAME} STREQUAL "Android")) + add_subdirectory(objdump) +endif () diff --git a/test/tools/objdump/extract_source_test.cpp b/test/tools/objdump/extract_source_test.cpp index 3fe633bc36..0b81caa483 100644 --- a/test/tools/objdump/extract_source_test.cpp +++ b/test/tools/objdump/extract_source_test.cpp @@ -27,7 +27,7 @@ namespace { constexpr auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6; -std::pair> extractSource( +std::pair> ExtractSource( const std::string& spv_source) { std::unique_ptr ctx = spvtools::BuildModule( kDefaultEnvironment, spvtools::utils::CLIMessageConsumer, spv_source, @@ -36,7 +36,7 @@ std::pair> extractSource( std::vector binary; ctx->module()->ToBinary(&binary, /* skip_nop = */ false); std::unordered_map output; - bool result = extract_source_from_module(binary, &output); + bool result = ExtractSourceFromModule(binary, &output); return std::make_pair(result, std::move(output)); } @@ -57,7 +57,209 @@ TEST(ExtractSourceTest, no_debug) { OpFunctionEnd )"; - auto[success, result] = extractSource(source); + auto[success, result] = ExtractSource(source); ASSERT_TRUE(success); ASSERT_TRUE(result.size() == 0); } + +TEST(ExtractSourceTest, SimpleSource) { + std::string source = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "compute_1" + OpExecutionMode %1 LocalSize 1 1 1 + %2 = OpString "compute.hlsl" + OpSource HLSL 660 %2 "[numthreads(1, 1, 1)] void compute_1(){ }" + OpName %1 "compute_1" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %1 = OpFunction %3 None %4 + %5 = OpLabel + OpLine %2 1 41 + OpReturn + OpFunctionEnd + )"; + + auto[success, result] = ExtractSource(source); + ASSERT_TRUE(success); + ASSERT_TRUE(result.size() == 1); + ASSERT_TRUE(result["compute.hlsl"] == + "[numthreads(1, 1, 1)] void compute_1(){ }"); +} + +TEST(ExtractSourceTest, SourceContinued) { + std::string source = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "compute_1" + OpExecutionMode %1 LocalSize 1 1 1 + %2 = OpString "compute.hlsl" + OpSource HLSL 660 %2 "[numthreads(1, 1, 1)] " + OpSourceContinued "void compute_1(){ }" + OpName %1 "compute_1" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %1 = OpFunction %3 None %4 + %5 = OpLabel + OpLine %2 1 41 + OpReturn + OpFunctionEnd + )"; + + auto[success, result] = ExtractSource(source); + ASSERT_TRUE(success); + ASSERT_TRUE(result.size() == 1); + ASSERT_TRUE(result["compute.hlsl"] == + "[numthreads(1, 1, 1)] void compute_1(){ }"); +} + +TEST(ExtractSourceTest, OnlyFilename) { + std::string source = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "compute_1" + OpExecutionMode %1 LocalSize 1 1 1 + %2 = OpString "compute.hlsl" + OpSource HLSL 660 %2 + OpName %1 "compute_1" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %1 = OpFunction %3 None %4 + %5 = OpLabel + OpLine %2 1 41 + OpReturn + OpFunctionEnd + )"; + + auto[success, result] = ExtractSource(source); + ASSERT_TRUE(success); + ASSERT_TRUE(result.size() == 1); + ASSERT_TRUE(result["compute.hlsl"] == ""); +} + +TEST(ExtractSourceTest, MultipleFiles) { + std::string source = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "compute_1" + OpExecutionMode %1 LocalSize 1 1 1 + %2 = OpString "compute1.hlsl" + %3 = OpString "compute2.hlsl" + OpSource HLSL 660 %2 "some instruction" + OpSource HLSL 660 %3 "some other instruction" + OpName %1 "compute_1" + %4 = OpTypeVoid + %5 = OpTypeFunction %4 + %1 = OpFunction %4 None %5 + %6 = OpLabel + OpLine %2 1 41 + OpReturn + OpFunctionEnd + )"; + + auto[success, result] = ExtractSource(source); + ASSERT_TRUE(success); + ASSERT_TRUE(result.size() == 2); + ASSERT_TRUE(result["compute1.hlsl"] == "some instruction"); + ASSERT_TRUE(result["compute2.hlsl"] == "some other instruction"); +} + +TEST(ExtractSourceTest, MultilineCode) { + std::string source = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "compute_1" + OpExecutionMode %1 LocalSize 1 1 1 + %2 = OpString "compute.hlsl" + OpSource HLSL 660 %2 "[numthreads(1, 1, 1)] +void compute_1() { +} +" + OpName %1 "compute_1" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %1 = OpFunction %3 None %4 + %5 = OpLabel + OpLine %2 3 1 + OpReturn + OpFunctionEnd + )"; + + auto[success, result] = ExtractSource(source); + ASSERT_TRUE(success); + ASSERT_TRUE(result.size() == 1); + ASSERT_TRUE(result["compute.hlsl"] == + "[numthreads(1, 1, 1)]\nvoid compute_1() {\n}\n"); +} + +TEST(ExtractSourceTest, EmptyFilename) { + std::string source = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "compute_1" + OpExecutionMode %1 LocalSize 1 1 1 + %2 = OpString "" + OpSource HLSL 660 %2 "void compute(){}" + OpName %1 "compute_1" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %1 = OpFunction %3 None %4 + %5 = OpLabel + OpLine %2 3 1 + OpReturn + OpFunctionEnd + )"; + + auto[success, result] = ExtractSource(source); + ASSERT_TRUE(success); + ASSERT_TRUE(result.size() == 1); + ASSERT_TRUE(result["unnamed-0.hlsl"] == "void compute(){}"); +} + +TEST(ExtractSourceTest, EscapeEscaped) { + std::string source = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "compute" + OpExecutionMode %1 LocalSize 1 1 1 + %2 = OpString "compute.hlsl" + OpSource HLSL 660 %2 "// check \" escape removed" + OpName %1 "compute" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %1 = OpFunction %3 None %4 + %5 = OpLabel + OpLine %2 6 1 + OpReturn + OpFunctionEnd + )"; + + auto[success, result] = ExtractSource(source); + ASSERT_TRUE(success); + ASSERT_TRUE(result.size() == 1); + ASSERT_TRUE(result["compute.hlsl"] == "// check \" escape removed"); +} + +TEST(ExtractSourceTest, OpSourceWithNoSource) { + std::string source = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "compute" + OpExecutionMode %1 LocalSize 1 1 1 + %2 = OpString "compute.hlsl" + OpSource HLSL 660 %2 + OpName %1 "compute" + %3 = OpTypeVoid + %4 = OpTypeFunction %3 + %1 = OpFunction %3 None %4 + %5 = OpLabel + OpLine %2 6 1 + OpReturn + OpFunctionEnd + )"; + + auto[success, result] = ExtractSource(source); + ASSERT_TRUE(success); + ASSERT_TRUE(result.size() == 1); + ASSERT_TRUE(result["compute.hlsl"] == ""); +} diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 4644a52595..a93f640432 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -16,7 +16,6 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES}) add_subdirectory(lesspipe) endif() add_subdirectory(emacs) -#add_subdirectory(objdump) # Add a SPIR-V Tools command line tool. Signature: # add_spvtools_tool( @@ -66,18 +65,21 @@ if (NOT ${SPIRV_SKIP_EXECUTABLES}) LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}) target_include_directories(spirv-cfg PRIVATE ${spirv-tools_SOURCE_DIR} ${SPIRV_HEADER_INCLUDE_DIR}) + set(SPIRV_INSTALL_TARGETS spirv-as spirv-dis spirv-val spirv-opt + spirv-cfg spirv-link spirv-lint) - add_spvtools_tool(TARGET spirv-objdump - SRCS objdump/objdump.cpp - objdump/extract_source.cpp - util/cli_consumer.cpp - ${COMMON_TOOLS_SRCS} - LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}) - target_include_directories(spirv-objdump PRIVATE ${spirv-tools_SOURCE_DIR} - ${SPIRV_HEADER_INCLUDE_DIR}) + if(NOT (${CMAKE_SYSTEM_NAME} STREQUAL "Android")) + add_spvtools_tool(TARGET spirv-objdump + SRCS objdump/objdump.cpp + objdump/extract_source.cpp + util/cli_consumer.cpp + ${COMMON_TOOLS_SRCS} + LIBS ${SPIRV_TOOLS_FULL_VISIBILITY}) + target_include_directories(spirv-objdump PRIVATE ${spirv-tools_SOURCE_DIR} + ${SPIRV_HEADER_INCLUDE_DIR}) + set(SPIRV_INSTALL_TARGETS ${SPIRV_INSTALL_TARGETS} spirv-objdump) + endif() - set(SPIRV_INSTALL_TARGETS spirv-as spirv-dis spirv-val spirv-opt - spirv-cfg spirv-link spirv-lint spirv-objdump) if(NOT (${CMAKE_SYSTEM_NAME} STREQUAL "iOS")) set(SPIRV_INSTALL_TARGETS ${SPIRV_INSTALL_TARGETS} spirv-reduce) endif() diff --git a/tools/objdump/extract_source.cpp b/tools/objdump/extract_source.cpp index 3722cf1080..02959525c6 100644 --- a/tools/objdump/extract_source.cpp +++ b/tools/objdump/extract_source.cpp @@ -14,43 +14,200 @@ #include "extract_source.h" +#include #include #include #include #include "source/opt/log.h" #include "spirv-tools/libspirv.hpp" +#include "spirv/unified1/spirv.hpp" #include "tools/util/cli_consumer.h" namespace { + constexpr auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_6; + +// Extract a string literal from a given range. +// Copies all the characters from `begin` to the first '\0' it encounters, while +// removing escape patterns. +// Not finding a '\0' before reaching `end` fails the extraction. +// +// Returns `true` if the extraction succeeded. +// `output` value is undefined if false is returned. +spv_result_t ExtractStringLiteral(const spv_position_t& loc, const char* begin, + const char* end, std::string* output) { + size_t sourceLength = std::distance(begin, end); + std::string escapedString; + escapedString.resize(sourceLength); + + size_t writeIndex = 0; + size_t readIndex = 0; + for (; readIndex < sourceLength; writeIndex++, readIndex++) { + const char read = begin[readIndex]; + if (read == '\0') { + escapedString.resize(writeIndex); + output->append(escapedString); + return SPV_SUCCESS; + } + + if (read == '\\') { + ++readIndex; + } + escapedString[writeIndex] = begin[readIndex]; + } + + spvtools::Error(spvtools::utils::CLIMessageConsumer, "", loc, + "Missing NULL terminator for literal string."); + return SPV_ERROR_INVALID_BINARY; +} + +spv_result_t extractOpString(const spv_position_t& loc, + const spv_parsed_instruction_t& instruction, + std::string* output) { + assert(output != nullptr); + assert(instruction.opcode == spv::Op::OpString); + if (instruction.num_operands != 2) { + spvtools::Error(spvtools::utils::CLIMessageConsumer, "", loc, + "Missing operands for OpString."); + return SPV_ERROR_INVALID_BINARY; + } + + const auto& operand = instruction.operands[1]; + const char* stringBegin = + reinterpret_cast(instruction.words + operand.offset); + const char* stringEnd = reinterpret_cast( + instruction.words + operand.offset + operand.num_words); + return ExtractStringLiteral(loc, stringBegin, stringEnd, output); +} + +spv_result_t extractOpSourceContinued( + const spv_position_t& loc, const spv_parsed_instruction_t& instruction, + std::string* output) { + assert(output != nullptr); + assert(instruction.opcode == spv::Op::OpSourceContinued); + if (instruction.num_operands != 1) { + spvtools::Error(spvtools::utils::CLIMessageConsumer, "", loc, + "Missing operands for OpSourceContinued."); + return SPV_ERROR_INVALID_BINARY; + } + + const auto& operand = instruction.operands[0]; + const char* stringBegin = + reinterpret_cast(instruction.words + operand.offset); + const char* stringEnd = reinterpret_cast( + instruction.words + operand.offset + operand.num_words); + return ExtractStringLiteral(loc, stringBegin, stringEnd, output); +} + +spv_result_t extractOpSource(const spv_position_t& loc, + const spv_parsed_instruction_t& instruction, + spv::Id* filename, std::string* code) { + assert(filename != nullptr && code != nullptr); + assert(instruction.opcode == spv::Op::OpSource); + // OpCode [ Source Language | Version | File (optional) | Source (optional) ] + if (instruction.num_words < 3) { + spvtools::Error(spvtools::utils::CLIMessageConsumer, "", loc, + "Missing operands for OpSource."); + return SPV_ERROR_INVALID_BINARY; + } + + *filename = 0; + *code = ""; + if (instruction.num_words < 4) { + return SPV_SUCCESS; + } + *filename = instruction.words[3]; + + if (instruction.num_words < 5) { + return SPV_SUCCESS; + } + + const char* stringBegin = + reinterpret_cast(instruction.words + 4); + const char* stringEnd = + reinterpret_cast(instruction.words + instruction.num_words); + return ExtractStringLiteral(loc, stringBegin, stringEnd, code); +} + } // namespace -bool extract_source_from_module( +bool ExtractSourceFromModule( const std::vector& binary, std::unordered_map* output) { auto context = spvtools::SpirvTools(kDefaultEnvironment); context.SetMessageConsumer(spvtools::utils::CLIMessageConsumer); - spvtools::HeaderParser headerParser = - [](const spv_endianness_t endianess, - const spv_parsed_header_t& instruction) { - (void)endianess; - (void)instruction; - return SPV_SUCCESS; - }; + // There is nothing valuable in the header. + spvtools::HeaderParser headerParser = [](const spv_endianness_t, + const spv_parsed_header_t&) { + return SPV_SUCCESS; + }; + + std::unordered_map stringMap; + std::vector> sources; + spv::Op lastOpcode = spv::Op::OpMax; + size_t instructionIndex = 0; spvtools::InstructionParser instructionParser = - [](const spv_parsed_instruction_t& instruction) { - (void)instruction; - return SPV_SUCCESS; + [&stringMap, &sources, &lastOpcode, + &instructionIndex](const spv_parsed_instruction_t& instruction) { + const spv_position_t loc = {0, 0, instructionIndex + 1}; + spv_result_t result = SPV_SUCCESS; + + if (instruction.opcode == spv::Op::OpString) { + std::string content; + result = extractOpString(loc, instruction, &content); + if (result == SPV_SUCCESS) { + stringMap.emplace(instruction.result_id, std::move(content)); + } + } else if (instruction.opcode == spv::Op::OpSource) { + spv::Id filenameId; + std::string code; + result = extractOpSource(loc, instruction, &filenameId, &code); + if (result == SPV_SUCCESS) { + sources.emplace_back(std::make_pair(filenameId, std::move(code))); + } + } else if (instruction.opcode == spv::Op::OpSourceContinued) { + if (lastOpcode != spv::Op::OpSource) { + spvtools::Error(spvtools::utils::CLIMessageConsumer, "", loc, + "OpSourceContinued MUST follow an OpSource."); + return SPV_ERROR_INVALID_BINARY; + } + + assert(sources.size() > 0); + result = extractOpSourceContinued(loc, instruction, + &sources.back().second); + } + + ++instructionIndex; + lastOpcode = static_cast(instruction.opcode); + return result; }; if (!context.Parse(binary, headerParser, instructionParser)) { return false; } - // FIXME - (void)output; + std::string defaultName = "unnamed-"; + size_t unnamedCount = 0; + for (auto & [ id, code ] : sources) { + std::string filename; + const auto it = stringMap.find(id); + if (it == stringMap.cend() || it->second.empty()) { + filename = "unnamed-" + std::to_string(unnamedCount) + ".hlsl"; + ++unnamedCount; + } else { + filename = it->second; + } + + if (output->count(filename) != 0) { + spvtools::Error(spvtools::utils::CLIMessageConsumer, "", {}, + "Source file name conflict."); + return false; + } + output->insert({filename, code}); + } + return true; } diff --git a/tools/objdump/extract_source.h b/tools/objdump/extract_source.h index a163be200b..3e5ecfa958 100644 --- a/tools/objdump/extract_source.h +++ b/tools/objdump/extract_source.h @@ -32,7 +32,7 @@ // // Returns `true` if the extraction succeeded, `false` otherwise. // `output` value is undefined if `false` is returned. -bool extract_source_from_module( +bool ExtractSourceFromModule( const std::vector& binary, std::unordered_map* output); diff --git a/tools/objdump/objdump.cpp b/tools/objdump/objdump.cpp index 520ff19f20..79181b0acd 100644 --- a/tools/objdump/objdump.cpp +++ b/tools/objdump/objdump.cpp @@ -12,6 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include +#include + #include "extract_source.h" #include "source/opt/log.h" #include "tools/io.h" @@ -42,6 +45,57 @@ Source dump options: File written to stdout if '-' is given. Default is `-`. )"; +// Removes trailing '/' from `input`. +// A behavior difference has been observed between libc++ implementations. +// Fixing path to prevent this edge case to be reached. +// (https://github.com/llvm/llvm-project/issues/60634) +std::string fixPathForLLVM(std::string input) { + while (!input.empty() && input.back() == '/') input.resize(input.size() - 1); + return input; +} + +// Write each HLSL file described in `sources` in a file in `outdirPath`. +// Doesn't ovewrite existing files, unless `overwrite` is set to true. The +// created HLSL file's filename is the path's filename obtained from `sources`. +// Returns true if all files could be written. False otherwise. +bool OutputSourceFiles( + const std::unordered_map& sources, + const std::string& outdirPath, bool overwrite) { + std::filesystem::path outdir(fixPathForLLVM(outdirPath)); + if (!std::filesystem::is_directory(outdir)) { + if (!std::filesystem::create_directories(outdir)) { + std::cerr << "error: could not create output directory " << outdir + << std::endl; + return false; + } + } + + for (const auto & [ filepath, code ] : sources) { + if (code.empty()) { + std::cout << "Ignoring source for " << filepath + << ": no code source in debug infos." << std::endl; + continue; + } + + std::filesystem::path old_path(filepath); + std::filesystem::path new_path = outdir / old_path.filename(); + + if (!overwrite && std::filesystem::exists(new_path)) { + std::cerr << "file " << filepath + << " already exists, aborting (use --overwrite to allow it)." + << std::endl; + return false; + } + + std::cout << "Exporting " << new_path << std::endl; + if (!WriteFile(new_path.string().c_str(), "w", code.c_str(), + code.size())) { + return false; + } + } + return true; +} + } // namespace // clang-format off @@ -71,14 +125,11 @@ int main(int, const char** argv) { } if (flags::positional_arguments.size() != 1) { - spvtools::Error(spvtools::utils::CLIMessageConsumer, nullptr, {}, - "expected exactly one input file."); + std::cerr << "Expected exactly one input file." << std::endl; return 1; } - if (flags::source.value() || flags::entrypoint.value() || - flags::compiler_cmd.value()) { - spvtools::Error(spvtools::utils::CLIMessageConsumer, nullptr, {}, - "not implemented yet."); + if (flags::entrypoint.value() || flags::compiler_cmd.value()) { + std::cerr << "Unimplemented flags." << std::endl; return 1; } @@ -88,8 +139,34 @@ int main(int, const char** argv) { } if (flags::source.value()) { - std::unordered_map output; - return extract_source_from_module(binary, &output) ? 0 : 1; + std::unordered_map sourceCode; + if (!ExtractSourceFromModule(binary, &sourceCode)) { + return 1; + } + + if (flags::list.value()) { + for (const auto & [ filename, source ] : sourceCode) { + printf("%s\n", filename.c_str()); + } + return 0; + } + + const bool outputToConsole = flags::outdir.value() == "-"; + + if (outputToConsole) { + for (const auto & [ filename, source ] : sourceCode) { + std::cout << filename << ":" << std::endl + << source << std::endl + << std::endl; + } + return 0; + } + + const std::filesystem::path outdirPath(flags::outdir.value()); + if (!OutputSourceFiles(sourceCode, outdirPath.string(), + flags::force.value())) { + return 1; + } } // FIXME: implement logic. From 9fbe1738ba674343d73b77d38a9e0b64964e8de2 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Thu, 23 Mar 2023 13:00:42 -0400 Subject: [PATCH 102/523] Update SPIRV-Headers deps (#5170) * Update test expectations to account for simplified enables * Don't clone spirv-headers twice for the smoketest --- DEPS | 2 +- kokoro/scripts/linux/build-docker.sh | 6 ++++-- test/operand_capabilities_test.cpp | 10 +++++----- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/DEPS b/DEPS index e07f0ef3cf..423c3db8aa 100644 --- a/DEPS +++ b/DEPS @@ -11,7 +11,7 @@ vars = { 'protobuf_revision': 'v3.13.0.1', 're2_revision': '11073deb73b3d01018308863c0bcdfd0d51d3e70', - 'spirv_headers_revision': '1feaf4414eb2b353764d01d88f8aa4bcc67b60db', + 'spirv_headers_revision': 'a41cf67dfa52d33c049dc1b606e2db5cf72dafeb', } deps = { diff --git a/kokoro/scripts/linux/build-docker.sh b/kokoro/scripts/linux/build-docker.sh index 6bd71ce864..f2a06e07c9 100755 --- a/kokoro/scripts/linux/build-docker.sh +++ b/kokoro/scripts/linux/build-docker.sh @@ -43,8 +43,10 @@ function clean_dir() { mkdir "$dir" } -# Get source for dependencies, as specified in the DEPS file -/usr/bin/python3 utils/git-sync-deps --treeless +if [ $TOOL != "cmake-smoketest" ]; then + # Get source for dependencies, as specified in the DEPS file + /usr/bin/python3 utils/git-sync-deps --treeless +fi if [ $TOOL = "cmake" ]; then using cmake-3.17.2 diff --git a/test/operand_capabilities_test.cpp b/test/operand_capabilities_test.cpp index 10ed82a180..01b98a63ef 100644 --- a/test/operand_capabilities_test.cpp +++ b/test/operand_capabilities_test.cpp @@ -223,12 +223,12 @@ INSTANTIATE_TEST_SUITE_P( Dim, EnumCapabilityTest, Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), ValuesIn(std::vector{ - CASE2(DIMENSIONALITY, Dim::Dim1D, Sampled1D, Image1D), - CASE3(DIMENSIONALITY, Dim::Dim2D, Kernel, Shader, ImageMSArray), + CASE1(DIMENSIONALITY, Dim::Dim1D, Sampled1D), + CASE0(DIMENSIONALITY, Dim::Dim2D), CASE0(DIMENSIONALITY, Dim::Dim3D), - CASE2(DIMENSIONALITY, Dim::Cube, Shader, ImageCubeArray), - CASE2(DIMENSIONALITY, Dim::Rect, SampledRect, ImageRect), - CASE2(DIMENSIONALITY, Dim::Buffer, SampledBuffer, ImageBuffer), + CASE1(DIMENSIONALITY, Dim::Cube, Shader), + CASE1(DIMENSIONALITY, Dim::Rect, SampledRect), + CASE1(DIMENSIONALITY, Dim::Buffer, SampledBuffer), CASE1(DIMENSIONALITY, Dim::SubpassData, InputAttachment), }))); From 32a4d840bb92f72972b2616472fb422d8750ce0b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 24 Mar 2023 10:03:09 -0400 Subject: [PATCH 103/523] roll deps (#5172) * Roll external/googletest/ 974e18ee6..6f01e3dc1 (2 commits) https://github.com/google/googletest/compare/974e18ee6f14...6f01e3dc125e $ git log 974e18ee6..6f01e3dc1 --date=short --no-merges --format='%ad %ae %s' 2023-03-23 absl-team Internal Code Change 2023-03-22 jacobsa gtest.cc: add a newline after a failure when there is no OS stack trace. Created with: roll-dep external/googletest * Roll external/spirv-headers/ a41cf67df..90547c54e (2 commits) https://github.com/KhronosGroup/SPIRV-Headers/compare/a41cf67dfa52...90547c54e24e $ git log a41cf67df..90547c54e --date=short --no-merges --format='%ad %ae %s' 2023-03-23 juan cmake: Overally cleanup/testing update 2023-03-23 dneto Revert "Merge pull request #326 from juan-lunarg/juaramos/cmake" 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 423c3db8aa..8091e4c612 100644 --- a/DEPS +++ b/DEPS @@ -5,13 +5,13 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': '974e18ee6f146a2418f9cea83170c640e7d622d6', + 'googletest_revision': '6f01e3dc125e82f2d3d87839a8be52f610c732ea', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', 're2_revision': '11073deb73b3d01018308863c0bcdfd0d51d3e70', - 'spirv_headers_revision': 'a41cf67dfa52d33c049dc1b606e2db5cf72dafeb', + 'spirv_headers_revision': '90547c54e24e01aae41a68124e7a304d0ec11dd0', } deps = { From b4e0850ef75cbf4f3e3a2340f4ee4c654a81d604 Mon Sep 17 00:00:00 2001 From: Jeremy Hayes Date: Fri, 24 Mar 2023 10:46:52 -0600 Subject: [PATCH 104/523] Ignore NonSemanticInstructions (#5171) Fix #5163. Ignore NonSemanticInstructions in DoDeadOutputStoresElimination and ComputeLiveness. --- source/opt/eliminate_dead_output_stores_pass.cpp | 2 +- source/opt/liveness.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/opt/eliminate_dead_output_stores_pass.cpp b/source/opt/eliminate_dead_output_stores_pass.cpp index f2f64f812a..99711a16e8 100644 --- a/source/opt/eliminate_dead_output_stores_pass.cpp +++ b/source/opt/eliminate_dead_output_stores_pass.cpp @@ -219,7 +219,7 @@ Pass::Status EliminateDeadOutputStoresPass::DoDeadOutputStoreElimination() { var_id, [this, &var, is_builtin](Instruction* user) { auto op = user->opcode(); if (op == spv::Op::OpEntryPoint || op == spv::Op::OpName || - op == spv::Op::OpDecorate) + op == spv::Op::OpDecorate || user->IsNonSemanticInstruction()) return; if (is_builtin) KillAllDeadStoresOfBuiltinRef(user, &var); diff --git a/source/opt/liveness.cpp b/source/opt/liveness.cpp index fdf3f4e110..336f3ae526 100644 --- a/source/opt/liveness.cpp +++ b/source/opt/liveness.cpp @@ -309,7 +309,7 @@ void LivenessManager::ComputeLiveness() { def_use_mgr->ForEachUser(var_id, [this, &var](Instruction* user) { auto op = user->opcode(); if (op == spv::Op::OpEntryPoint || op == spv::Op::OpName || - op == spv::Op::OpDecorate) { + op == spv::Op::OpDecorate || user->IsNonSemanticInstruction()) { return; } MarkRefLive(user, &var); From f9f31fa5a903fc4a0c5d5272d9a7781d3ffef319 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 25 Mar 2023 08:06:26 -0400 Subject: [PATCH 105/523] Roll external/googletest/ 6f01e3dc1..e9fb5c7ba (2 commits) (#5175) https://github.com/google/googletest/compare/6f01e3dc125e...e9fb5c7bacc4 $ git log 6f01e3dc1..e9fb5c7ba --date=short --no-merges --format='%ad %ae %s' 2023-03-24 absl-team Replace `const char*` with `absl::string_view` as the latter is preferred. 2023-03-24 absl-team Internal Code Change 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 8091e4c612..e94772101e 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': '6f01e3dc125e82f2d3d87839a8be52f610c732ea', + 'googletest_revision': 'e9fb5c7bacc4a25b030569c92ff9f6925288f1c3', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From d24a39a7f00d218fa8b5aed1393a1756281725bd Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Mon, 27 Mar 2023 11:04:40 -0400 Subject: [PATCH 106/523] Do not remove control barrier after spv1.3 (#5174) The control barrier instruction was allowed in a limiteted set of shader types. Part of the HLSL legalization, we use to remove the instructions when it was is a shader in which it was not allowed. As of spv1.3 that restriction is not long there. This change modifies replaced invalid opc to no longer remove it. Fixes #4999. --- source/opt/ir_context.h | 11 ++++ source/opt/replace_invalid_opc.cpp | 3 +- test/opt/ir_context_test.cpp | 85 +++++++++++++++++++++++++++ test/opt/replace_invalid_opc_test.cpp | 32 ++++++++++ 4 files changed, 130 insertions(+), 1 deletion(-) diff --git a/source/opt/ir_context.h b/source/opt/ir_context.h index 35075de171..8419ee7e95 100644 --- a/source/opt/ir_context.h +++ b/source/opt/ir_context.h @@ -645,6 +645,17 @@ class IRContext { // all have the same stage. spv::ExecutionModel GetStage(); + // Returns true of the current target environment is at least that of the + // given environment. + bool IsTargetEnvAtLeast(spv_target_env env) { + // A bit of a hack. We assume that the target environments are appended to + // the enum, so that there is an appropriate order. + return syntax_context_->target_env >= env; + } + + // Return the target environment for the current context. + spv_target_env GetTargetEnv() const { return syntax_context_->target_env; } + private: // Builds the def-use manager from scratch, even if it was already valid. void BuildDefUseManager() { diff --git a/source/opt/replace_invalid_opc.cpp b/source/opt/replace_invalid_opc.cpp index 214097398d..1b97c0e84f 100644 --- a/source/opt/replace_invalid_opc.cpp +++ b/source/opt/replace_invalid_opc.cpp @@ -86,7 +86,8 @@ bool ReplaceInvalidOpcodePass::RewriteFunction(Function* function, } if (model != spv::ExecutionModel::TessellationControl && - model != spv::ExecutionModel::GLCompute) { + model != spv::ExecutionModel::GLCompute && + !context()->IsTargetEnvAtLeast(SPV_ENV_UNIVERSAL_1_3)) { if (inst->opcode() == spv::Op::OpControlBarrier) { assert(model != spv::ExecutionModel::Kernel && "Expecting to be working on a shader module."); diff --git a/test/opt/ir_context_test.cpp b/test/opt/ir_context_test.cpp index 86a3f4596e..28cd0d5e92 100644 --- a/test/opt/ir_context_test.cpp +++ b/test/opt/ir_context_test.cpp @@ -1149,6 +1149,91 @@ OpFunctionEnd)"; 20); } +struct TargetEnvCompareTestData { + spv_target_env later_env, earlier_env; +}; + +using TargetEnvCompareTest = ::testing::TestWithParam; + +TEST_P(TargetEnvCompareTest, Case) { + // If new environments are added, then we must update the list of tests. + ASSERT_EQ(SPV_ENV_VULKAN_1_3 + 1, SPV_ENV_MAX); + + const auto& tc = GetParam(); + + std::unique_ptr module(new Module()); + IRContext localContext(tc.later_env, std::move(module), + spvtools::MessageConsumer()); + EXPECT_TRUE(localContext.IsTargetEnvAtLeast(tc.earlier_env)); + + if (tc.earlier_env != tc.later_env) { + std::unique_ptr module(new Module()); + IRContext localContext(tc.earlier_env, std::move(module), + spvtools::MessageConsumer()); + EXPECT_FALSE(localContext.IsTargetEnvAtLeast(tc.later_env)); + } +} + +INSTANTIATE_TEST_SUITE_P( + TestCase, TargetEnvCompareTest, + ::testing::Values( + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_0}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_0}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_0}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_0}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_0}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_5, SPV_ENV_UNIVERSAL_1_0}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_6, SPV_ENV_UNIVERSAL_1_0}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_1}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_1}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_1}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_1}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_5, SPV_ENV_UNIVERSAL_1_1}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_6, SPV_ENV_UNIVERSAL_1_1}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_2}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_2}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_2}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_5, SPV_ENV_UNIVERSAL_1_2}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_6, SPV_ENV_UNIVERSAL_1_2}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_3}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_3}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_5, SPV_ENV_UNIVERSAL_1_3}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_6, SPV_ENV_UNIVERSAL_1_3}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_4}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_5, SPV_ENV_UNIVERSAL_1_4}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_6, SPV_ENV_UNIVERSAL_1_4}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_5, SPV_ENV_UNIVERSAL_1_5}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_6, SPV_ENV_UNIVERSAL_1_5}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_6, SPV_ENV_UNIVERSAL_1_6}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_0, SPV_ENV_UNIVERSAL_1_0}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_1, SPV_ENV_VULKAN_1_0}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_2, SPV_ENV_VULKAN_1_0}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_4, SPV_ENV_VULKAN_1_0}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_0}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_6, SPV_ENV_VULKAN_1_0}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_1, SPV_ENV_UNIVERSAL_1_0}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_1, SPV_ENV_UNIVERSAL_1_1}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_1, SPV_ENV_UNIVERSAL_1_2}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_1, SPV_ENV_UNIVERSAL_1_3}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_4, SPV_ENV_VULKAN_1_1}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_1}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_6, SPV_ENV_VULKAN_1_1}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_2, SPV_ENV_UNIVERSAL_1_0}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_2, SPV_ENV_UNIVERSAL_1_1}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_2, SPV_ENV_UNIVERSAL_1_2}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_2, SPV_ENV_UNIVERSAL_1_3}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_2, SPV_ENV_UNIVERSAL_1_4}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_2, SPV_ENV_UNIVERSAL_1_5}, + TargetEnvCompareTestData{SPV_ENV_UNIVERSAL_1_6, SPV_ENV_VULKAN_1_2}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_3, SPV_ENV_UNIVERSAL_1_0}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_3, SPV_ENV_UNIVERSAL_1_1}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_3, SPV_ENV_UNIVERSAL_1_2}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_3, SPV_ENV_UNIVERSAL_1_3}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_3, SPV_ENV_UNIVERSAL_1_4}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_3, SPV_ENV_UNIVERSAL_1_5}, + TargetEnvCompareTestData{SPV_ENV_VULKAN_1_3, SPV_ENV_UNIVERSAL_1_6})); + } // namespace } // namespace opt } // namespace spvtools diff --git a/test/opt/replace_invalid_opc_test.cpp b/test/opt/replace_invalid_opc_test.cpp index 1be904b4e4..c0f5df29d2 100644 --- a/test/opt/replace_invalid_opc_test.cpp +++ b/test/opt/replace_invalid_opc_test.cpp @@ -404,6 +404,7 @@ TEST_F(ReplaceInvalidOpcodeTest, BarrierDontReplace) { OpReturn OpFunctionEnd)"; + SetTargetEnv(SPV_ENV_UNIVERSAL_1_2); auto result = SinglePassRunAndDisassemble( text, /* skip_nop = */ true, /* do_validation = */ false); EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); @@ -432,9 +433,40 @@ TEST_F(ReplaceInvalidOpcodeTest, BarrierReplace) { OpReturn OpFunctionEnd)"; + SetTargetEnv(SPV_ENV_UNIVERSAL_1_2); SinglePassRunAndMatch(text, false); } +// Since version 1.3 OpControlBarriers are allowed is more shaders. +// https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpControlBarrier +TEST_F(ReplaceInvalidOpcodeTest, BarrierDontReplaceV13) { + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" + OpSourceExtension "GL_GOOGLE_include_directive" + OpName %main "main" + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %uint_2 = OpConstant %uint 2 +%uint_264 = OpConstant %uint 264 + %main = OpFunction %void None %3 + %5 = OpLabel + OpControlBarrier %uint_2 %uint_2 %uint_264 + OpReturn + OpFunctionEnd)"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_3); + auto result = SinglePassRunAndDisassemble( + text, /* skip_nop = */ true, /* do_validation = */ false); + EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result)); +} + TEST_F(ReplaceInvalidOpcodeTest, MessageTest) { const std::string text = R"( OpCapability Shader From fa69b09cff0e5918e0095f9483e68198fe09007c Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Wed, 29 Mar 2023 01:40:30 +0900 Subject: [PATCH 107/523] spirv-opt: Remove unused includes and code (#5177) --- source/opt/aggressive_dead_code_elim_pass.cpp | 2 -- source/opt/basic_block.cpp | 2 -- source/opt/block_merge_pass.cpp | 3 --- source/opt/ccp_pass.cpp | 1 - source/opt/cfg_cleanup_pass.cpp | 4 ---- source/opt/code_sink.cpp | 2 -- source/opt/constants.cpp | 1 - source/opt/control_dependence.cpp | 2 -- source/opt/convert_to_sampled_image_pass.cpp | 1 - source/opt/dataflow.cpp | 1 - source/opt/dead_branch_elim_pass.cpp | 1 - source/opt/eliminate_dead_constant_pass.cpp | 1 - source/opt/eliminate_dead_io_components_pass.cpp | 2 -- source/opt/eliminate_dead_output_stores_pass.h | 6 ------ source/opt/feature_manager.cpp | 2 -- source/opt/fold.cpp | 1 - source/opt/fold_spec_constant_op_and_composite_pass.cpp | 3 --- source/opt/folding_rules.cpp | 1 - source/opt/function.cpp | 2 -- source/opt/graphics_robust_access_pass.cpp | 6 ------ source/opt/interface_var_sroa.h | 4 ---- source/opt/interp_fixup_pass.cpp | 1 - source/opt/ir_context.cpp | 1 - source/opt/licm_pass.cpp | 1 - source/opt/local_access_chain_convert_pass.cpp | 1 - source/opt/local_single_block_elim_pass.cpp | 1 - source/opt/local_single_store_elim_pass.cpp | 2 -- source/opt/loop_dependence.cpp | 2 -- source/opt/loop_dependence_helpers.cpp | 4 +--- source/opt/loop_descriptor.cpp | 3 --- source/opt/loop_fusion_pass.cpp | 1 - source/opt/loop_peeling.cpp | 5 ++--- source/opt/loop_unroller.cpp | 1 - source/opt/loop_unswitch_pass.cpp | 2 -- source/opt/mem_pass.cpp | 2 -- source/opt/remove_duplicates_pass.cpp | 3 --- source/opt/scalar_analysis.cpp | 1 - source/opt/scalar_analysis_simplification.cpp | 5 ++--- source/opt/scalar_replacement_pass.cpp | 2 -- source/opt/set_spec_constant_default_value_pass.cpp | 2 -- source/opt/simplification_pass.cpp | 1 - source/opt/spread_volatile_semantics.cpp | 1 - source/opt/ssa_rewrite_pass.cpp | 1 - source/opt/strength_reduction_pass.cpp | 4 ---- source/opt/strip_nonsemantic_info_pass.cpp | 1 - source/opt/types.cpp | 1 - source/opt/unify_const_pass.cpp | 1 - test/opt/analyze_live_input_test.cpp | 1 - test/opt/ccp_test.cpp | 1 - test/opt/code_sink_test.cpp | 1 - test/opt/combine_access_chains_test.cpp | 2 -- test/opt/compact_ids_test.cpp | 1 - test/opt/constant_manager_test.cpp | 2 -- test/opt/constants_test.cpp | 1 - test/opt/copy_prop_array_test.cpp | 1 - test/opt/dataflow.cpp | 1 - test/opt/debug_info_manager_test.cpp | 3 --- test/opt/decoration_manager_test.cpp | 1 - test/opt/def_use_test.cpp | 1 - test/opt/desc_sroa_test.cpp | 2 -- test/opt/dominator_tree/common_dominators.cpp | 2 -- test/opt/dominator_tree/generated.cpp | 1 - test/opt/dominator_tree/nested_ifs.cpp | 2 -- test/opt/dominator_tree/nested_ifs_post.cpp | 1 - test/opt/dominator_tree/nested_loops.cpp | 1 - .../opt/dominator_tree/nested_loops_with_unreachables.cpp | 1 - test/opt/dominator_tree/post.cpp | 1 - test/opt/dominator_tree/simple.cpp | 1 - test/opt/dominator_tree/switch_case_fallthrough.cpp | 1 - test/opt/dominator_tree/unreachable_for.cpp | 1 - test/opt/dominator_tree/unreachable_for_post.cpp | 1 - test/opt/eliminate_dead_const_test.cpp | 3 --- test/opt/eliminate_dead_io_components_test.cpp | 1 - test/opt/eliminate_dead_member_test.cpp | 1 - test/opt/eliminate_dead_output_stores_test.cpp | 1 - test/opt/feature_manager_test.cpp | 2 -- test/opt/fix_func_call_arguments_test.cpp | 1 - test/opt/fix_storage_class_test.cpp | 2 -- test/opt/flatten_decoration_test.cpp | 1 - test/opt/fold_test.cpp | 1 - test/opt/freeze_spec_const_test.cpp | 1 - test/opt/function_test.cpp | 2 -- test/opt/graphics_robust_access_test.cpp | 2 -- test/opt/if_conversion_test.cpp | 2 -- test/opt/inst_bindless_check_test.cpp | 1 - test/opt/inst_buff_addr_check_test.cpp | 1 - test/opt/inst_debug_printf_test.cpp | 1 - test/opt/instruction_test.cpp | 4 ++-- test/opt/interface_var_sroa_test.cpp | 2 -- test/opt/ir_builder.cpp | 6 ++---- test/opt/ir_context_test.cpp | 1 - test/opt/ir_loader_test.cpp | 1 - test/opt/local_redundancy_elimination_test.cpp | 2 -- test/opt/loop_optimizations/dependence_analysis.cpp | 6 ------ .../loop_optimizations/dependence_analysis_helpers.cpp | 6 ------ test/opt/loop_optimizations/fusion_compatibility.cpp | 3 --- test/opt/loop_optimizations/fusion_illegal.cpp | 3 --- test/opt/loop_optimizations/fusion_legal.cpp | 3 --- test/opt/loop_optimizations/lcssa.cpp | 2 -- test/opt/loop_optimizations/loop_descriptions.cpp | 1 - test/opt/loop_optimizations/loop_fission.cpp | 6 ++---- test/opt/loop_optimizations/peeling.cpp | 1 - test/opt/loop_optimizations/peeling_pass.cpp | 1 - test/opt/loop_optimizations/unroll_assumptions.cpp | 1 - test/opt/loop_optimizations/unroll_simple.cpp | 1 - test/opt/module_test.cpp | 6 ++---- test/opt/pass_merge_return_test.cpp | 2 -- test/opt/pass_remove_duplicates_test.cpp | 2 -- test/opt/private_to_local_test.cpp | 1 - test/opt/propagator_test.cpp | 5 ++--- test/opt/redundancy_elimination_test.cpp | 2 -- test/opt/register_liveness.cpp | 1 - test/opt/relax_float_ops_test.cpp | 1 - test/opt/remove_unused_interface_variables_test.cpp | 1 - .../replace_desc_array_access_using_var_index_test.cpp | 2 -- test/opt/replace_invalid_opc_test.cpp | 2 -- test/opt/scalar_analysis.cpp | 8 ++------ test/opt/scalar_replacement_test.cpp | 4 +--- test/opt/simplification_test.cpp | 1 - test/opt/spread_volatile_semantics_test.cpp | 1 - test/opt/strength_reduction_test.cpp | 5 ----- test/opt/struct_cfg_analysis_test.cpp | 1 - test/opt/type_manager_test.cpp | 4 ++-- test/opt/upgrade_memory_model_test.cpp | 1 - test/opt/value_table_test.cpp | 1 - test/opt/workaround1209_test.cpp | 6 ------ test/opt/wrap_opkill_test.cpp | 1 - 127 files changed, 20 insertions(+), 240 deletions(-) diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp index 53d13f18bf..51a65245fb 100644 --- a/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/source/opt/aggressive_dead_code_elim_pass.cpp @@ -21,10 +21,8 @@ #include #include "source/cfa.h" -#include "source/latest_version_glsl_std_450_header.h" #include "source/opt/eliminate_dead_functions_util.h" #include "source/opt/ir_builder.h" -#include "source/opt/iterator.h" #include "source/opt/reflect.h" #include "source/spirv_constant.h" #include "source/util/string_utils.h" diff --git a/source/opt/basic_block.cpp b/source/opt/basic_block.cpp index d12178ebe3..a9fc8e2f7b 100644 --- a/source/opt/basic_block.cpp +++ b/source/opt/basic_block.cpp @@ -16,9 +16,7 @@ #include -#include "source/opt/function.h" #include "source/opt/ir_context.h" -#include "source/opt/module.h" #include "source/opt/reflect.h" #include "source/util/make_unique.h" diff --git a/source/opt/block_merge_pass.cpp b/source/opt/block_merge_pass.cpp index ef7f31fe0b..d6c33e52b5 100644 --- a/source/opt/block_merge_pass.cpp +++ b/source/opt/block_merge_pass.cpp @@ -16,11 +16,8 @@ #include "source/opt/block_merge_pass.h" -#include - #include "source/opt/block_merge_util.h" #include "source/opt/ir_context.h" -#include "source/opt/iterator.h" namespace spvtools { namespace opt { diff --git a/source/opt/ccp_pass.cpp b/source/opt/ccp_pass.cpp index 63627a2f73..46bfc907de 100644 --- a/source/opt/ccp_pass.cpp +++ b/source/opt/ccp_pass.cpp @@ -24,7 +24,6 @@ #include "source/opt/fold.h" #include "source/opt/function.h" -#include "source/opt/module.h" #include "source/opt/propagator.h" namespace spvtools { diff --git a/source/opt/cfg_cleanup_pass.cpp b/source/opt/cfg_cleanup_pass.cpp index 6d48637a45..26fed89fb1 100644 --- a/source/opt/cfg_cleanup_pass.cpp +++ b/source/opt/cfg_cleanup_pass.cpp @@ -16,13 +16,9 @@ // constructs (e.g., unreachable basic blocks, empty control flow structures, // etc) -#include -#include - #include "source/opt/cfg_cleanup_pass.h" #include "source/opt/function.h" -#include "source/opt/module.h" namespace spvtools { namespace opt { diff --git a/source/opt/code_sink.cpp b/source/opt/code_sink.cpp index 35a8df23b9..90231791e7 100644 --- a/source/opt/code_sink.cpp +++ b/source/opt/code_sink.cpp @@ -14,11 +14,9 @@ #include "code_sink.h" -#include #include #include "source/opt/instruction.h" -#include "source/opt/ir_builder.h" #include "source/opt/ir_context.h" #include "source/util/bit_vector.h" diff --git a/source/opt/constants.cpp b/source/opt/constants.cpp index d70e27bb29..9b4c89a655 100644 --- a/source/opt/constants.cpp +++ b/source/opt/constants.cpp @@ -14,7 +14,6 @@ #include "source/opt/constants.h" -#include #include #include "source/opt/ir_context.h" diff --git a/source/opt/control_dependence.cpp b/source/opt/control_dependence.cpp index a153cabfc6..3d48139636 100644 --- a/source/opt/control_dependence.cpp +++ b/source/opt/control_dependence.cpp @@ -16,8 +16,6 @@ #include #include -#include -#include #include "source/opt/basic_block.h" #include "source/opt/cfg.h" diff --git a/source/opt/convert_to_sampled_image_pass.cpp b/source/opt/convert_to_sampled_image_pass.cpp index 2effc3e4c7..c82db41cec 100644 --- a/source/opt/convert_to_sampled_image_pass.cpp +++ b/source/opt/convert_to_sampled_image_pass.cpp @@ -16,7 +16,6 @@ #include #include -#include #include "source/opt/ir_builder.h" #include "source/util/make_unique.h" diff --git a/source/opt/dataflow.cpp b/source/opt/dataflow.cpp index 8d74e41373..63737f1984 100644 --- a/source/opt/dataflow.cpp +++ b/source/opt/dataflow.cpp @@ -14,7 +14,6 @@ #include "source/opt/dataflow.h" -#include #include namespace spvtools { diff --git a/source/opt/dead_branch_elim_pass.cpp b/source/opt/dead_branch_elim_pass.cpp index 319b8d161c..1526b9e05e 100644 --- a/source/opt/dead_branch_elim_pass.cpp +++ b/source/opt/dead_branch_elim_pass.cpp @@ -23,7 +23,6 @@ #include "source/cfa.h" #include "source/opt/ir_context.h" -#include "source/opt/iterator.h" #include "source/opt/struct_cfg_analysis.h" #include "source/util/make_unique.h" diff --git a/source/opt/eliminate_dead_constant_pass.cpp b/source/opt/eliminate_dead_constant_pass.cpp index d021515600..500fd8af9a 100644 --- a/source/opt/eliminate_dead_constant_pass.cpp +++ b/source/opt/eliminate_dead_constant_pass.cpp @@ -20,7 +20,6 @@ #include #include "source/opt/def_use_manager.h" -#include "source/opt/ir_context.h" #include "source/opt/log.h" #include "source/opt/reflect.h" diff --git a/source/opt/eliminate_dead_io_components_pass.cpp b/source/opt/eliminate_dead_io_components_pass.cpp index 916fc27a3c..5553a3362f 100644 --- a/source/opt/eliminate_dead_io_components_pass.cpp +++ b/source/opt/eliminate_dead_io_components_pass.cpp @@ -15,11 +15,9 @@ #include "source/opt/eliminate_dead_io_components_pass.h" -#include #include #include "source/opt/instruction.h" -#include "source/opt/ir_builder.h" #include "source/opt/ir_context.h" #include "source/util/bit_vector.h" diff --git a/source/opt/eliminate_dead_output_stores_pass.h b/source/opt/eliminate_dead_output_stores_pass.h index 13785f3493..676d4f4f00 100644 --- a/source/opt/eliminate_dead_output_stores_pass.h +++ b/source/opt/eliminate_dead_output_stores_pass.h @@ -50,15 +50,9 @@ class EliminateDeadOutputStoresPass : public Pass { // Initialize elimination void InitializeElimination(); - // Do dead output store analysis - Status DoDeadOutputStoreAnalysis(); - // Do dead output store analysis Status DoDeadOutputStoreElimination(); - // Mark all locations live - void MarkAllLocsLive(); - // Kill all stores resulting from |ref|. void KillAllStoresOfRef(Instruction* ref); diff --git a/source/opt/feature_manager.cpp b/source/opt/feature_manager.cpp index 2a1c00664a..07e053b8eb 100644 --- a/source/opt/feature_manager.cpp +++ b/source/opt/feature_manager.cpp @@ -14,8 +14,6 @@ #include "source/opt/feature_manager.h" -#include -#include #include #include "source/enum_string_mapping.h" diff --git a/source/opt/fold.cpp b/source/opt/fold.cpp index 3c234c4e35..453756f8c3 100644 --- a/source/opt/fold.cpp +++ b/source/opt/fold.cpp @@ -21,7 +21,6 @@ #include "source/opt/const_folding_rules.h" #include "source/opt/def_use_manager.h" #include "source/opt/folding_rules.h" -#include "source/opt/ir_builder.h" #include "source/opt/ir_context.h" namespace spvtools { 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 132be0c4b1..f6d61554a4 100644 --- a/source/opt/fold_spec_constant_op_and_composite_pass.cpp +++ b/source/opt/fold_spec_constant_op_and_composite_pass.cpp @@ -15,12 +15,9 @@ #include "source/opt/fold_spec_constant_op_and_composite_pass.h" #include -#include #include #include "source/opt/constants.h" -#include "source/opt/fold.h" -#include "source/opt/ir_context.h" #include "source/util/make_unique.h" namespace spvtools { diff --git a/source/opt/folding_rules.cpp b/source/opt/folding_rules.cpp index a2260ccb22..7730ac1d27 100644 --- a/source/opt/folding_rules.cpp +++ b/source/opt/folding_rules.cpp @@ -14,7 +14,6 @@ #include "source/opt/folding_rules.h" -#include #include #include #include diff --git a/source/opt/function.cpp b/source/opt/function.cpp index 6c7c949fd3..2ee88eca8e 100644 --- a/source/opt/function.cpp +++ b/source/opt/function.cpp @@ -15,9 +15,7 @@ #include "source/opt/function.h" #include -#include -#include "function.h" #include "ir_context.h" #include "source/util/bit_vector.h" diff --git a/source/opt/graphics_robust_access_pass.cpp b/source/opt/graphics_robust_access_pass.cpp index da2764fc83..8fff8a032b 100644 --- a/source/opt/graphics_robust_access_pass.cpp +++ b/source/opt/graphics_robust_access_pass.cpp @@ -141,18 +141,12 @@ #include "graphics_robust_access_pass.h" -#include -#include #include #include -#include #include -#include "constants.h" -#include "def_use_manager.h" #include "function.h" #include "ir_context.h" -#include "module.h" #include "pass.h" #include "source/diagnostic.h" #include "source/util/make_unique.h" diff --git a/source/opt/interface_var_sroa.h b/source/opt/interface_var_sroa.h index df7511bf3a..45ed3717ad 100644 --- a/source/opt/interface_var_sroa.h +++ b/source/opt/interface_var_sroa.h @@ -90,10 +90,6 @@ class InterfaceVariableScalarReplacement : public Pass { // |component|. Returns true whether the component exists or not. bool GetVariableComponent(Instruction* var, uint32_t* component); - // Returns the interface variable instruction whose result id is - // |interface_var_id|. - Instruction* GetInterfaceVariable(uint32_t interface_var_id); - // Returns the type of |var| as an instruction. Instruction* GetTypeOfVariable(Instruction* var); diff --git a/source/opt/interp_fixup_pass.cpp b/source/opt/interp_fixup_pass.cpp index bb6f6108cf..2ec2147d60 100644 --- a/source/opt/interp_fixup_pass.cpp +++ b/source/opt/interp_fixup_pass.cpp @@ -19,7 +19,6 @@ #include #include -#include "ir_builder.h" #include "source/opt/ir_context.h" #include "type_manager.h" diff --git a/source/opt/ir_context.cpp b/source/opt/ir_context.cpp index 889a671d07..26501c2cce 100644 --- a/source/opt/ir_context.cpp +++ b/source/opt/ir_context.cpp @@ -19,7 +19,6 @@ #include "OpenCLDebugInfo100.h" #include "source/latest_version_glsl_std_450_header.h" #include "source/opt/log.h" -#include "source/opt/mem_pass.h" #include "source/opt/reflect.h" namespace spvtools { diff --git a/source/opt/licm_pass.cpp b/source/opt/licm_pass.cpp index 514518b467..c485115fed 100644 --- a/source/opt/licm_pass.cpp +++ b/source/opt/licm_pass.cpp @@ -15,7 +15,6 @@ #include "source/opt/licm_pass.h" #include -#include #include "source/opt/module.h" #include "source/opt/pass.h" diff --git a/source/opt/local_access_chain_convert_pass.cpp b/source/opt/local_access_chain_convert_pass.cpp index 66e8813365..4b472f3845 100644 --- a/source/opt/local_access_chain_convert_pass.cpp +++ b/source/opt/local_access_chain_convert_pass.cpp @@ -16,7 +16,6 @@ #include "source/opt/local_access_chain_convert_pass.h" -#include "ir_builder.h" #include "ir_context.h" #include "iterator.h" #include "source/util/string_utils.h" diff --git a/source/opt/local_single_block_elim_pass.cpp b/source/opt/local_single_block_elim_pass.cpp index c1789c8851..ee79c25026 100644 --- a/source/opt/local_single_block_elim_pass.cpp +++ b/source/opt/local_single_block_elim_pass.cpp @@ -18,7 +18,6 @@ #include -#include "source/opt/iterator.h" #include "source/util/string_utils.h" namespace spvtools { diff --git a/source/opt/local_single_store_elim_pass.cpp b/source/opt/local_single_store_elim_pass.cpp index e494689fa6..6491d384eb 100644 --- a/source/opt/local_single_store_elim_pass.cpp +++ b/source/opt/local_single_store_elim_pass.cpp @@ -17,8 +17,6 @@ #include "source/opt/local_single_store_elim_pass.h" #include "source/cfa.h" -#include "source/latest_version_glsl_std_450_header.h" -#include "source/opt/iterator.h" #include "source/util/string_utils.h" namespace spvtools { diff --git a/source/opt/loop_dependence.cpp b/source/opt/loop_dependence.cpp index d7256bf840..e41c044afd 100644 --- a/source/opt/loop_dependence.cpp +++ b/source/opt/loop_dependence.cpp @@ -15,14 +15,12 @@ #include "source/opt/loop_dependence.h" #include -#include #include #include #include #include #include "source/opt/instruction.h" -#include "source/opt/scalar_analysis.h" #include "source/opt/scalar_analysis_nodes.h" namespace spvtools { diff --git a/source/opt/loop_dependence_helpers.cpp b/source/opt/loop_dependence_helpers.cpp index 929c9404ba..5d7d994035 100644 --- a/source/opt/loop_dependence_helpers.cpp +++ b/source/opt/loop_dependence_helpers.cpp @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/opt/loop_dependence.h" - #include #include #include @@ -23,7 +21,7 @@ #include "source/opt/basic_block.h" #include "source/opt/instruction.h" -#include "source/opt/scalar_analysis.h" +#include "source/opt/loop_dependence.h" #include "source/opt/scalar_analysis_nodes.h" namespace spvtools { diff --git a/source/opt/loop_descriptor.cpp b/source/opt/loop_descriptor.cpp index 172b978150..2a9f905945 100644 --- a/source/opt/loop_descriptor.cpp +++ b/source/opt/loop_descriptor.cpp @@ -15,17 +15,14 @@ #include "source/opt/loop_descriptor.h" #include -#include #include #include -#include #include #include #include "source/opt/cfg.h" #include "source/opt/constants.h" #include "source/opt/dominator_tree.h" -#include "source/opt/ir_builder.h" #include "source/opt/ir_context.h" #include "source/opt/iterator.h" #include "source/opt/tree_iterator.h" diff --git a/source/opt/loop_fusion_pass.cpp b/source/opt/loop_fusion_pass.cpp index bd8444ae56..097430fcf1 100644 --- a/source/opt/loop_fusion_pass.cpp +++ b/source/opt/loop_fusion_pass.cpp @@ -14,7 +14,6 @@ #include "source/opt/loop_fusion_pass.h" -#include "source/opt/ir_context.h" #include "source/opt/loop_descriptor.h" #include "source/opt/loop_fusion.h" #include "source/opt/register_pressure.h" diff --git a/source/opt/loop_peeling.cpp b/source/opt/loop_peeling.cpp index d512273035..25c6db1207 100644 --- a/source/opt/loop_peeling.cpp +++ b/source/opt/loop_peeling.cpp @@ -12,17 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#include "source/opt/loop_peeling.h" + #include #include -#include #include #include #include "source/opt/ir_builder.h" #include "source/opt/ir_context.h" #include "source/opt/loop_descriptor.h" -#include "source/opt/loop_peeling.h" #include "source/opt/loop_utils.h" #include "source/opt/scalar_analysis.h" #include "source/opt/scalar_analysis_nodes.h" diff --git a/source/opt/loop_unroller.cpp b/source/opt/loop_unroller.cpp index 07b529d494..d9e34f2423 100644 --- a/source/opt/loop_unroller.cpp +++ b/source/opt/loop_unroller.cpp @@ -15,7 +15,6 @@ #include "source/opt/loop_unroller.h" #include -#include #include #include #include diff --git a/source/opt/loop_unswitch_pass.cpp b/source/opt/loop_unswitch_pass.cpp index b00d66de82..41f1a804bf 100644 --- a/source/opt/loop_unswitch_pass.cpp +++ b/source/opt/loop_unswitch_pass.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -31,7 +30,6 @@ #include "source/opt/ir_builder.h" #include "source/opt/ir_context.h" #include "source/opt/loop_descriptor.h" - #include "source/opt/loop_utils.h" namespace spvtools { diff --git a/source/opt/mem_pass.cpp b/source/opt/mem_pass.cpp index 5f59291865..9f95785699 100644 --- a/source/opt/mem_pass.cpp +++ b/source/opt/mem_pass.cpp @@ -22,9 +22,7 @@ #include "source/cfa.h" #include "source/opt/basic_block.h" -#include "source/opt/dominator_analysis.h" #include "source/opt/ir_context.h" -#include "source/opt/iterator.h" namespace spvtools { namespace opt { diff --git a/source/opt/remove_duplicates_pass.cpp b/source/opt/remove_duplicates_pass.cpp index 90c3acff2c..0df559b345 100644 --- a/source/opt/remove_duplicates_pass.cpp +++ b/source/opt/remove_duplicates_pass.cpp @@ -15,8 +15,6 @@ #include "source/opt/remove_duplicates_pass.h" #include -#include -#include #include #include #include @@ -25,7 +23,6 @@ #include "source/opcode.h" #include "source/opt/decoration_manager.h" #include "source/opt/ir_context.h" -#include "source/opt/reflect.h" namespace spvtools { namespace opt { diff --git a/source/opt/scalar_analysis.cpp b/source/opt/scalar_analysis.cpp index 0c8babe8ae..26cc8b303a 100644 --- a/source/opt/scalar_analysis.cpp +++ b/source/opt/scalar_analysis.cpp @@ -14,7 +14,6 @@ #include "source/opt/scalar_analysis.h" -#include #include #include #include diff --git a/source/opt/scalar_analysis_simplification.cpp b/source/opt/scalar_analysis_simplification.cpp index 3c1ecc082a..3c0947cdae 100644 --- a/source/opt/scalar_analysis_simplification.cpp +++ b/source/opt/scalar_analysis_simplification.cpp @@ -12,16 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/opt/scalar_analysis.h" - #include #include #include #include -#include #include #include +#include "source/opt/scalar_analysis.h" + // Simplifies scalar analysis DAGs. // // 1. Given a node passed to SimplifyExpression we first simplify the graph by diff --git a/source/opt/scalar_replacement_pass.cpp b/source/opt/scalar_replacement_pass.cpp index bfebb01c87..ae1a2a363e 100644 --- a/source/opt/scalar_replacement_pass.cpp +++ b/source/opt/scalar_replacement_pass.cpp @@ -19,12 +19,10 @@ #include #include -#include "source/enum_string_mapping.h" #include "source/extensions.h" #include "source/opt/reflect.h" #include "source/opt/types.h" #include "source/util/make_unique.h" -#include "types.h" namespace spvtools { namespace opt { diff --git a/source/opt/set_spec_constant_default_value_pass.cpp b/source/opt/set_spec_constant_default_value_pass.cpp index 5125bd153b..d2aa9b1da2 100644 --- a/source/opt/set_spec_constant_default_value_pass.cpp +++ b/source/opt/set_spec_constant_default_value_pass.cpp @@ -21,8 +21,6 @@ #include #include "source/opt/def_use_manager.h" -#include "source/opt/ir_context.h" -#include "source/opt/type_manager.h" #include "source/opt/types.h" #include "source/util/make_unique.h" #include "source/util/parse_number.h" diff --git a/source/opt/simplification_pass.cpp b/source/opt/simplification_pass.cpp index dbda397285..f8ffc03c20 100644 --- a/source/opt/simplification_pass.cpp +++ b/source/opt/simplification_pass.cpp @@ -14,7 +14,6 @@ #include "source/opt/simplification_pass.h" -#include #include #include diff --git a/source/opt/spread_volatile_semantics.cpp b/source/opt/spread_volatile_semantics.cpp index 3037274d38..e552ba5e76 100644 --- a/source/opt/spread_volatile_semantics.cpp +++ b/source/opt/spread_volatile_semantics.cpp @@ -15,7 +15,6 @@ #include "source/opt/spread_volatile_semantics.h" #include "source/opt/decoration_manager.h" -#include "source/opt/ir_builder.h" #include "source/spirv_constant.h" namespace spvtools { diff --git a/source/opt/ssa_rewrite_pass.cpp b/source/opt/ssa_rewrite_pass.cpp index b8e22908df..3eb4ec3f8e 100644 --- a/source/opt/ssa_rewrite_pass.cpp +++ b/source/opt/ssa_rewrite_pass.cpp @@ -48,7 +48,6 @@ #include "source/opt/cfg.h" #include "source/opt/mem_pass.h" #include "source/opt/types.h" -#include "source/util/make_unique.h" // Debug logging (0: Off, 1-N: Verbosity level). Replace this with the // implementation done for diff --git a/source/opt/strength_reduction_pass.cpp b/source/opt/strength_reduction_pass.cpp index f2e849871d..16a7869ec5 100644 --- a/source/opt/strength_reduction_pass.cpp +++ b/source/opt/strength_reduction_pass.cpp @@ -14,12 +14,8 @@ #include "source/opt/strength_reduction_pass.h" -#include -#include #include #include -#include -#include #include #include diff --git a/source/opt/strip_nonsemantic_info_pass.cpp b/source/opt/strip_nonsemantic_info_pass.cpp index 889969007a..3886835ad7 100644 --- a/source/opt/strip_nonsemantic_info_pass.cpp +++ b/source/opt/strip_nonsemantic_info_pass.cpp @@ -14,7 +14,6 @@ #include "source/opt/strip_nonsemantic_info_pass.h" -#include #include #include "source/opt/instruction.h" diff --git a/source/opt/types.cpp b/source/opt/types.cpp index ab95906b6d..2f1836281b 100644 --- a/source/opt/types.cpp +++ b/source/opt/types.cpp @@ -16,7 +16,6 @@ #include #include -#include #include #include #include diff --git a/source/opt/unify_const_pass.cpp b/source/opt/unify_const_pass.cpp index f774aa6b61..83dd438b63 100644 --- a/source/opt/unify_const_pass.cpp +++ b/source/opt/unify_const_pass.cpp @@ -20,7 +20,6 @@ #include #include "source/opt/def_use_manager.h" -#include "source/opt/ir_context.h" #include "source/util/make_unique.h" namespace spvtools { diff --git a/test/opt/analyze_live_input_test.cpp b/test/opt/analyze_live_input_test.cpp index c2a8f4cb59..7f1ff2e0ce 100644 --- a/test/opt/analyze_live_input_test.cpp +++ b/test/opt/analyze_live_input_test.cpp @@ -15,7 +15,6 @@ #include -#include "gmock/gmock.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/ccp_test.cpp b/test/opt/ccp_test.cpp index f0f2436240..a8e9557db0 100644 --- a/test/opt/ccp_test.cpp +++ b/test/opt/ccp_test.cpp @@ -14,7 +14,6 @@ #include -#include "gmock/gmock.h" #include "gtest/gtest.h" #include "source/opt/ccp_pass.h" #include "test/opt/pass_fixture.h" diff --git a/test/opt/code_sink_test.cpp b/test/opt/code_sink_test.cpp index bf5029b67c..98033fb0a6 100644 --- a/test/opt/code_sink_test.cpp +++ b/test/opt/code_sink_test.cpp @@ -14,7 +14,6 @@ #include -#include "gmock/gmock.h" #include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/combine_access_chains_test.cpp b/test/opt/combine_access_chains_test.cpp index 5be3ba6384..ef7addc7eb 100644 --- a/test/opt/combine_access_chains_test.cpp +++ b/test/opt/combine_access_chains_test.cpp @@ -14,8 +14,6 @@ #include -#include "gmock/gmock.h" -#include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/compact_ids_test.cpp b/test/opt/compact_ids_test.cpp index 7c232fe4c3..42f23517ed 100644 --- a/test/opt/compact_ids_test.cpp +++ b/test/opt/compact_ids_test.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include -#include #include #include "gmock/gmock.h" diff --git a/test/opt/constant_manager_test.cpp b/test/opt/constant_manager_test.cpp index 14e14ec20e..54c86527e4 100644 --- a/test/opt/constant_manager_test.cpp +++ b/test/opt/constant_manager_test.cpp @@ -13,9 +13,7 @@ // limitations under the License. #include -#include -#include "gmock/gmock.h" #include "gtest/gtest.h" #include "source/opt/build_module.h" #include "source/opt/constants.h" diff --git a/test/opt/constants_test.cpp b/test/opt/constants_test.cpp index 55c92a513f..1d4c738fc3 100644 --- a/test/opt/constants_test.cpp +++ b/test/opt/constants_test.cpp @@ -16,7 +16,6 @@ #include -#include "gmock/gmock.h" #include "gtest/gtest.h" #include "source/opt/types.h" diff --git a/test/opt/copy_prop_array_test.cpp b/test/opt/copy_prop_array_test.cpp index d6e376ecc7..2d4b7a3b60 100644 --- a/test/opt/copy_prop_array_test.cpp +++ b/test/opt/copy_prop_array_test.cpp @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include #include #include "gmock/gmock.h" diff --git a/test/opt/dataflow.cpp b/test/opt/dataflow.cpp index 51473d84e7..dcb6bc6afe 100644 --- a/test/opt/dataflow.cpp +++ b/test/opt/dataflow.cpp @@ -17,7 +17,6 @@ #include #include -#include "gmock/gmock.h" #include "gtest/gtest.h" #include "opt/function_utils.h" #include "source/opt/build_module.h" diff --git a/test/opt/debug_info_manager_test.cpp b/test/opt/debug_info_manager_test.cpp index 9e479c0fb5..3df26a9765 100644 --- a/test/opt/debug_info_manager_test.cpp +++ b/test/opt/debug_info_manager_test.cpp @@ -15,11 +15,8 @@ #include "source/opt/debug_info_manager.h" #include -#include #include -#include "effcee/effcee.h" -#include "gmock/gmock.h" #include "gtest/gtest.h" #include "source/opt/build_module.h" #include "source/opt/instruction.h" diff --git a/test/opt/decoration_manager_test.cpp b/test/opt/decoration_manager_test.cpp index cf3516a9ff..b287d5ec97 100644 --- a/test/opt/decoration_manager_test.cpp +++ b/test/opt/decoration_manager_test.cpp @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include #include #include #include diff --git a/test/opt/def_use_test.cpp b/test/opt/def_use_test.cpp index 431501274c..5f7731be3b 100644 --- a/test/opt/def_use_test.cpp +++ b/test/opt/def_use_test.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include -#include #include #include #include diff --git a/test/opt/desc_sroa_test.cpp b/test/opt/desc_sroa_test.cpp index 91c950e88e..7a118f988e 100644 --- a/test/opt/desc_sroa_test.cpp +++ b/test/opt/desc_sroa_test.cpp @@ -14,8 +14,6 @@ #include -#include "gmock/gmock.h" -#include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/dominator_tree/common_dominators.cpp b/test/opt/dominator_tree/common_dominators.cpp index dfa03e986a..9573afa228 100644 --- a/test/opt/dominator_tree/common_dominators.cpp +++ b/test/opt/dominator_tree/common_dominators.cpp @@ -13,9 +13,7 @@ // limitations under the License. #include -#include -#include "gmock/gmock.h" #include "gtest/gtest.h" #include "source/opt/build_module.h" #include "source/opt/ir_context.h" diff --git a/test/opt/dominator_tree/generated.cpp b/test/opt/dominator_tree/generated.cpp index 4fccef0527..2a5bc98a75 100644 --- a/test/opt/dominator_tree/generated.cpp +++ b/test/opt/dominator_tree/generated.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include diff --git a/test/opt/dominator_tree/nested_ifs.cpp b/test/opt/dominator_tree/nested_ifs.cpp index 0552b75801..848296a236 100644 --- a/test/opt/dominator_tree/nested_ifs.cpp +++ b/test/opt/dominator_tree/nested_ifs.cpp @@ -12,9 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. - #include -#include #include #include "gmock/gmock.h" diff --git a/test/opt/dominator_tree/nested_ifs_post.cpp b/test/opt/dominator_tree/nested_ifs_post.cpp index ad759df868..217bdece1f 100644 --- a/test/opt/dominator_tree/nested_ifs_post.cpp +++ b/test/opt/dominator_tree/nested_ifs_post.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include -#include #include #include "gmock/gmock.h" diff --git a/test/opt/dominator_tree/nested_loops.cpp b/test/opt/dominator_tree/nested_loops.cpp index 7d03937b1a..a82f4095c4 100644 --- a/test/opt/dominator_tree/nested_loops.cpp +++ b/test/opt/dominator_tree/nested_loops.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include -#include #include #include "gmock/gmock.h" diff --git a/test/opt/dominator_tree/nested_loops_with_unreachables.cpp b/test/opt/dominator_tree/nested_loops_with_unreachables.cpp index e87e8ddab3..2c91bd1e2f 100644 --- a/test/opt/dominator_tree/nested_loops_with_unreachables.cpp +++ b/test/opt/dominator_tree/nested_loops_with_unreachables.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include -#include #include #include "gmock/gmock.h" diff --git a/test/opt/dominator_tree/post.cpp b/test/opt/dominator_tree/post.cpp index bb10fdef1d..acbf01272b 100644 --- a/test/opt/dominator_tree/post.cpp +++ b/test/opt/dominator_tree/post.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include -#include #include #include "gmock/gmock.h" diff --git a/test/opt/dominator_tree/simple.cpp b/test/opt/dominator_tree/simple.cpp index d11854d550..eae243850e 100644 --- a/test/opt/dominator_tree/simple.cpp +++ b/test/opt/dominator_tree/simple.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include -#include #include #include "gmock/gmock.h" diff --git a/test/opt/dominator_tree/switch_case_fallthrough.cpp b/test/opt/dominator_tree/switch_case_fallthrough.cpp index d9dd7d1619..9eeb4103b2 100644 --- a/test/opt/dominator_tree/switch_case_fallthrough.cpp +++ b/test/opt/dominator_tree/switch_case_fallthrough.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include -#include #include #include "gmock/gmock.h" diff --git a/test/opt/dominator_tree/unreachable_for.cpp b/test/opt/dominator_tree/unreachable_for.cpp index 469e5c142d..bf95930d17 100644 --- a/test/opt/dominator_tree/unreachable_for.cpp +++ b/test/opt/dominator_tree/unreachable_for.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include -#include #include #include "gmock/gmock.h" diff --git a/test/opt/dominator_tree/unreachable_for_post.cpp b/test/opt/dominator_tree/unreachable_for_post.cpp index 8d3e37b4a4..57278f50e0 100644 --- a/test/opt/dominator_tree/unreachable_for_post.cpp +++ b/test/opt/dominator_tree/unreachable_for_post.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include -#include #include #include "gmock/gmock.h" diff --git a/test/opt/eliminate_dead_const_test.cpp b/test/opt/eliminate_dead_const_test.cpp index 87aab54511..ec4c284e68 100644 --- a/test/opt/eliminate_dead_const_test.cpp +++ b/test/opt/eliminate_dead_const_test.cpp @@ -13,9 +13,6 @@ // limitations under the License. #include -#include -#include -#include #include #include #include diff --git a/test/opt/eliminate_dead_io_components_test.cpp b/test/opt/eliminate_dead_io_components_test.cpp index da26cefde5..b7a2fb5056 100644 --- a/test/opt/eliminate_dead_io_components_test.cpp +++ b/test/opt/eliminate_dead_io_components_test.cpp @@ -15,7 +15,6 @@ #include -#include "gmock/gmock.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/eliminate_dead_member_test.cpp b/test/opt/eliminate_dead_member_test.cpp index 4438f3d864..bb0ec039bc 100644 --- a/test/opt/eliminate_dead_member_test.cpp +++ b/test/opt/eliminate_dead_member_test.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include "assembly_builder.h" -#include "gmock/gmock.h" #include "pass_fixture.h" #include "pass_utils.h" diff --git a/test/opt/eliminate_dead_output_stores_test.cpp b/test/opt/eliminate_dead_output_stores_test.cpp index 470e709ebb..4c2e44c001 100644 --- a/test/opt/eliminate_dead_output_stores_test.cpp +++ b/test/opt/eliminate_dead_output_stores_test.cpp @@ -15,7 +15,6 @@ #include -#include "gmock/gmock.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/feature_manager_test.cpp b/test/opt/feature_manager_test.cpp index 94c7734b8e..a5105a9ac5 100644 --- a/test/opt/feature_manager_test.cpp +++ b/test/opt/feature_manager_test.cpp @@ -14,9 +14,7 @@ #include #include -#include -#include "gmock/gmock.h" #include "gtest/gtest.h" #include "source/opt/build_module.h" #include "source/opt/ir_context.h" diff --git a/test/opt/fix_func_call_arguments_test.cpp b/test/opt/fix_func_call_arguments_test.cpp index ecd13a866d..606ed261ed 100644 --- a/test/opt/fix_func_call_arguments_test.cpp +++ b/test/opt/fix_func_call_arguments_test.cpp @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "gmock/gmock.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/fix_storage_class_test.cpp b/test/opt/fix_storage_class_test.cpp index 1c0101a0e6..93ce873605 100644 --- a/test/opt/fix_storage_class_test.cpp +++ b/test/opt/fix_storage_class_test.cpp @@ -14,8 +14,6 @@ #include -#include "gmock/gmock.h" -#include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/flatten_decoration_test.cpp b/test/opt/flatten_decoration_test.cpp index 63207fd21f..d7ac2ab789 100644 --- a/test/opt/flatten_decoration_test.cpp +++ b/test/opt/flatten_decoration_test.cpp @@ -16,7 +16,6 @@ #include #include -#include "gmock/gmock.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index 111973b26a..636c20cd60 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -27,7 +27,6 @@ #include "source/opt/ir_context.h" #include "source/opt/module.h" #include "spirv-tools/libspirv.hpp" -#include "test/opt/pass_utils.h" namespace spvtools { namespace opt { diff --git a/test/opt/freeze_spec_const_test.cpp b/test/opt/freeze_spec_const_test.cpp index ad0fc32ea0..1ccaa3ef0e 100644 --- a/test/opt/freeze_spec_const_test.cpp +++ b/test/opt/freeze_spec_const_test.cpp @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include #include #include #include diff --git a/test/opt/function_test.cpp b/test/opt/function_test.cpp index 09cca33492..6a40e93878 100644 --- a/test/opt/function_test.cpp +++ b/test/opt/function_test.cpp @@ -13,8 +13,6 @@ // limitations under the License. #include -#include -#include #include #include "function_utils.h" diff --git a/test/opt/graphics_robust_access_test.cpp b/test/opt/graphics_robust_access_test.cpp index 057b909def..a1a3b7d3fd 100644 --- a/test/opt/graphics_robust_access_test.cpp +++ b/test/opt/graphics_robust_access_test.cpp @@ -12,12 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include #include #include #include -#include "gmock/gmock.h" #include "pass_fixture.h" #include "pass_utils.h" #include "source/opt/graphics_robust_access_pass.h" diff --git a/test/opt/if_conversion_test.cpp b/test/opt/if_conversion_test.cpp index dc7f83163d..c1425e830c 100644 --- a/test/opt/if_conversion_test.cpp +++ b/test/opt/if_conversion_test.cpp @@ -14,8 +14,6 @@ #include -#include "gmock/gmock.h" -#include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp index d450511e0c..5ee6eed492 100644 --- a/test/opt/inst_bindless_check_test.cpp +++ b/test/opt/inst_bindless_check_test.cpp @@ -18,7 +18,6 @@ #include #include -#include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/inst_buff_addr_check_test.cpp b/test/opt/inst_buff_addr_check_test.cpp index 4a56f60500..80e6b7a065 100644 --- a/test/opt/inst_buff_addr_check_test.cpp +++ b/test/opt/inst_buff_addr_check_test.cpp @@ -19,7 +19,6 @@ #include #include -#include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/inst_debug_printf_test.cpp b/test/opt/inst_debug_printf_test.cpp index 4031480311..7dd10d8fad 100644 --- a/test/opt/inst_debug_printf_test.cpp +++ b/test/opt/inst_debug_printf_test.cpp @@ -18,7 +18,6 @@ #include #include -#include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/instruction_test.cpp b/test/opt/instruction_test.cpp index 6ea7fccef2..67961eb696 100644 --- a/test/opt/instruction_test.cpp +++ b/test/opt/instruction_test.cpp @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "source/opt/instruction.h" + #include -#include #include #include #include "gmock/gmock.h" -#include "source/opt/instruction.h" #include "source/opt/ir_context.h" #include "spirv-tools/libspirv.h" #include "test/opt/pass_fixture.h" diff --git a/test/opt/interface_var_sroa_test.cpp b/test/opt/interface_var_sroa_test.cpp index 77624587bf..6f51b087f1 100644 --- a/test/opt/interface_var_sroa_test.cpp +++ b/test/opt/interface_var_sroa_test.cpp @@ -14,8 +14,6 @@ #include -#include "gmock/gmock.h" -#include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/ir_builder.cpp b/test/opt/ir_builder.cpp index e04e7815f5..f0cfc1849b 100644 --- a/test/opt/ir_builder.cpp +++ b/test/opt/ir_builder.cpp @@ -12,18 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#include "source/opt/ir_builder.h" + #include -#include #include #include "effcee/effcee.h" -#include "gmock/gmock.h" #include "gtest/gtest.h" #include "source/opt/basic_block.h" #include "source/opt/build_module.h" #include "source/opt/instruction.h" -#include "source/opt/ir_builder.h" #include "source/opt/type_manager.h" #include "spirv-tools/libspirv.hpp" diff --git a/test/opt/ir_context_test.cpp b/test/opt/ir_context_test.cpp index 28cd0d5e92..1acbefe7ee 100644 --- a/test/opt/ir_context_test.cpp +++ b/test/opt/ir_context_test.cpp @@ -16,7 +16,6 @@ #include #include -#include #include #include "OpenCLDebugInfo100.h" diff --git a/test/opt/ir_loader_test.cpp b/test/opt/ir_loader_test.cpp index 45104f4714..769a25dd6c 100644 --- a/test/opt/ir_loader_test.cpp +++ b/test/opt/ir_loader_test.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include #include diff --git a/test/opt/local_redundancy_elimination_test.cpp b/test/opt/local_redundancy_elimination_test.cpp index 291e1bc258..01f766615a 100644 --- a/test/opt/local_redundancy_elimination_test.cpp +++ b/test/opt/local_redundancy_elimination_test.cpp @@ -15,9 +15,7 @@ #include #include "gmock/gmock.h" -#include "source/opt/build_module.h" #include "source/opt/value_number_table.h" -#include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/loop_optimizations/dependence_analysis.cpp b/test/opt/loop_optimizations/dependence_analysis.cpp index 42d9acba1b..40520f574f 100644 --- a/test/opt/loop_optimizations/dependence_analysis.cpp +++ b/test/opt/loop_optimizations/dependence_analysis.cpp @@ -14,17 +14,11 @@ #include #include -#include -#include #include #include -#include "gmock/gmock.h" -#include "source/opt/iterator.h" #include "source/opt/loop_dependence.h" #include "source/opt/loop_descriptor.h" -#include "source/opt/pass.h" -#include "source/opt/tree_iterator.h" #include "test/opt//assembly_builder.h" #include "test/opt//function_utils.h" #include "test/opt//pass_fixture.h" diff --git a/test/opt/loop_optimizations/dependence_analysis_helpers.cpp b/test/opt/loop_optimizations/dependence_analysis_helpers.cpp index aabf478447..620619983a 100644 --- a/test/opt/loop_optimizations/dependence_analysis_helpers.cpp +++ b/test/opt/loop_optimizations/dependence_analysis_helpers.cpp @@ -13,17 +13,11 @@ // limitations under the License. #include -#include -#include #include -#include "gmock/gmock.h" -#include "source/opt/iterator.h" #include "source/opt/loop_dependence.h" #include "source/opt/loop_descriptor.h" -#include "source/opt/pass.h" #include "source/opt/scalar_analysis.h" -#include "source/opt/tree_iterator.h" #include "test/opt/assembly_builder.h" #include "test/opt/function_utils.h" #include "test/opt/pass_fixture.h" diff --git a/test/opt/loop_optimizations/fusion_compatibility.cpp b/test/opt/loop_optimizations/fusion_compatibility.cpp index cda8576c5d..9acfe8fc9e 100644 --- a/test/opt/loop_optimizations/fusion_compatibility.cpp +++ b/test/opt/loop_optimizations/fusion_compatibility.cpp @@ -12,10 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include -#include #include -#include #include #include "gmock/gmock.h" diff --git a/test/opt/loop_optimizations/fusion_illegal.cpp b/test/opt/loop_optimizations/fusion_illegal.cpp index 26d54457d2..bff416b676 100644 --- a/test/opt/loop_optimizations/fusion_illegal.cpp +++ b/test/opt/loop_optimizations/fusion_illegal.cpp @@ -12,10 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include -#include #include -#include #include #include "gmock/gmock.h" diff --git a/test/opt/loop_optimizations/fusion_legal.cpp b/test/opt/loop_optimizations/fusion_legal.cpp index 56b0b76f4c..ef7daeeaeb 100644 --- a/test/opt/loop_optimizations/fusion_legal.cpp +++ b/test/opt/loop_optimizations/fusion_legal.cpp @@ -12,10 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include -#include #include -#include #include #include "effcee/effcee.h" diff --git a/test/opt/loop_optimizations/lcssa.cpp b/test/opt/loop_optimizations/lcssa.cpp index ace6ce1968..32c2f7235a 100644 --- a/test/opt/loop_optimizations/lcssa.cpp +++ b/test/opt/loop_optimizations/lcssa.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include -#include #include #include "effcee/effcee.h" @@ -21,7 +20,6 @@ #include "source/opt/build_module.h" #include "source/opt/loop_descriptor.h" #include "source/opt/loop_utils.h" -#include "source/opt/pass.h" #include "test/opt//assembly_builder.h" #include "test/opt/function_utils.h" diff --git a/test/opt/loop_optimizations/loop_descriptions.cpp b/test/opt/loop_optimizations/loop_descriptions.cpp index b3f4f440cd..3dd0b93058 100644 --- a/test/opt/loop_optimizations/loop_descriptions.cpp +++ b/test/opt/loop_optimizations/loop_descriptions.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include -#include #include #include "gmock/gmock.h" diff --git a/test/opt/loop_optimizations/loop_fission.cpp b/test/opt/loop_optimizations/loop_fission.cpp index bc3ec39bdf..41e40c3b12 100644 --- a/test/opt/loop_optimizations/loop_fission.cpp +++ b/test/opt/loop_optimizations/loop_fission.cpp @@ -12,15 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "source/opt/loop_fission.h" + #include -#include #include #include "gmock/gmock.h" -#include "source/opt/loop_fission.h" -#include "source/opt/loop_unroller.h" #include "source/opt/loop_utils.h" -#include "source/opt/pass.h" #include "test/opt/assembly_builder.h" #include "test/opt/function_utils.h" #include "test/opt/pass_fixture.h" diff --git a/test/opt/loop_optimizations/peeling.cpp b/test/opt/loop_optimizations/peeling.cpp index 4ff7a5a2e9..34c33074f4 100644 --- a/test/opt/loop_optimizations/peeling.cpp +++ b/test/opt/loop_optimizations/peeling.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include -#include #include #include "effcee/effcee.h" diff --git a/test/opt/loop_optimizations/peeling_pass.cpp b/test/opt/loop_optimizations/peeling_pass.cpp index 1b5a12d244..ad7fcdc3c6 100644 --- a/test/opt/loop_optimizations/peeling_pass.cpp +++ b/test/opt/loop_optimizations/peeling_pass.cpp @@ -17,7 +17,6 @@ #include #include "gmock/gmock.h" -#include "source/opt/ir_builder.h" #include "source/opt/loop_descriptor.h" #include "source/opt/loop_peeling.h" #include "test/opt/pass_fixture.h" diff --git a/test/opt/loop_optimizations/unroll_assumptions.cpp b/test/opt/loop_optimizations/unroll_assumptions.cpp index 159e4a1430..81657a50b3 100644 --- a/test/opt/loop_optimizations/unroll_assumptions.cpp +++ b/test/opt/loop_optimizations/unroll_assumptions.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include -#include #include #include "gmock/gmock.h" diff --git a/test/opt/loop_optimizations/unroll_simple.cpp b/test/opt/loop_optimizations/unroll_simple.cpp index 299fb2d5c3..6468adf48b 100644 --- a/test/opt/loop_optimizations/unroll_simple.cpp +++ b/test/opt/loop_optimizations/unroll_simple.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include -#include #include #include "gmock/gmock.h" diff --git a/test/opt/module_test.cpp b/test/opt/module_test.cpp index 33dc05f8a1..a93a50b08e 100644 --- a/test/opt/module_test.cpp +++ b/test/opt/module_test.cpp @@ -12,16 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "source/opt/module.h" + #include -#include -#include #include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "source/opt/build_module.h" -#include "source/opt/module.h" -#include "source/opt/pass.h" #include "spirv-tools/libspirv.hpp" #include "test/opt/module_utils.h" diff --git a/test/opt/pass_merge_return_test.cpp b/test/opt/pass_merge_return_test.cpp index 04bd5d9b9c..494f2e95f0 100644 --- a/test/opt/pass_merge_return_test.cpp +++ b/test/opt/pass_merge_return_test.cpp @@ -14,9 +14,7 @@ #include -#include "gmock/gmock.h" #include "spirv-tools/libspirv.hpp" -#include "spirv-tools/optimizer.hpp" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/pass_remove_duplicates_test.cpp b/test/opt/pass_remove_duplicates_test.cpp index ac87db17fe..131a6b4bc4 100644 --- a/test/opt/pass_remove_duplicates_test.cpp +++ b/test/opt/pass_remove_duplicates_test.cpp @@ -12,12 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include #include #include #include -#include "gmock/gmock.h" #include "source/opt/build_module.h" #include "source/opt/ir_context.h" #include "source/opt/pass_manager.h" diff --git a/test/opt/private_to_local_test.cpp b/test/opt/private_to_local_test.cpp index 8b5ec59e22..f7c37c9111 100644 --- a/test/opt/private_to_local_test.cpp +++ b/test/opt/private_to_local_test.cpp @@ -15,7 +15,6 @@ #include #include "gmock/gmock.h" -#include "source/opt/build_module.h" #include "source/opt/value_number_table.h" #include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" diff --git a/test/opt/propagator_test.cpp b/test/opt/propagator_test.cpp index 76211a58f0..307a2a12b2 100644 --- a/test/opt/propagator_test.cpp +++ b/test/opt/propagator_test.cpp @@ -12,9 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "source/opt/propagator.h" + #include #include -#include #include #include "gmock/gmock.h" @@ -22,8 +23,6 @@ #include "source/opt/build_module.h" #include "source/opt/cfg.h" #include "source/opt/ir_context.h" -#include "source/opt/pass.h" -#include "source/opt/propagator.h" namespace spvtools { namespace opt { diff --git a/test/opt/redundancy_elimination_test.cpp b/test/opt/redundancy_elimination_test.cpp index 28eda73eff..eb78497b89 100644 --- a/test/opt/redundancy_elimination_test.cpp +++ b/test/opt/redundancy_elimination_test.cpp @@ -15,8 +15,6 @@ #include #include "gmock/gmock.h" -#include "source/opt/build_module.h" -#include "source/opt/value_number_table.h" #include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/register_liveness.cpp b/test/opt/register_liveness.cpp index 7cb210f1e5..3870e2f995 100644 --- a/test/opt/register_liveness.cpp +++ b/test/opt/register_liveness.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include -#include #include #include diff --git a/test/opt/relax_float_ops_test.cpp b/test/opt/relax_float_ops_test.cpp index b9cb0de097..e486df3001 100644 --- a/test/opt/relax_float_ops_test.cpp +++ b/test/opt/relax_float_ops_test.cpp @@ -18,7 +18,6 @@ #include #include -#include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/remove_unused_interface_variables_test.cpp b/test/opt/remove_unused_interface_variables_test.cpp index ddf027f1ba..8bb40f7bf9 100644 --- a/test/opt/remove_unused_interface_variables_test.cpp +++ b/test/opt/remove_unused_interface_variables_test.cpp @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "gmock/gmock.h" #include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/replace_desc_array_access_using_var_index_test.cpp b/test/opt/replace_desc_array_access_using_var_index_test.cpp index 9ab9eb1148..6018be23e3 100644 --- a/test/opt/replace_desc_array_access_using_var_index_test.cpp +++ b/test/opt/replace_desc_array_access_using_var_index_test.cpp @@ -14,8 +14,6 @@ #include -#include "gmock/gmock.h" -#include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/replace_invalid_opc_test.cpp b/test/opt/replace_invalid_opc_test.cpp index c0f5df29d2..aee0d6e2f2 100644 --- a/test/opt/replace_invalid_opc_test.cpp +++ b/test/opt/replace_invalid_opc_test.cpp @@ -12,11 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include #include #include -#include "gmock/gmock.h" #include "pass_utils.h" #include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" diff --git a/test/opt/scalar_analysis.cpp b/test/opt/scalar_analysis.cpp index 14f82af68a..4779658d19 100644 --- a/test/opt/scalar_analysis.cpp +++ b/test/opt/scalar_analysis.cpp @@ -12,17 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "source/opt/scalar_analysis.h" + #include -#include -#include #include #include "gmock/gmock.h" -#include "source/opt/iterator.h" -#include "source/opt/loop_descriptor.h" #include "source/opt/pass.h" -#include "source/opt/scalar_analysis.h" -#include "source/opt/tree_iterator.h" #include "test/opt/assembly_builder.h" #include "test/opt/function_utils.h" #include "test/opt/pass_fixture.h" diff --git a/test/opt/scalar_replacement_test.cpp b/test/opt/scalar_replacement_test.cpp index 0c97c80b77..b63a6b6c11 100644 --- a/test/opt/scalar_replacement_test.cpp +++ b/test/opt/scalar_replacement_test.cpp @@ -12,11 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/opt/scalar_replacement_pass.h" - #include -#include "gmock/gmock.h" +#include "source/opt/scalar_replacement_pass.h" #include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/simplification_test.cpp b/test/opt/simplification_test.cpp index 7727f5673d..7fce289804 100644 --- a/test/opt/simplification_test.cpp +++ b/test/opt/simplification_test.cpp @@ -16,7 +16,6 @@ #include "gmock/gmock.h" #include "source/opt/simplification_pass.h" -#include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" namespace spvtools { diff --git a/test/opt/spread_volatile_semantics_test.cpp b/test/opt/spread_volatile_semantics_test.cpp index dbb889c090..4328c396d9 100644 --- a/test/opt/spread_volatile_semantics_test.cpp +++ b/test/opt/spread_volatile_semantics_test.cpp @@ -14,7 +14,6 @@ #include -#include "gmock/gmock.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/strength_reduction_test.cpp b/test/opt/strength_reduction_test.cpp index 31d0503605..a37c6c23a8 100644 --- a/test/opt/strength_reduction_test.cpp +++ b/test/opt/strength_reduction_test.cpp @@ -12,16 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include -#include -#include -#include #include #include #include #include "gmock/gmock.h" -#include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/struct_cfg_analysis_test.cpp b/test/opt/struct_cfg_analysis_test.cpp index e7031cb5ca..9c72cee955 100644 --- a/test/opt/struct_cfg_analysis_test.cpp +++ b/test/opt/struct_cfg_analysis_test.cpp @@ -17,7 +17,6 @@ #include #include "gmock/gmock.h" -#include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/type_manager_test.cpp b/test/opt/type_manager_test.cpp index bc80050c37..563eb74012 100644 --- a/test/opt/type_manager_test.cpp +++ b/test/opt/type_manager_test.cpp @@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "source/opt/type_manager.h" + #include -#include #include #include @@ -22,7 +23,6 @@ #include "gtest/gtest.h" #include "source/opt/build_module.h" #include "source/opt/instruction.h" -#include "source/opt/type_manager.h" #include "spirv-tools/libspirv.hpp" namespace spvtools { diff --git a/test/opt/upgrade_memory_model_test.cpp b/test/opt/upgrade_memory_model_test.cpp index 2cd3c7dfb5..d213b8be0c 100644 --- a/test/opt/upgrade_memory_model_test.cpp +++ b/test/opt/upgrade_memory_model_test.cpp @@ -13,7 +13,6 @@ // limitations under the License. #include "assembly_builder.h" -#include "gmock/gmock.h" #include "pass_fixture.h" #include "pass_utils.h" diff --git a/test/opt/value_table_test.cpp b/test/opt/value_table_test.cpp index c760f98598..3d7aaad5b2 100644 --- a/test/opt/value_table_test.cpp +++ b/test/opt/value_table_test.cpp @@ -17,7 +17,6 @@ #include "gmock/gmock.h" #include "source/opt/build_module.h" #include "source/opt/value_number_table.h" -#include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" namespace spvtools { diff --git a/test/opt/workaround1209_test.cpp b/test/opt/workaround1209_test.cpp index 50d3c09151..5b0146b9ba 100644 --- a/test/opt/workaround1209_test.cpp +++ b/test/opt/workaround1209_test.cpp @@ -12,15 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include -#include -#include -#include #include #include -#include "gmock/gmock.h" -#include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" diff --git a/test/opt/wrap_opkill_test.cpp b/test/opt/wrap_opkill_test.cpp index e40d701f07..efc834cf04 100644 --- a/test/opt/wrap_opkill_test.cpp +++ b/test/opt/wrap_opkill_test.cpp @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "gmock/gmock.h" #include "test/opt/assembly_builder.h" #include "test/opt/pass_fixture.h" #include "test/opt/pass_utils.h" From 4680d2bef8bce0693b4697f1a2568cb43774ece4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 28 Mar 2023 12:41:01 -0400 Subject: [PATCH 108/523] Roll external/googletest/ e9fb5c7ba..88af49efa (1 commit) (#5179) https://github.com/google/googletest/compare/e9fb5c7bacc4...88af49efa72a $ git log e9fb5c7ba..88af49efa --date=short --no-merges --format='%ad %ae %s' 2023-03-27 dmauro Migrate CI builds to MSVC 2022 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 e94772101e..cad1641a9f 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': 'e9fb5c7bacc4a25b030569c92ff9f6925288f1c3', + 'googletest_revision': '88af49efa72a06d56910d69ecfd87e3b330e5778', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From d8a8af8e6dc7b88530408485ee6dae7a8abaf695 Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Wed, 29 Mar 2023 03:18:19 +0900 Subject: [PATCH 109/523] spirv-val: Remove unused includes and code (#5176) --- source/val/basic_block.cpp | 1 - source/val/construct.cpp | 1 - source/val/function.cpp | 1 - source/val/validate.cpp | 8 -------- source/val/validate.h | 5 ----- source/val/validate_adjacency.cpp | 5 +---- source/val/validate_arithmetics.cpp | 4 +--- source/val/validate_atomics.cpp | 4 +--- source/val/validate_barriers.cpp | 3 --- source/val/validate_bitwise.cpp | 1 - source/val/validate_builtins.cpp | 2 -- source/val/validate_capability.cpp | 2 -- source/val/validate_cfg.cpp | 3 --- source/val/validate_composites.cpp | 4 +--- source/val/validate_conversion.cpp | 1 - source/val/validate_debug.cpp | 4 +--- source/val/validate_decorations.cpp | 8 -------- source/val/validate_derivatives.cpp | 4 +--- source/val/validate_execution_limitations.cpp | 2 -- source/val/validate_extensions.cpp | 6 +----- source/val/validate_id.cpp | 13 +------------ source/val/validate_image.cpp | 1 - source/val/validate_instruction.cpp | 6 ------ source/val/validate_interfaces.cpp | 1 - source/val/validate_layout.cpp | 3 --- source/val/validate_literals.cpp | 5 +---- source/val/validate_logicals.cpp | 4 +--- source/val/validate_memory_semantics.cpp | 1 - source/val/validate_non_uniform.cpp | 5 +---- source/val/validate_primitives.cpp | 4 +--- source/val/validate_scopes.cpp | 1 - test/val/val_annotation_test.cpp | 1 - test/val/val_cfg_test.cpp | 2 -- test/val/val_data_test.cpp | 1 - test/val/val_decoration_test.cpp | 1 - .../val_extension_spv_khr_bit_instructions_test.cpp | 3 --- .../val_extension_spv_khr_expect_assume_test.cpp | 3 --- ...l_extension_spv_khr_integer_dot_product_test.cpp | 3 --- .../val/val_extension_spv_khr_linkonce_odr_test.cpp | 3 --- ...n_spv_khr_subgroup_uniform_control_flow_test.cpp | 3 --- ..._extension_spv_khr_terminate_invocation_test.cpp | 3 --- test/val/val_extensions_test.cpp | 2 -- test/val/val_function_test.cpp | 2 -- test/val/val_layout_test.cpp | 9 --------- test/val/val_limits_test.cpp | 1 - test/val/val_mesh_shading_test.cpp | 1 - test/val/val_modes_test.cpp | 1 - test/val/val_state_test.cpp | 6 +----- test/val/val_storage_test.cpp | 2 -- 49 files changed, 13 insertions(+), 147 deletions(-) diff --git a/source/val/basic_block.cpp b/source/val/basic_block.cpp index da05db3a81..9a358fcb97 100644 --- a/source/val/basic_block.cpp +++ b/source/val/basic_block.cpp @@ -15,7 +15,6 @@ #include "source/val/basic_block.h" #include -#include #include namespace spvtools { diff --git a/source/val/construct.cpp b/source/val/construct.cpp index 1ca81d4161..10af155da2 100644 --- a/source/val/construct.cpp +++ b/source/val/construct.cpp @@ -16,7 +16,6 @@ #include #include -#include #include "source/val/function.h" #include "source/val/validation_state.h" diff --git a/source/val/function.cpp b/source/val/function.cpp index 8b4423a1f9..290574b859 100644 --- a/source/val/function.cpp +++ b/source/val/function.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include "source/cfa.h" diff --git a/source/val/validate.cpp b/source/val/validate.cpp index 52cb0d8bb8..e73e466026 100644 --- a/source/val/validate.cpp +++ b/source/val/validate.cpp @@ -14,13 +14,9 @@ #include "source/val/validate.h" -#include -#include -#include #include #include #include -#include #include #include @@ -28,15 +24,11 @@ #include "source/diagnostic.h" #include "source/enum_string_mapping.h" #include "source/extensions.h" -#include "source/instruction.h" #include "source/opcode.h" -#include "source/operand.h" #include "source/spirv_constant.h" #include "source/spirv_endian.h" #include "source/spirv_target_env.h" -#include "source/spirv_validator_options.h" #include "source/val/construct.h" -#include "source/val/function.h" #include "source/val/instruction.h" #include "source/val/validation_state.h" #include "spirv-tools/libspirv.h" diff --git a/source/val/validate.h b/source/val/validate.h index 898743859e..2cd229f96a 100644 --- a/source/val/validate.h +++ b/source/val/validate.h @@ -31,11 +31,6 @@ class ValidationState_t; class BasicBlock; class Instruction; -/// A function that returns a vector of BasicBlocks given a BasicBlock. Used to -/// get the successor and predecessor nodes of a CFG block -using get_blocks_func = - std::function*(const BasicBlock*)>; - /// @brief Performs the Control Flow Graph checks /// /// @param[in] _ the validation state of the module diff --git a/source/val/validate_adjacency.cpp b/source/val/validate_adjacency.cpp index 50c2e92aec..7e371c2f9f 100644 --- a/source/val/validate_adjacency.cpp +++ b/source/val/validate_adjacency.cpp @@ -15,13 +15,10 @@ // Validates correctness of the intra-block preconditions of SPIR-V // instructions. -#include "source/val/validate.h" - #include -#include "source/diagnostic.h" -#include "source/opcode.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { diff --git a/source/val/validate_arithmetics.cpp b/source/val/validate_arithmetics.cpp index a082eebc9f..4e7dd5e884 100644 --- a/source/val/validate_arithmetics.cpp +++ b/source/val/validate_arithmetics.cpp @@ -14,13 +14,11 @@ // Performs validation of arithmetic instructions. -#include "source/val/validate.h" - #include -#include "source/diagnostic.h" #include "source/opcode.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { diff --git a/source/val/validate_atomics.cpp b/source/val/validate_atomics.cpp index d6b094c4aa..b745a9ec1d 100644 --- a/source/val/validate_atomics.cpp +++ b/source/val/validate_atomics.cpp @@ -16,13 +16,11 @@ // Validates correctness of atomic SPIR-V instructions. -#include "source/val/validate.h" - -#include "source/diagnostic.h" #include "source/opcode.h" #include "source/spirv_target_env.h" #include "source/util/bitutils.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validate_memory_semantics.h" #include "source/val/validate_scopes.h" #include "source/val/validation_state.h" diff --git a/source/val/validate_barriers.cpp b/source/val/validate_barriers.cpp index 59d886a117..0abd5c8599 100644 --- a/source/val/validate_barriers.cpp +++ b/source/val/validate_barriers.cpp @@ -16,11 +16,8 @@ #include -#include "source/diagnostic.h" #include "source/opcode.h" #include "source/spirv_constant.h" -#include "source/spirv_target_env.h" -#include "source/util/bitutils.h" #include "source/val/instruction.h" #include "source/val/validate.h" #include "source/val/validate_memory_semantics.h" diff --git a/source/val/validate_bitwise.cpp b/source/val/validate_bitwise.cpp index 6ab1faebc3..d8d995814d 100644 --- a/source/val/validate_bitwise.cpp +++ b/source/val/validate_bitwise.cpp @@ -14,7 +14,6 @@ // Validates correctness of bitwise instructions. -#include "source/diagnostic.h" #include "source/opcode.h" #include "source/spirv_target_env.h" #include "source/val/instruction.h" diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp index c07dcaddd2..3e81712506 100644 --- a/source/val/validate_builtins.cpp +++ b/source/val/validate_builtins.cpp @@ -24,10 +24,8 @@ #include #include #include -#include #include -#include "source/diagnostic.h" #include "source/opcode.h" #include "source/spirv_target_env.h" #include "source/util/bitutils.h" diff --git a/source/val/validate_capability.cpp b/source/val/validate_capability.cpp index d70c8273c7..98dab4237f 100644 --- a/source/val/validate_capability.cpp +++ b/source/val/validate_capability.cpp @@ -16,9 +16,7 @@ #include #include -#include -#include "source/diagnostic.h" #include "source/opcode.h" #include "source/val/instruction.h" #include "source/val/validate.h" diff --git a/source/val/validate_cfg.cpp b/source/val/validate_cfg.cpp index a29b5fd074..7b3f7480f2 100644 --- a/source/val/validate_cfg.cpp +++ b/source/val/validate_cfg.cpp @@ -12,11 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include #include #include #include -#include #include #include #include @@ -28,7 +26,6 @@ #include "source/cfa.h" #include "source/opcode.h" #include "source/spirv_constant.h" -#include "source/spirv_target_env.h" #include "source/spirv_validator_options.h" #include "source/val/basic_block.h" #include "source/val/construct.h" diff --git a/source/val/validate_composites.cpp b/source/val/validate_composites.cpp index e777f1640e..2b83c63dd2 100644 --- a/source/val/validate_composites.cpp +++ b/source/val/validate_composites.cpp @@ -14,12 +14,10 @@ // Validates correctness of composite SPIR-V instructions. -#include "source/val/validate.h" - -#include "source/diagnostic.h" #include "source/opcode.h" #include "source/spirv_target_env.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { diff --git a/source/val/validate_conversion.cpp b/source/val/validate_conversion.cpp index c67b19685d..476c1fe8b1 100644 --- a/source/val/validate_conversion.cpp +++ b/source/val/validate_conversion.cpp @@ -14,7 +14,6 @@ // Validates correctness of conversion instructions. -#include "source/diagnostic.h" #include "source/opcode.h" #include "source/spirv_constant.h" #include "source/spirv_target_env.h" diff --git a/source/val/validate_debug.cpp b/source/val/validate_debug.cpp index c433c939f1..ef537ea027 100644 --- a/source/val/validate_debug.cpp +++ b/source/val/validate_debug.cpp @@ -12,11 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/val/validate.h" - -#include "source/opcode.h" #include "source/spirv_target_env.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp index f9c843521f..c1fca45f99 100644 --- a/source/val/validate_decorations.cpp +++ b/source/val/validate_decorations.cpp @@ -21,7 +21,6 @@ #include #include -#include "source/binary.h" #include "source/diagnostic.h" #include "source/opcode.h" #include "source/spirv_constant.h" @@ -48,13 +47,6 @@ struct PairHash { } }; -// A functor for hashing decoration types. -struct SpvDecorationHash { - std::size_t operator()(spv::Decoration dec) const { - return static_cast(dec); - } -}; - // Struct member layout attributes that are inherited through arrays. struct LayoutConstraints { explicit LayoutConstraints( diff --git a/source/val/validate_derivatives.cpp b/source/val/validate_derivatives.cpp index d87240f606..90cf6645c4 100644 --- a/source/val/validate_derivatives.cpp +++ b/source/val/validate_derivatives.cpp @@ -14,13 +14,11 @@ // Validates correctness of derivative SPIR-V instructions. -#include "source/val/validate.h" - #include -#include "source/diagnostic.h" #include "source/opcode.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { diff --git a/source/val/validate_execution_limitations.cpp b/source/val/validate_execution_limitations.cpp index 00c6603581..0221d7ef20 100644 --- a/source/val/validate_execution_limitations.cpp +++ b/source/val/validate_execution_limitations.cpp @@ -13,8 +13,6 @@ // limitations under the License. #include "source/val/validate.h" - -#include "source/val/function.h" #include "source/val/validation_state.h" namespace spvtools { diff --git a/source/val/validate_extensions.cpp b/source/val/validate_extensions.cpp index fa58e0f940..0ac62bfc8d 100644 --- a/source/val/validate_extensions.cpp +++ b/source/val/validate_extensions.cpp @@ -18,22 +18,18 @@ #include #include -#include "spirv/unified1/NonSemanticClspvReflection.h" - #include "NonSemanticShaderDebugInfo100.h" #include "OpenCLDebugInfo100.h" #include "source/common_debug_info.h" -#include "source/diagnostic.h" #include "source/enum_string_mapping.h" #include "source/extensions.h" #include "source/latest_version_glsl_std_450_header.h" #include "source/latest_version_opencl_std_header.h" -#include "source/opcode.h" #include "source/spirv_constant.h" -#include "source/spirv_target_env.h" #include "source/val/instruction.h" #include "source/val/validate.h" #include "source/val/validation_state.h" +#include "spirv/unified1/NonSemanticClspvReflection.h" namespace spvtools { namespace val { diff --git a/source/val/validate_id.cpp b/source/val/validate_id.cpp index 89a5ddd79d..92a4e8e33d 100644 --- a/source/val/validate_id.cpp +++ b/source/val/validate_id.cpp @@ -12,25 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "source/val/validate.h" - -#include - -#include -#include -#include -#include -#include #include -#include #include -#include "source/diagnostic.h" #include "source/instruction.h" #include "source/opcode.h" #include "source/operand.h" -#include "source/spirv_validator_options.h" #include "source/val/function.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" #include "spirv-tools/libspirv.h" diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 8f0e6c4d48..675c2cc56c 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -18,7 +18,6 @@ #include -#include "source/diagnostic.h" #include "source/opcode.h" #include "source/spirv_constant.h" #include "source/spirv_target_env.h" diff --git a/source/val/validate_instruction.cpp b/source/val/validate_instruction.cpp index 1b7847cacb..fde6e52e5b 100644 --- a/source/val/validate_instruction.cpp +++ b/source/val/validate_instruction.cpp @@ -14,26 +14,20 @@ // Performs validation on instructions that appear inside of a SPIR-V block. -#include #include -#include #include #include #include -#include "source/binary.h" -#include "source/diagnostic.h" #include "source/enum_set.h" #include "source/enum_string_mapping.h" #include "source/extensions.h" #include "source/opcode.h" #include "source/operand.h" #include "source/spirv_constant.h" -#include "source/spirv_definition.h" #include "source/spirv_target_env.h" #include "source/spirv_validator_options.h" #include "source/util/string_utils.h" -#include "source/val/function.h" #include "source/val/validate.h" #include "source/val/validation_state.h" diff --git a/source/val/validate_interfaces.cpp b/source/val/validate_interfaces.cpp index 00a5999bdf..35666984d0 100644 --- a/source/val/validate_interfaces.cpp +++ b/source/val/validate_interfaces.cpp @@ -15,7 +15,6 @@ #include #include -#include "source/diagnostic.h" #include "source/spirv_constant.h" #include "source/spirv_target_env.h" #include "source/val/function.h" diff --git a/source/val/validate_layout.cpp b/source/val/validate_layout.cpp index 238dd9b2fe..dbc1f1e5de 100644 --- a/source/val/validate_layout.cpp +++ b/source/val/validate_layout.cpp @@ -14,12 +14,9 @@ // Source code for logical layout validation as described in section 2.4 -#include - #include "DebugInfo.h" #include "NonSemanticShaderDebugInfo100.h" #include "OpenCLDebugInfo100.h" -#include "source/diagnostic.h" #include "source/opcode.h" #include "source/operand.h" #include "source/val/function.h" diff --git a/source/val/validate_literals.cpp b/source/val/validate_literals.cpp index 53aae0767a..15cc27a92f 100644 --- a/source/val/validate_literals.cpp +++ b/source/val/validate_literals.cpp @@ -14,13 +14,10 @@ // Validates literal numbers. -#include "source/val/validate.h" - #include -#include "source/diagnostic.h" -#include "source/opcode.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { diff --git a/source/val/validate_logicals.cpp b/source/val/validate_logicals.cpp index dd66ce948e..4479e43958 100644 --- a/source/val/validate_logicals.cpp +++ b/source/val/validate_logicals.cpp @@ -14,11 +14,9 @@ // Validates correctness of logical SPIR-V instructions. -#include "source/val/validate.h" - -#include "source/diagnostic.h" #include "source/opcode.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { diff --git a/source/val/validate_memory_semantics.cpp b/source/val/validate_memory_semantics.cpp index 748b238618..c4f22a611e 100644 --- a/source/val/validate_memory_semantics.cpp +++ b/source/val/validate_memory_semantics.cpp @@ -14,7 +14,6 @@ #include "source/val/validate_memory_semantics.h" -#include "source/diagnostic.h" #include "source/spirv_target_env.h" #include "source/util/bitutils.h" #include "source/val/instruction.h" diff --git a/source/val/validate_non_uniform.cpp b/source/val/validate_non_uniform.cpp index 5c5e9bd8b4..af04e76af0 100644 --- a/source/val/validate_non_uniform.cpp +++ b/source/val/validate_non_uniform.cpp @@ -14,14 +14,11 @@ // Validates correctness of barrier SPIR-V instructions. -#include "source/val/validate.h" - -#include "source/diagnostic.h" #include "source/opcode.h" #include "source/spirv_constant.h" #include "source/spirv_target_env.h" -#include "source/util/bitutils.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validate_scopes.h" #include "source/val/validation_state.h" diff --git a/source/val/validate_primitives.cpp b/source/val/validate_primitives.cpp index 5e598c3aea..6769090db8 100644 --- a/source/val/validate_primitives.cpp +++ b/source/val/validate_primitives.cpp @@ -14,13 +14,11 @@ // Validates correctness of primitive SPIR-V instructions. -#include "source/val/validate.h" - #include -#include "source/diagnostic.h" #include "source/opcode.h" #include "source/val/instruction.h" +#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { diff --git a/source/val/validate_scopes.cpp b/source/val/validate_scopes.cpp index fa93e5b694..40c49d1ff2 100644 --- a/source/val/validate_scopes.cpp +++ b/source/val/validate_scopes.cpp @@ -14,7 +14,6 @@ #include "source/val/validate_scopes.h" -#include "source/diagnostic.h" #include "source/spirv_target_env.h" #include "source/val/instruction.h" #include "source/val/validation_state.h" diff --git a/test/val/val_annotation_test.cpp b/test/val/val_annotation_test.cpp index bb30de0a90..9f85a30bbb 100644 --- a/test/val/val_annotation_test.cpp +++ b/test/val/val_annotation_test.cpp @@ -18,7 +18,6 @@ #include #include "gmock/gmock.h" -#include "test/test_fixture.h" #include "test/unit_spirv.h" #include "test/val/val_code_generator.h" #include "test/val/val_fixtures.h" diff --git a/test/val/val_cfg_test.cpp b/test/val/val_cfg_test.cpp index a43f72dbe4..3953057e1c 100644 --- a/test/val/val_cfg_test.cpp +++ b/test/val/val_cfg_test.cpp @@ -16,14 +16,12 @@ #include #include -#include #include #include #include #include #include "gmock/gmock.h" -#include "source/diagnostic.h" #include "source/spirv_target_env.h" #include "source/val/validate.h" #include "test/test_fixture.h" diff --git a/test/val/val_data_test.cpp b/test/val/val_data_test.cpp index 6a7f243f6b..349e5e9ef2 100644 --- a/test/val/val_data_test.cpp +++ b/test/val/val_data_test.cpp @@ -14,7 +14,6 @@ // Validation tests for Data Rules. -#include #include #include diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp index 4f90e6b03d..be16abae90 100644 --- a/test/val/val_decoration_test.cpp +++ b/test/val/val_decoration_test.cpp @@ -19,7 +19,6 @@ #include "gmock/gmock.h" #include "source/val/decoration.h" -#include "test/test_fixture.h" #include "test/unit_spirv.h" #include "test/val/val_code_generator.h" #include "test/val/val_fixtures.h" diff --git a/test/val/val_extension_spv_khr_bit_instructions_test.cpp b/test/val/val_extension_spv_khr_bit_instructions_test.cpp index 0e926716f7..d23b9b6fa3 100644 --- a/test/val/val_extension_spv_khr_bit_instructions_test.cpp +++ b/test/val/val_extension_spv_khr_bit_instructions_test.cpp @@ -18,10 +18,7 @@ #include #include "gmock/gmock.h" -#include "source/enum_string_mapping.h" -#include "source/extensions.h" #include "source/spirv_target_env.h" -#include "test/test_fixture.h" #include "test/unit_spirv.h" #include "test/val/val_fixtures.h" diff --git a/test/val/val_extension_spv_khr_expect_assume_test.cpp b/test/val/val_extension_spv_khr_expect_assume_test.cpp index 6ece15d18e..85a484aa7e 100644 --- a/test/val/val_extension_spv_khr_expect_assume_test.cpp +++ b/test/val/val_extension_spv_khr_expect_assume_test.cpp @@ -18,10 +18,7 @@ #include #include "gmock/gmock.h" -#include "source/enum_string_mapping.h" -#include "source/extensions.h" #include "source/spirv_target_env.h" -#include "test/test_fixture.h" #include "test/unit_spirv.h" #include "test/val/val_fixtures.h" diff --git a/test/val/val_extension_spv_khr_integer_dot_product_test.cpp b/test/val/val_extension_spv_khr_integer_dot_product_test.cpp index e0e6896c90..041751d944 100644 --- a/test/val/val_extension_spv_khr_integer_dot_product_test.cpp +++ b/test/val/val_extension_spv_khr_integer_dot_product_test.cpp @@ -14,15 +14,12 @@ // limitations under the License. #include -#include #include #include #include "gmock/gmock.h" -#include "source/enum_string_mapping.h" #include "source/extensions.h" #include "source/spirv_target_env.h" -#include "test/test_fixture.h" #include "test/unit_spirv.h" #include "test/val/val_fixtures.h" diff --git a/test/val/val_extension_spv_khr_linkonce_odr_test.cpp b/test/val/val_extension_spv_khr_linkonce_odr_test.cpp index ac15558bef..ed3fb8a1c2 100644 --- a/test/val/val_extension_spv_khr_linkonce_odr_test.cpp +++ b/test/val/val_extension_spv_khr_linkonce_odr_test.cpp @@ -18,10 +18,7 @@ #include #include "gmock/gmock.h" -#include "source/enum_string_mapping.h" -#include "source/extensions.h" #include "source/spirv_target_env.h" -#include "test/test_fixture.h" #include "test/unit_spirv.h" #include "test/val/val_fixtures.h" diff --git a/test/val/val_extension_spv_khr_subgroup_uniform_control_flow_test.cpp b/test/val/val_extension_spv_khr_subgroup_uniform_control_flow_test.cpp index f528cb9eef..80d57533da 100644 --- a/test/val/val_extension_spv_khr_subgroup_uniform_control_flow_test.cpp +++ b/test/val/val_extension_spv_khr_subgroup_uniform_control_flow_test.cpp @@ -18,10 +18,7 @@ #include #include "gmock/gmock.h" -#include "source/enum_string_mapping.h" -#include "source/extensions.h" #include "source/spirv_target_env.h" -#include "test/test_fixture.h" #include "test/unit_spirv.h" #include "test/val/val_fixtures.h" diff --git a/test/val/val_extension_spv_khr_terminate_invocation_test.cpp b/test/val/val_extension_spv_khr_terminate_invocation_test.cpp index 8d92414901..4d3e4d6af7 100644 --- a/test/val/val_extension_spv_khr_terminate_invocation_test.cpp +++ b/test/val/val_extension_spv_khr_terminate_invocation_test.cpp @@ -18,10 +18,7 @@ #include #include "gmock/gmock.h" -#include "source/enum_string_mapping.h" -#include "source/extensions.h" #include "source/spirv_target_env.h" -#include "test/test_fixture.h" #include "test/unit_spirv.h" #include "test/val/val_fixtures.h" diff --git a/test/val/val_extensions_test.cpp b/test/val/val_extensions_test.cpp index 491a80853a..0ab8c6e3c3 100644 --- a/test/val/val_extensions_test.cpp +++ b/test/val/val_extensions_test.cpp @@ -18,10 +18,8 @@ #include #include "gmock/gmock.h" -#include "source/enum_string_mapping.h" #include "source/extensions.h" #include "source/spirv_target_env.h" -#include "test/test_fixture.h" #include "test/unit_spirv.h" #include "test/val/val_fixtures.h" diff --git a/test/val/val_function_test.cpp b/test/val/val_function_test.cpp index e7d5cd7e04..24b52638a2 100644 --- a/test/val/val_function_test.cpp +++ b/test/val/val_function_test.cpp @@ -12,12 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include #include #include #include "gmock/gmock.h" -#include "test/test_fixture.h" #include "test/unit_spirv.h" #include "test/val/val_fixtures.h" diff --git a/test/val/val_layout_test.cpp b/test/val/val_layout_test.cpp index 8cca96f59e..e809abf812 100644 --- a/test/val/val_layout_test.cpp +++ b/test/val/val_layout_test.cpp @@ -14,9 +14,7 @@ // Validation tests for Logical Layout -#include #include -#include #include #include #include @@ -57,13 +55,6 @@ struct Range { bool inverse_; }; -template -spv_result_t InvalidSet(int order) { - for (spv_result_t val : {T(true)(order)...}) - if (val != SPV_SUCCESS) return val; - return SPV_SUCCESS; -} - // SPIRV source used to test the logical layout const std::vector& getInstructions() { // clang-format off diff --git a/test/val/val_limits_test.cpp b/test/val/val_limits_test.cpp index 364d514edc..66a6ff7f77 100644 --- a/test/val/val_limits_test.cpp +++ b/test/val/val_limits_test.cpp @@ -16,7 +16,6 @@ #include #include -#include #include "gmock/gmock.h" #include "test/unit_spirv.h" diff --git a/test/val/val_mesh_shading_test.cpp b/test/val/val_mesh_shading_test.cpp index ce6999dcb6..a7b96a4edc 100644 --- a/test/val/val_mesh_shading_test.cpp +++ b/test/val/val_mesh_shading_test.cpp @@ -14,7 +14,6 @@ // Tests instructions from SPV_EXT_mesh_shader -#include #include #include "gmock/gmock.h" diff --git a/test/val/val_modes_test.cpp b/test/val/val_modes_test.cpp index 689f0baa93..a50ac51646 100644 --- a/test/val/val_modes_test.cpp +++ b/test/val/val_modes_test.cpp @@ -18,7 +18,6 @@ #include "gmock/gmock.h" #include "source/spirv_target_env.h" -#include "test/test_fixture.h" #include "test/unit_spirv.h" #include "test/val/val_fixtures.h" diff --git a/test/val/val_state_test.cpp b/test/val/val_state_test.cpp index 4097a1feb8..51064abd41 100644 --- a/test/val/val_state_test.cpp +++ b/test/val/val_state_test.cpp @@ -18,14 +18,10 @@ #include #include "gtest/gtest.h" -#include "source/latest_version_spirv_header.h" - #include "source/enum_set.h" #include "source/extensions.h" +#include "source/latest_version_spirv_header.h" #include "source/spirv_validator_options.h" -#include "source/val/construct.h" -#include "source/val/function.h" -#include "source/val/validate.h" #include "source/val/validation_state.h" namespace spvtools { diff --git a/test/val/val_storage_test.cpp b/test/val/val_storage_test.cpp index 8693e8036e..6a3e4bdb26 100644 --- a/test/val/val_storage_test.cpp +++ b/test/val/val_storage_test.cpp @@ -28,8 +28,6 @@ namespace { using ::testing::HasSubstr; using ::testing::Values; using ValidateStorage = spvtest::ValidateBase; -using ValidateStorageClass = - spvtest::ValidateBase>; using ValidateStorageExecutionModel = spvtest::ValidateBase; TEST_F(ValidateStorage, FunctionStorageInsideFunction) { From a0fcd06f8fcc65c4c340e1a72492dc89017af8f5 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Tue, 28 Mar 2023 16:57:45 -0400 Subject: [PATCH 110/523] Add Vulkan memory model to allow lists (#5173) Fixes #5086 --- .../opt/local_access_chain_convert_pass.cpp | 84 +++++--------- source/opt/local_single_block_elim_pass.cpp | 107 +++++++++--------- source/opt/local_single_store_elim_pass.cpp | 101 ++++++++--------- test/opt/local_access_chain_convert_test.cpp | 50 ++++++++ test/opt/local_single_block_elim.cpp | 43 +++++++ test/opt/local_single_store_elim_test.cpp | 52 +++++++++ 6 files changed, 278 insertions(+), 159 deletions(-) diff --git a/source/opt/local_access_chain_convert_pass.cpp b/source/opt/local_access_chain_convert_pass.cpp index 4b472f3845..6ec0c2d387 100644 --- a/source/opt/local_access_chain_convert_pass.cpp +++ b/source/opt/local_access_chain_convert_pass.cpp @@ -397,60 +397,36 @@ Pass::Status LocalAccessChainConvertPass::Process() { void LocalAccessChainConvertPass::InitExtensions() { extensions_allowlist_.clear(); - extensions_allowlist_.insert({ - "SPV_AMD_shader_explicit_vertex_parameter", - "SPV_AMD_shader_trinary_minmax", - "SPV_AMD_gcn_shader", - "SPV_KHR_shader_ballot", - "SPV_AMD_shader_ballot", - "SPV_AMD_gpu_shader_half_float", - "SPV_KHR_shader_draw_parameters", - "SPV_KHR_subgroup_vote", - "SPV_KHR_8bit_storage", - "SPV_KHR_16bit_storage", - "SPV_KHR_device_group", - "SPV_KHR_multiview", - "SPV_NVX_multiview_per_view_attributes", - "SPV_NV_viewport_array2", - "SPV_NV_stereo_view_rendering", - "SPV_NV_sample_mask_override_coverage", - "SPV_NV_geometry_shader_passthrough", - "SPV_AMD_texture_gather_bias_lod", - "SPV_KHR_storage_buffer_storage_class", - // SPV_KHR_variable_pointers - // Currently do not support extended pointer expressions - "SPV_AMD_gpu_shader_int16", - "SPV_KHR_post_depth_coverage", - "SPV_KHR_shader_atomic_counter_ops", - "SPV_EXT_shader_stencil_export", - "SPV_EXT_shader_viewport_index_layer", - "SPV_AMD_shader_image_load_store_lod", - "SPV_AMD_shader_fragment_mask", - "SPV_EXT_fragment_fully_covered", - "SPV_AMD_gpu_shader_half_float_fetch", - "SPV_GOOGLE_decorate_string", - "SPV_GOOGLE_hlsl_functionality1", - "SPV_GOOGLE_user_type", - "SPV_NV_shader_subgroup_partitioned", - "SPV_EXT_demote_to_helper_invocation", - "SPV_EXT_descriptor_indexing", - "SPV_NV_fragment_shader_barycentric", - "SPV_NV_compute_shader_derivatives", - "SPV_NV_shader_image_footprint", - "SPV_NV_shading_rate", - "SPV_NV_mesh_shader", - "SPV_NV_ray_tracing", - "SPV_KHR_ray_tracing", - "SPV_KHR_ray_query", - "SPV_EXT_fragment_invocation_density", - "SPV_KHR_terminate_invocation", - "SPV_KHR_subgroup_uniform_control_flow", - "SPV_KHR_integer_dot_product", - "SPV_EXT_shader_image_int64", - "SPV_KHR_non_semantic_info", - "SPV_KHR_uniform_group_instructions", - "SPV_KHR_fragment_shader_barycentric", - }); + extensions_allowlist_.insert( + {"SPV_AMD_shader_explicit_vertex_parameter", + "SPV_AMD_shader_trinary_minmax", "SPV_AMD_gcn_shader", + "SPV_KHR_shader_ballot", "SPV_AMD_shader_ballot", + "SPV_AMD_gpu_shader_half_float", "SPV_KHR_shader_draw_parameters", + "SPV_KHR_subgroup_vote", "SPV_KHR_8bit_storage", "SPV_KHR_16bit_storage", + "SPV_KHR_device_group", "SPV_KHR_multiview", + "SPV_NVX_multiview_per_view_attributes", "SPV_NV_viewport_array2", + "SPV_NV_stereo_view_rendering", "SPV_NV_sample_mask_override_coverage", + "SPV_NV_geometry_shader_passthrough", "SPV_AMD_texture_gather_bias_lod", + "SPV_KHR_storage_buffer_storage_class", + // SPV_KHR_variable_pointers + // Currently do not support extended pointer expressions + "SPV_AMD_gpu_shader_int16", "SPV_KHR_post_depth_coverage", + "SPV_KHR_shader_atomic_counter_ops", "SPV_EXT_shader_stencil_export", + "SPV_EXT_shader_viewport_index_layer", + "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_fragment_mask", + "SPV_EXT_fragment_fully_covered", "SPV_AMD_gpu_shader_half_float_fetch", + "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", + "SPV_GOOGLE_user_type", "SPV_NV_shader_subgroup_partitioned", + "SPV_EXT_demote_to_helper_invocation", "SPV_EXT_descriptor_indexing", + "SPV_NV_fragment_shader_barycentric", + "SPV_NV_compute_shader_derivatives", "SPV_NV_shader_image_footprint", + "SPV_NV_shading_rate", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", + "SPV_KHR_ray_tracing", "SPV_KHR_ray_query", + "SPV_EXT_fragment_invocation_density", "SPV_KHR_terminate_invocation", + "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_integer_dot_product", + "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"}); } bool LocalAccessChainConvertPass::AnyIndexIsOutOfBounds( diff --git a/source/opt/local_single_block_elim_pass.cpp b/source/opt/local_single_block_elim_pass.cpp index ee79c25026..063d1b95c1 100644 --- a/source/opt/local_single_block_elim_pass.cpp +++ b/source/opt/local_single_block_elim_pass.cpp @@ -233,60 +233,59 @@ Pass::Status LocalSingleBlockLoadStoreElimPass::Process() { void LocalSingleBlockLoadStoreElimPass::InitExtensions() { extensions_allowlist_.clear(); - extensions_allowlist_.insert({ - "SPV_AMD_shader_explicit_vertex_parameter", - "SPV_AMD_shader_trinary_minmax", - "SPV_AMD_gcn_shader", - "SPV_KHR_shader_ballot", - "SPV_AMD_shader_ballot", - "SPV_AMD_gpu_shader_half_float", - "SPV_KHR_shader_draw_parameters", - "SPV_KHR_subgroup_vote", - "SPV_KHR_8bit_storage", - "SPV_KHR_16bit_storage", - "SPV_KHR_device_group", - "SPV_KHR_multiview", - "SPV_NVX_multiview_per_view_attributes", - "SPV_NV_viewport_array2", - "SPV_NV_stereo_view_rendering", - "SPV_NV_sample_mask_override_coverage", - "SPV_NV_geometry_shader_passthrough", - "SPV_AMD_texture_gather_bias_lod", - "SPV_KHR_storage_buffer_storage_class", - "SPV_KHR_variable_pointers", - "SPV_AMD_gpu_shader_int16", - "SPV_KHR_post_depth_coverage", - "SPV_KHR_shader_atomic_counter_ops", - "SPV_EXT_shader_stencil_export", - "SPV_EXT_shader_viewport_index_layer", - "SPV_AMD_shader_image_load_store_lod", - "SPV_AMD_shader_fragment_mask", - "SPV_EXT_fragment_fully_covered", - "SPV_AMD_gpu_shader_half_float_fetch", - "SPV_GOOGLE_decorate_string", - "SPV_GOOGLE_hlsl_functionality1", - "SPV_GOOGLE_user_type", - "SPV_NV_shader_subgroup_partitioned", - "SPV_EXT_demote_to_helper_invocation", - "SPV_EXT_descriptor_indexing", - "SPV_NV_fragment_shader_barycentric", - "SPV_NV_compute_shader_derivatives", - "SPV_NV_shader_image_footprint", - "SPV_NV_shading_rate", - "SPV_NV_mesh_shader", - "SPV_NV_ray_tracing", - "SPV_KHR_ray_tracing", - "SPV_KHR_ray_query", - "SPV_EXT_fragment_invocation_density", - "SPV_EXT_physical_storage_buffer", - "SPV_KHR_terminate_invocation", - "SPV_KHR_subgroup_uniform_control_flow", - "SPV_KHR_integer_dot_product", - "SPV_EXT_shader_image_int64", - "SPV_KHR_non_semantic_info", - "SPV_KHR_uniform_group_instructions", - "SPV_KHR_fragment_shader_barycentric", - }); + extensions_allowlist_.insert({"SPV_AMD_shader_explicit_vertex_parameter", + "SPV_AMD_shader_trinary_minmax", + "SPV_AMD_gcn_shader", + "SPV_KHR_shader_ballot", + "SPV_AMD_shader_ballot", + "SPV_AMD_gpu_shader_half_float", + "SPV_KHR_shader_draw_parameters", + "SPV_KHR_subgroup_vote", + "SPV_KHR_8bit_storage", + "SPV_KHR_16bit_storage", + "SPV_KHR_device_group", + "SPV_KHR_multiview", + "SPV_NVX_multiview_per_view_attributes", + "SPV_NV_viewport_array2", + "SPV_NV_stereo_view_rendering", + "SPV_NV_sample_mask_override_coverage", + "SPV_NV_geometry_shader_passthrough", + "SPV_AMD_texture_gather_bias_lod", + "SPV_KHR_storage_buffer_storage_class", + "SPV_KHR_variable_pointers", + "SPV_AMD_gpu_shader_int16", + "SPV_KHR_post_depth_coverage", + "SPV_KHR_shader_atomic_counter_ops", + "SPV_EXT_shader_stencil_export", + "SPV_EXT_shader_viewport_index_layer", + "SPV_AMD_shader_image_load_store_lod", + "SPV_AMD_shader_fragment_mask", + "SPV_EXT_fragment_fully_covered", + "SPV_AMD_gpu_shader_half_float_fetch", + "SPV_GOOGLE_decorate_string", + "SPV_GOOGLE_hlsl_functionality1", + "SPV_GOOGLE_user_type", + "SPV_NV_shader_subgroup_partitioned", + "SPV_EXT_demote_to_helper_invocation", + "SPV_EXT_descriptor_indexing", + "SPV_NV_fragment_shader_barycentric", + "SPV_NV_compute_shader_derivatives", + "SPV_NV_shader_image_footprint", + "SPV_NV_shading_rate", + "SPV_NV_mesh_shader", + "SPV_NV_ray_tracing", + "SPV_KHR_ray_tracing", + "SPV_KHR_ray_query", + "SPV_EXT_fragment_invocation_density", + "SPV_EXT_physical_storage_buffer", + "SPV_KHR_terminate_invocation", + "SPV_KHR_subgroup_uniform_control_flow", + "SPV_KHR_integer_dot_product", + "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"}); } } // namespace opt diff --git a/source/opt/local_single_store_elim_pass.cpp b/source/opt/local_single_store_elim_pass.cpp index 6491d384eb..a0de44c70f 100644 --- a/source/opt/local_single_store_elim_pass.cpp +++ b/source/opt/local_single_store_elim_pass.cpp @@ -86,57 +86,56 @@ Pass::Status LocalSingleStoreElimPass::Process() { } void LocalSingleStoreElimPass::InitExtensionAllowList() { - extensions_allowlist_.insert({ - "SPV_AMD_shader_explicit_vertex_parameter", - "SPV_AMD_shader_trinary_minmax", - "SPV_AMD_gcn_shader", - "SPV_KHR_shader_ballot", - "SPV_AMD_shader_ballot", - "SPV_AMD_gpu_shader_half_float", - "SPV_KHR_shader_draw_parameters", - "SPV_KHR_subgroup_vote", - "SPV_KHR_8bit_storage", - "SPV_KHR_16bit_storage", - "SPV_KHR_device_group", - "SPV_KHR_multiview", - "SPV_NVX_multiview_per_view_attributes", - "SPV_NV_viewport_array2", - "SPV_NV_stereo_view_rendering", - "SPV_NV_sample_mask_override_coverage", - "SPV_NV_geometry_shader_passthrough", - "SPV_AMD_texture_gather_bias_lod", - "SPV_KHR_storage_buffer_storage_class", - "SPV_KHR_variable_pointers", - "SPV_AMD_gpu_shader_int16", - "SPV_KHR_post_depth_coverage", - "SPV_KHR_shader_atomic_counter_ops", - "SPV_EXT_shader_stencil_export", - "SPV_EXT_shader_viewport_index_layer", - "SPV_AMD_shader_image_load_store_lod", - "SPV_AMD_shader_fragment_mask", - "SPV_EXT_fragment_fully_covered", - "SPV_AMD_gpu_shader_half_float_fetch", - "SPV_GOOGLE_decorate_string", - "SPV_GOOGLE_hlsl_functionality1", - "SPV_NV_shader_subgroup_partitioned", - "SPV_EXT_descriptor_indexing", - "SPV_NV_fragment_shader_barycentric", - "SPV_NV_compute_shader_derivatives", - "SPV_NV_shader_image_footprint", - "SPV_NV_shading_rate", - "SPV_NV_mesh_shader", - "SPV_NV_ray_tracing", - "SPV_KHR_ray_query", - "SPV_EXT_fragment_invocation_density", - "SPV_EXT_physical_storage_buffer", - "SPV_KHR_terminate_invocation", - "SPV_KHR_subgroup_uniform_control_flow", - "SPV_KHR_integer_dot_product", - "SPV_EXT_shader_image_int64", - "SPV_KHR_non_semantic_info", - "SPV_KHR_uniform_group_instructions", - "SPV_KHR_fragment_shader_barycentric", - }); + extensions_allowlist_.insert({"SPV_AMD_shader_explicit_vertex_parameter", + "SPV_AMD_shader_trinary_minmax", + "SPV_AMD_gcn_shader", + "SPV_KHR_shader_ballot", + "SPV_AMD_shader_ballot", + "SPV_AMD_gpu_shader_half_float", + "SPV_KHR_shader_draw_parameters", + "SPV_KHR_subgroup_vote", + "SPV_KHR_8bit_storage", + "SPV_KHR_16bit_storage", + "SPV_KHR_device_group", + "SPV_KHR_multiview", + "SPV_NVX_multiview_per_view_attributes", + "SPV_NV_viewport_array2", + "SPV_NV_stereo_view_rendering", + "SPV_NV_sample_mask_override_coverage", + "SPV_NV_geometry_shader_passthrough", + "SPV_AMD_texture_gather_bias_lod", + "SPV_KHR_storage_buffer_storage_class", + "SPV_KHR_variable_pointers", + "SPV_AMD_gpu_shader_int16", + "SPV_KHR_post_depth_coverage", + "SPV_KHR_shader_atomic_counter_ops", + "SPV_EXT_shader_stencil_export", + "SPV_EXT_shader_viewport_index_layer", + "SPV_AMD_shader_image_load_store_lod", + "SPV_AMD_shader_fragment_mask", + "SPV_EXT_fragment_fully_covered", + "SPV_AMD_gpu_shader_half_float_fetch", + "SPV_GOOGLE_decorate_string", + "SPV_GOOGLE_hlsl_functionality1", + "SPV_NV_shader_subgroup_partitioned", + "SPV_EXT_descriptor_indexing", + "SPV_NV_fragment_shader_barycentric", + "SPV_NV_compute_shader_derivatives", + "SPV_NV_shader_image_footprint", + "SPV_NV_shading_rate", + "SPV_NV_mesh_shader", + "SPV_NV_ray_tracing", + "SPV_KHR_ray_query", + "SPV_EXT_fragment_invocation_density", + "SPV_EXT_physical_storage_buffer", + "SPV_KHR_terminate_invocation", + "SPV_KHR_subgroup_uniform_control_flow", + "SPV_KHR_integer_dot_product", + "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"}); } bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) { std::vector users; diff --git a/test/opt/local_access_chain_convert_test.cpp b/test/opt/local_access_chain_convert_test.cpp index 07fb537c2e..b35f3a3f86 100644 --- a/test/opt/local_access_chain_convert_test.cpp +++ b/test/opt/local_access_chain_convert_test.cpp @@ -1348,6 +1348,56 @@ OpFunctionEnd true); } +TEST_F(LocalAccessChainConvertTest, VkMemoryModelTest) { + const std::string text = + R"( +; CHECK: OpCapability Shader +; CHECK: OpCapability VulkanMemoryModel +; CHECK: OpExtension "SPV_KHR_vulkan_memory_model" + OpCapability Shader + OpCapability VulkanMemoryModel + OpExtension "SPV_KHR_vulkan_memory_model" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical Vulkan + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" + OpSourceExtension "GL_GOOGLE_include_directive" + OpName %main "main" + OpName %a "a" + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%_ptr_Function_v4float = OpTypePointer Function %v4float + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 +%_ptr_Function_float = OpTypePointer Function %float + %float_1 = OpConstant %float 1 +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[a:%\w+]] = OpVariable +; Make sure the access chains were removed. +; CHECK: [[ld:%\w+]] = OpLoad {{%\w+}} [[a]] +; CHECK: [[ex:%\w+]] = OpCompositeExtract {{%\w+}} [[ld]] 0 +; CHECK: [[ld2:%\w+]] = OpLoad {{%\w+}} [[a]] +; CHECK: [[v:%\w+]] = OpCompositeInsert {{%\w+}} [[ex]] [[ld2]] 0 +; CHECK: OpStore [[a]] [[v]] + %main = OpFunction %void None %3 + %5 = OpLabel + %a = OpVariable %_ptr_Function_v4float Function + %13 = OpAccessChain %_ptr_Function_float %a %uint_0 + %14 = OpLoad %float %13 + %17 = OpAccessChain %_ptr_Function_float %a %uint_0 + OpStore %17 %14 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Assorted vector and matrix types diff --git a/test/opt/local_single_block_elim.cpp b/test/opt/local_single_block_elim.cpp index 28b8a07d1f..7d19c227f6 100644 --- a/test/opt/local_single_block_elim.cpp +++ b/test/opt/local_single_block_elim.cpp @@ -1502,6 +1502,49 @@ TEST_F(LocalSingleBlockLoadStoreElimTest, DebugValueTest) { SinglePassRunAndMatch(text, false); } +TEST_F(LocalSingleBlockLoadStoreElimTest, VkMemoryModelTest) { + const std::string text = + R"( +; CHECK: OpCapability Shader +; CHECK: OpCapability VulkanMemoryModel +; CHECK: OpExtension "SPV_KHR_vulkan_memory_model" + OpCapability Shader + OpCapability VulkanMemoryModel + OpExtension "SPV_KHR_vulkan_memory_model" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical Vulkan + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %bool = OpTypeBool + %false = OpConstantFalse %bool +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[a:%\w+]] = OpVariable +; CHECK-NEXT: [[b:%\w+]] = OpVariable +; CHECK: OpStore [[a]] [[v:%\w+]] +; CHECK-NOT: OpLoad %int [[a]] +; CHECK: OpStore [[b]] [[v]] + %main = OpFunction %void None %3 + %5 = OpLabel + %a = OpVariable %_ptr_Function_int Function + %b = OpVariable %_ptr_Function_int Function + OpStore %a %int_0 + %16 = OpLoad %int %a + OpStore %b %16 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Other target variable types diff --git a/test/opt/local_single_store_elim_test.cpp b/test/opt/local_single_store_elim_test.cpp index 8f43a11d41..ffe352ed11 100644 --- a/test/opt/local_single_store_elim_test.cpp +++ b/test/opt/local_single_store_elim_test.cpp @@ -1750,6 +1750,58 @@ TEST_F(LocalSingleStoreElimTest, DebugValuesForAllLocalsAndParams) { SinglePassRunAndMatch(text, false); } +TEST_F(LocalSingleStoreElimTest, VkMemoryModelTest) { + const std::string text = + R"( +; CHECK: OpCapability Shader +; CHECK: OpCapability VulkanMemoryModel +; CHECK: OpExtension "SPV_KHR_vulkan_memory_model" + OpCapability Shader + OpCapability VulkanMemoryModel + OpExtension "SPV_KHR_vulkan_memory_model" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical Vulkan + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpSource GLSL 450 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %bool = OpTypeBool + %false = OpConstantFalse %bool +; CHECK: OpFunction +; CHECK-NEXT: OpLabel +; CHECK-NEXT: [[a:%\w+]] = OpVariable +; CHECK-NEXT: [[b:%\w+]] = OpVariable +; CHECK: OpStore [[a]] [[v:%\w+]] +; CHECK: OpStore [[b]] +; Make sure the load was removed. +; CHECK: OpLabel +; CHECK-NOT: OpLoad %int [[a]] +; CHECK: OpStore [[b]] [[v]] + %main = OpFunction %void None %3 + %5 = OpLabel + %a = OpVariable %_ptr_Function_int Function + %b = OpVariable %_ptr_Function_int Function + OpStore %a %int_0 + OpStore %b %int_1 + OpSelectionMerge %15 None + OpBranchConditional %false %14 %15 + %14 = OpLabel + %16 = OpLoad %int %a + OpStore %b %16 + OpBranch %15 + %15 = OpLabel + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Other types From f5ff7ae4a184dc406ca8292614d19af632d48a3f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 29 Mar 2023 13:07:20 -0400 Subject: [PATCH 111/523] Roll external/googletest/ 88af49efa..ca0d46e95 (4 commits) (#5180) https://github.com/google/googletest/compare/88af49efa72a...ca0d46e95dd1 $ git log 88af49efa..ca0d46e95 --date=short --no-merges --format='%ad %ae %s' 2023-03-28 dmauro Fix redundant redeclaration warning 2023-03-28 dmauro Remove the Win64 arch from the CMake Generator since this can't be used with MSVC 2022 2023-03-23 65027571+gonzalobg Add doc comment 2022-12-28 gonzalob Fix warnings with nvc++ as the compiler 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 cad1641a9f..a5629c7d76 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': '88af49efa72a06d56910d69ecfd87e3b330e5778', + 'googletest_revision': 'ca0d46e95dd13e331bb9419b0b0e3af758e8644c', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From 7ab0a2781af40d58fb0c56bc9ac0bcbc457a420f Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 29 Mar 2023 15:48:15 -0400 Subject: [PATCH 112/523] Remove non-ascii char from comments. (#5182) Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/4851 --- source/val/validate_image.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 675c2cc56c..ebcd8c3b79 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -1995,11 +1995,11 @@ spv_result_t ValidateImageQueryLod(ValidationState_t& _, << " components, but given only " << actual_coord_size; } - // The operad is a sampled image. + // The operand is a sampled image. // The sampled image type is already checked to be parameterized by an image // type with Sampled=0 or Sampled=1. Vulkan bans Sampled=0, and so we have // Sampled=1. So the validator already enforces Vulkan VUID 4659: - // OpImageQuerySizeLod must only consume an “Image” operand whose type has + // OpImageQuerySizeLod must only consume an "Image" operand whose type has // its "Sampled" operand set to 1 return SPV_SUCCESS; } From 6b72fe20c5d261f9698a82742ae08d9930375981 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 29 Mar 2023 15:52:47 -0400 Subject: [PATCH 113/523] Add missing header guard (#5181) Fixes #5018 --- source/opt/remove_unused_interface_variables_pass.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/opt/remove_unused_interface_variables_pass.h b/source/opt/remove_unused_interface_variables_pass.h index 7f11187cac..a4cb1085ab 100644 --- a/source/opt/remove_unused_interface_variables_pass.h +++ b/source/opt/remove_unused_interface_variables_pass.h @@ -12,6 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +#ifndef SOURCE_OPT_REMOVE_UNUSED_INTERFACE_VARIABLES_PASS_H_ +#define SOURCE_OPT_REMOVE_UNUSED_INTERFACE_VARIABLES_PASS_H_ + #include "source/opt/pass.h" namespace spvtools { namespace opt { @@ -23,4 +26,6 @@ class RemoveUnusedInterfaceVariablesPass : public Pass { Status Process() override; }; } // namespace opt -} // namespace spvtools \ No newline at end of file +} // namespace spvtools + +#endif // SOURCE_OPT_REMOVE_UNUSED_INTERFACE_VARIABLES_PASS_H_ \ No newline at end of file From a2db3fb17b4c2c27381a20b02d192f9737ce09fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 3 Apr 2023 15:27:45 +0200 Subject: [PATCH 114/523] kokoro: always chown files (#5186) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the build fails, the artifacts must still be chowned so the CI can pick them up. If they are not, the CI tooling will fail and go into 'aborted' state, which blocks the logs. Signed-off-by: Nathan Gauër --- kokoro/scripts/linux/build.sh | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/kokoro/scripts/linux/build.sh b/kokoro/scripts/linux/build.sh index 85d4b61abb..688ba7933d 100644 --- a/kokoro/scripts/linux/build.sh +++ b/kokoro/scripts/linux/build.sh @@ -26,6 +26,18 @@ COMPILER=$2 TOOL=$3 BUILD_SHA=${KOKORO_GITHUB_COMMIT:-$KOKORO_GITHUB_PULL_REQUEST_COMMIT} +# chown the given directory to the current user, if it exists. +# Docker creates files with the root user - this can upset the Kokoro artifact copier. +function chown_dir() { + dir=$1 + if [[ -d "$dir" ]]; then + sudo chown -R "$(id -u):$(id -g)" "$dir" + fi +} + +set +e +# Allow build failures + # "--privileged" is required to run ptrace in the asan builds. docker run --rm -i \ --privileged \ @@ -41,16 +53,11 @@ docker run --rm -i \ --env BUILD_SHA="${BUILD_SHA}" \ --entrypoint "${SCRIPT_DIR}/build-docker.sh" \ "gcr.io/shaderc-build/radial-build:latest" +RESULT=$? - -# chown the given directory to the current user, if it exists. -# Docker creates files with the root user - this can upset the Kokoro artifact copier. -function chown_dir() { - dir=$1 - if [[ -d "$dir" ]]; then - sudo chown -R "$(id -u):$(id -g)" "$dir" - fi -} - +# This is important. If the permissions are not fixed, kokoro will fail +# to pull build artifacts, and put the build in tool-failure state, which +# blocks the logs. chown_dir "${ROOT_DIR}/build" chown_dir "${ROOT_DIR}/external" +exit $RESULT From ac335c76347440e5df3d00b4e6a1a1629338d3a3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 3 Apr 2023 12:20:17 -0400 Subject: [PATCH 115/523] roll deps (#5185) * Roll external/googletest/ ca0d46e95..b5fd99bbd (2 commits) https://github.com/google/googletest/compare/ca0d46e95dd1...b5fd99bbd55e $ git log ca0d46e95..b5fd99bbd --date=short --no-merges --format='%ad %ae %s' 2023-03-30 jacobsa gtest.cc: run tests within a test suite in a deterministic order. 2023-03-29 absl-team Update naming to "GoogleTest" in the GoogleTest Primer. Created with: roll-dep external/googletest * Roll external/spirv-headers/ 90547c54e..29ba24931 (1 commit) https://github.com/KhronosGroup/SPIRV-Headers/compare/90547c54e24e...29ba2493125e $ git log 90547c54e..29ba24931 --date=short --no-merges --format='%ad %ae %s' 2023-03-23 duncan.brawley Reserve SPIR-V blocks for Codeplay 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 a5629c7d76..f5764c3891 100644 --- a/DEPS +++ b/DEPS @@ -5,13 +5,13 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': 'ca0d46e95dd13e331bb9419b0b0e3af758e8644c', + 'googletest_revision': 'b5fd99bbd55ebe1a3488b8ea3717fba089293457', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', 're2_revision': '11073deb73b3d01018308863c0bcdfd0d51d3e70', - 'spirv_headers_revision': '90547c54e24e01aae41a68124e7a304d0ec11dd0', + 'spirv_headers_revision': '29ba2493125effc581532518add689613cebfec7', } deps = { From 97a55196d276c32e820c11bbc66efd0f0ac5279d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 4 Apr 2023 11:48:30 -0400 Subject: [PATCH 116/523] Roll external/googletest/ b5fd99bbd..7ee260c54 (1 commit) (#5187) https://github.com/google/googletest/compare/b5fd99bbd55e...7ee260c54921 $ git log b5fd99bbd..7ee260c54 --date=short --no-merges --format='%ad %ae %s' 2023-04-03 absl-team Rolled back due to breaking existing tests. 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 f5764c3891..2b7e7ec9ed 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': 'b5fd99bbd55ebe1a3488b8ea3717fba089293457', + 'googletest_revision': '7ee260c54921571b18b15049304426fe151c1265', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From dd03c1fca45df87755b75526438dfd2f5b374865 Mon Sep 17 00:00:00 2001 From: LDeakin Date: Thu, 6 Apr 2023 01:48:14 +1000 Subject: [PATCH 117/523] Fix LICMPass (#5087) Do not move loads out of the loop unless the memory is readonly. Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/5075 --- source/opt/licm_pass.cpp | 2 +- source/opt/loop_descriptor.cpp | 23 +-- source/opt/loop_descriptor.h | 8 +- test/opt/loop_optimizations/CMakeLists.txt | 1 + .../hoist_access_chains.cpp | 157 ++++++++++++++++++ 5 files changed, 172 insertions(+), 19 deletions(-) create mode 100644 test/opt/loop_optimizations/hoist_access_chains.cpp diff --git a/source/opt/licm_pass.cpp b/source/opt/licm_pass.cpp index c485115fed..f2a6e4df56 100644 --- a/source/opt/licm_pass.cpp +++ b/source/opt/licm_pass.cpp @@ -84,7 +84,7 @@ Pass::Status LICMPass::AnalyseAndHoistFromBB( bool modified = false; std::function hoist_inst = [this, &loop, &modified](Instruction* inst) { - if (loop->ShouldHoistInstruction(this->context(), inst)) { + if (loop->ShouldHoistInstruction(*inst)) { if (!HoistInstruction(loop, inst)) { return false; } diff --git a/source/opt/loop_descriptor.cpp b/source/opt/loop_descriptor.cpp index 2a9f905945..cbfc2e7599 100644 --- a/source/opt/loop_descriptor.cpp +++ b/source/opt/loop_descriptor.cpp @@ -450,25 +450,20 @@ bool Loop::IsLCSSA() const { return true; } -bool Loop::ShouldHoistInstruction(IRContext* context, Instruction* inst) { - return AreAllOperandsOutsideLoop(context, inst) && - inst->IsOpcodeCodeMotionSafe(); +bool Loop::ShouldHoistInstruction(const Instruction& inst) const { + return inst.IsOpcodeCodeMotionSafe() && AreAllOperandsOutsideLoop(inst) && + (!inst.IsLoad() || inst.IsReadOnlyLoad()); } -bool Loop::AreAllOperandsOutsideLoop(IRContext* context, Instruction* inst) { - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - bool all_outside_loop = true; +bool Loop::AreAllOperandsOutsideLoop(const Instruction& inst) const { + analysis::DefUseManager* def_use_mgr = GetContext()->get_def_use_mgr(); - const std::function operand_outside_loop = - [this, &def_use_mgr, &all_outside_loop](uint32_t* id) { - if (this->IsInsideLoop(def_use_mgr->GetDef(*id))) { - all_outside_loop = false; - return; - } + const std::function operand_outside_loop = + [this, &def_use_mgr](const uint32_t* id) { + return !this->IsInsideLoop(def_use_mgr->GetDef(*id)); }; - inst->ForEachInId(operand_outside_loop); - return all_outside_loop; + return inst.WhileEachInId(operand_outside_loop); } void Loop::ComputeLoopStructuredOrder( diff --git a/source/opt/loop_descriptor.h b/source/opt/loop_descriptor.h index 35256bc3fe..d451496e77 100644 --- a/source/opt/loop_descriptor.h +++ b/source/opt/loop_descriptor.h @@ -296,12 +296,12 @@ class Loop { // as a nested child loop. inline void SetParent(Loop* parent) { parent_ = parent; } - // Returns true is the instruction is invariant and safe to move wrt loop - bool ShouldHoistInstruction(IRContext* context, Instruction* inst); + // Returns true is the instruction is invariant and safe to move wrt loop. + bool ShouldHoistInstruction(const Instruction& inst) const; // Returns true if all operands of inst are in basic blocks not contained in - // loop - bool AreAllOperandsOutsideLoop(IRContext* context, Instruction* inst); + // loop. + bool AreAllOperandsOutsideLoop(const Instruction& inst) const; // Extract the initial value from the |induction| variable and store it in // |value|. If the function couldn't find the initial value of |induction| diff --git a/test/opt/loop_optimizations/CMakeLists.txt b/test/opt/loop_optimizations/CMakeLists.txt index e3620787db..6e20f72fe1 100644 --- a/test/opt/loop_optimizations/CMakeLists.txt +++ b/test/opt/loop_optimizations/CMakeLists.txt @@ -21,6 +21,7 @@ add_spvtools_unittest(TARGET opt_loops fusion_illegal.cpp fusion_legal.cpp fusion_pass.cpp + hoist_access_chains.cpp hoist_all_loop_types.cpp hoist_double_nested_loops.cpp hoist_from_independent_loops.cpp diff --git a/test/opt/loop_optimizations/hoist_access_chains.cpp b/test/opt/loop_optimizations/hoist_access_chains.cpp new file mode 100644 index 0000000000..0c688b3176 --- /dev/null +++ b/test/opt/loop_optimizations/hoist_access_chains.cpp @@ -0,0 +1,157 @@ +// Copyright (c) 2023 The Khronos Group 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 + +#include "gmock/gmock.h" +#include "source/opt/licm_pass.h" +#include "test/opt/pass_fixture.h" + +namespace spvtools { +namespace opt { +namespace { + +using PassClassTest = PassTest<::testing::Test>; + +/* + Tests for the LICM pass to check it handles access chains correctly + + Generated from the following GLSL fragment shader +--eliminate-local-multi-store has also been run on the spv binary +#version 460 +void main() { + for (uint i = 0; i < 123u; ++i) { + vec2 do_not_hoist_store = vec2(0.0f); + float do_not_hoist_access_chain_load = do_not_hoist_store.x; + } +} +*/ + +TEST_F(PassClassTest, HoistAccessChains) { + const std::string before_hoist = R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 460 +OpName %main "main" +OpName %i "i" +OpName %do_not_hoist_store "do_not_hoist_store" +OpName %do_not_hoist_access_chain_load "do_not_hoist_access_chain_load" +%void = OpTypeVoid +%7 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%_ptr_Function_uint = OpTypePointer Function %uint +%uint_0 = OpConstant %uint 0 +%uint_123 = OpConstant %uint 123 +%bool = OpTypeBool +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%_ptr_Function_v2float = OpTypePointer Function %v2float +%float_0 = OpConstant %float 0 +%17 = OpConstantComposite %v2float %float_0 %float_0 +%_ptr_Function_float = OpTypePointer Function %float +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%main = OpFunction %void None %7 +%21 = OpLabel +%i = OpVariable %_ptr_Function_uint Function +%do_not_hoist_store = OpVariable %_ptr_Function_v2float Function +%do_not_hoist_access_chain_load = OpVariable %_ptr_Function_float Function +OpStore %i %uint_0 +OpBranch %22 +%22 = OpLabel +OpLoopMerge %23 %24 None +OpBranch %25 +%25 = OpLabel +%26 = OpLoad %uint %i +%27 = OpULessThan %bool %26 %uint_123 +OpBranchConditional %27 %28 %23 +%28 = OpLabel +OpStore %do_not_hoist_store %17 +%29 = OpAccessChain %_ptr_Function_float %do_not_hoist_store %uint_0 +%30 = OpLoad %float %29 +OpStore %do_not_hoist_access_chain_load %30 +OpBranch %24 +%24 = OpLabel +%31 = OpLoad %uint %i +%32 = OpIAdd %uint %31 %int_1 +OpStore %i %32 +OpBranch %22 +%23 = OpLabel +OpReturn +OpFunctionEnd +)"; + + const std::string after_hoist = R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpSource GLSL 460 +OpName %main "main" +OpName %i "i" +OpName %do_not_hoist_store "do_not_hoist_store" +OpName %do_not_hoist_access_chain_load "do_not_hoist_access_chain_load" +%void = OpTypeVoid +%7 = OpTypeFunction %void +%uint = OpTypeInt 32 0 +%_ptr_Function_uint = OpTypePointer Function %uint +%uint_0 = OpConstant %uint 0 +%uint_123 = OpConstant %uint 123 +%bool = OpTypeBool +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%_ptr_Function_v2float = OpTypePointer Function %v2float +%float_0 = OpConstant %float 0 +%17 = OpConstantComposite %v2float %float_0 %float_0 +%_ptr_Function_float = OpTypePointer Function %float +%int = OpTypeInt 32 1 +%int_1 = OpConstant %int 1 +%main = OpFunction %void None %7 +%21 = OpLabel +%i = OpVariable %_ptr_Function_uint Function +%do_not_hoist_store = OpVariable %_ptr_Function_v2float Function +%do_not_hoist_access_chain_load = OpVariable %_ptr_Function_float Function +OpStore %i %uint_0 +%29 = OpAccessChain %_ptr_Function_float %do_not_hoist_store %uint_0 +OpBranch %22 +%22 = OpLabel +OpLoopMerge %23 %24 None +OpBranch %25 +%25 = OpLabel +%26 = OpLoad %uint %i +%27 = OpULessThan %bool %26 %uint_123 +OpBranchConditional %27 %28 %23 +%28 = OpLabel +OpStore %do_not_hoist_store %17 +%30 = OpLoad %float %29 +OpStore %do_not_hoist_access_chain_load %30 +OpBranch %24 +%24 = OpLabel +%31 = OpLoad %uint %i +%32 = OpIAdd %uint %31 %int_1 +OpStore %i %32 +OpBranch %22 +%23 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(before_hoist, after_hoist, true); +} + +} // namespace +} // namespace opt +} // namespace spvtools From 13ea01b3ea47a6a4dc6623cdd215ba696db09e98 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 6 Apr 2023 10:58:00 -0400 Subject: [PATCH 118/523] Roll external/googletest/ 7ee260c54..057b4e904 (1 commit) (#5190) https://github.com/google/googletest/compare/7ee260c54921...057b4e904fd7 $ git log 7ee260c54..057b4e904 --date=short --no-merges --format='%ad %ae %s' 2023-04-05 absl-team gtest.cc: run tests within a test suite in a deterministic order. 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 2b7e7ec9ed..7935ba72da 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': '7ee260c54921571b18b15049304426fe151c1265', + 'googletest_revision': '057b4e904fd754135dc19ff557c14036fd316425', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From 048faf2e530ff398d4e0700867a4734dcfe9c983 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 6 Apr 2023 11:22:28 -0400 Subject: [PATCH 119/523] Remove use of deprecated std::aligned_storage (#5183) * Remove use of deprecated std::aligned_storage Fixes #4806. --- source/util/small_vector.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/source/util/small_vector.h b/source/util/small_vector.h index 648a34824f..1351475bd8 100644 --- a/source/util/small_vector.h +++ b/source/util/small_vector.h @@ -15,7 +15,9 @@ #ifndef SOURCE_UTIL_SMALL_VECTOR_H_ #define SOURCE_UTIL_SMALL_VECTOR_H_ +#include #include +#include #include #include #include @@ -461,14 +463,18 @@ class SmallVector { // The number of elements in |small_data_| that have been constructed. size_t size_; - // The pointed used to access the array of elements when the number of - // elements is small. - T* small_data_; + // A type with the same alignment and size as T, but will is POD. + struct alignas(T) PodType { + std::array data; + }; // The actual data used to store the array elements. It must never be used // directly, but must only be accessed through |small_data_|. - typename std::aligned_storage::value>::type - buffer[small_size]; + PodType buffer[small_size]; + + // The pointed used to access the array of elements when the number of + // elements is small. + T* small_data_; // A pointer to a vector that is used to store the elements of the vector when // this size exceeds |small_size|. If |large_data_| is nullptr, then the data From 31c546e316592b6e394a8fc55f1e9f91a0df9ac2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 12 Apr 2023 11:05:49 -0400 Subject: [PATCH 120/523] Roll external/googletest/ 057b4e904..8fa9461cc (2 commits) (#5192) https://github.com/google/googletest/compare/057b4e904fd7...8fa9461cc28e $ git log 057b4e904..8fa9461cc --date=short --no-merges --format='%ad %ae %s' 2023-04-11 absl-team Fix FunctionMocker compilation slowdown in 9d21db9e0a60a1ea61ec19331c9bc0dd33e907b1 2023-04-11 absl-team Support --gtest_stream_result_to on macOS 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 7935ba72da..413f0edca3 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': '057b4e904fd754135dc19ff557c14036fd316425', + 'googletest_revision': '8fa9461cc28e053d66f17132808d287ae51575e2', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v3.13.0.1', From 9a4e7a1eb5dd5b2faa8489c74970e93cd8e8418b Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 12 Apr 2023 13:37:07 -0400 Subject: [PATCH 121/523] Update protobuf to v21.12 (#5189) * Update protobuf to v21.12 We need to update because the current version was not buliding with gcc 12.2. I could not move upda to v22.x because there was an odd use of some defines that were causing failures. * Disable clang warnings for protobuf headers --- DEPS | 2 +- external/CMakeLists.txt | 2 +- source/fuzz/protobufs/spirvfuzz_protobufs.h | 4 ++++ utils/check_symbol_exports.py | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index 413f0edca3..4fbf1a2b3e 100644 --- a/DEPS +++ b/DEPS @@ -8,7 +8,7 @@ vars = { 'googletest_revision': '8fa9461cc28e053d66f17132808d287ae51575e2', # Use protobufs before they gained the dependency on abseil - 'protobuf_revision': 'v3.13.0.1', + 'protobuf_revision': 'v21.12', 're2_revision': '11073deb73b3d01018308863c0bcdfd0d51d3e70', 'spirv_headers_revision': '29ba2493125effc581532518add689613cebfec7', diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 81011f1a20..6ee37d9ea5 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -154,7 +154,7 @@ if(SPIRV_BUILD_FUZZER) if(NOT TARGET protobuf::libprotobuf OR NOT TARGET protobuf::protoc) - set(SPIRV_TOOLS_PROTOBUF_DIR ${CMAKE_CURRENT_SOURCE_DIR}/protobuf/cmake) + set(SPIRV_TOOLS_PROTOBUF_DIR ${CMAKE_CURRENT_SOURCE_DIR}/protobuf) if (NOT IS_DIRECTORY ${SPIRV_TOOLS_PROTOBUF_DIR}) message( FATAL_ERROR diff --git a/source/fuzz/protobufs/spirvfuzz_protobufs.h b/source/fuzz/protobufs/spirvfuzz_protobufs.h index 46c218814e..d798361efd 100644 --- a/source/fuzz/protobufs/spirvfuzz_protobufs.h +++ b/source/fuzz/protobufs/spirvfuzz_protobufs.h @@ -21,6 +21,8 @@ // of these header files without having to compromise on freedom from warnings // in the rest of the project. +#define GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE 1 + #if defined(__clang__) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunknown-warning-option" // Must come first @@ -28,6 +30,8 @@ #pragma clang diagnostic ignored "-Wshadow" #pragma clang diagnostic ignored "-Wsuggest-destructor-override" #pragma clang diagnostic ignored "-Wunused-parameter" +#pragma clang diagnostic ignored "-Wc++98-compat-extra-semi" +#pragma clang diagnostic ignored "-Wshorten-64-to-32" #elif defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wconversion" diff --git a/utils/check_symbol_exports.py b/utils/check_symbol_exports.py index 7795d72bc9..e1ca0b7888 100755 --- a/utils/check_symbol_exports.py +++ b/utils/check_symbol_exports.py @@ -67,7 +67,7 @@ def check_library(library): # by the protobuf compiler: # - AddDescriptors_spvtoolsfuzz_2eproto() # - InitDefaults_spvtoolsfuzz_2eproto() - symbol_allowlist_pattern = re.compile(r'_Z[0-9]+(InitDefaults|AddDescriptors)_spvtoolsfuzz_2eprotov') + symbol_allowlist_pattern = re.compile(r'_Z[0-9]+.*spvtoolsfuzz_2eproto.*') symbol_is_new_or_delete = re.compile(r'^(_Zna|_Znw|_Zdl|_Zda)') # Compilaion for Arm has various thunks for constructors, destructors, vtables. From f449fb4ad9d7e1424a85ff4c09285385ec090607 Mon Sep 17 00:00:00 2001 From: Corentin Wallez Date: Thu, 13 Apr 2023 17:10:02 +0200 Subject: [PATCH 122/523] Add default case for spv::Dim for TileImageEXT (#5194) Without this the switch statement must be updated at the same time as the SPIR-V headers, which makes rolls impossible. --- source/val/validate_image.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index ebcd8c3b79..0e5142248a 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -218,6 +218,7 @@ uint32_t GetPlaneCoordSize(const ImageTypeInfo& info) { plane_size = 3; break; case spv::Dim::Max: + default: assert(0); break; } From 1877a7f9094d0b8e4f9f4e90ab175b13cedb733d Mon Sep 17 00:00:00 2001 From: James Price Date: Thu, 13 Apr 2023 12:50:16 -0400 Subject: [PATCH 123/523] Fix vector OpConstantComposite type validation (#5191) The constituent types much fully match, not just the opcode. --- source/val/validate_constants.cpp | 2 +- test/val/val_constants_test.cpp | 16 ++++++++++++++++ ...xtension_spv_khr_integer_dot_product_test.cpp | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/source/val/validate_constants.cpp b/source/val/validate_constants.cpp index a8ee5a6b1e..006e504c0c 100644 --- a/source/val/validate_constants.cpp +++ b/source/val/validate_constants.cpp @@ -76,7 +76,7 @@ spv_result_t ValidateConstantComposite(ValidationState_t& _, } const auto constituent_result_type = _.FindDef(constituent->type_id()); if (!constituent_result_type || - component_type->opcode() != constituent_result_type->opcode()) { + component_type->id() != constituent_result_type->id()) { return _.diag(SPV_ERROR_INVALID_ID, inst) << opcode_name << " Constituent " << _.getIdName(constituent_id) diff --git a/test/val/val_constants_test.cpp b/test/val/val_constants_test.cpp index 301539d98f..47278777dc 100644 --- a/test/val/val_constants_test.cpp +++ b/test/val/val_constants_test.cpp @@ -478,6 +478,22 @@ OpName %ptr "ptr" "a null value")); } +TEST_F(ValidateConstant, VectorMismatchedConstituents) { + std::string spirv = kShaderPreamble kBasicTypes R"( +%int = OpTypeInt 32 1 +%int_0 = OpConstantNull %int +%const_vector = OpConstantComposite %uint2 %uint_0 %int_0 +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpConstantComposite Constituent '13[%13]'s type " + "does not match Result Type '3[%v2uint]'s vector element type")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/test/val/val_extension_spv_khr_integer_dot_product_test.cpp b/test/val/val_extension_spv_khr_integer_dot_product_test.cpp index 041751d944..5b3a309612 100644 --- a/test/val/val_extension_spv_khr_integer_dot_product_test.cpp +++ b/test/val/val_extension_spv_khr_integer_dot_product_test.cpp @@ -128,7 +128,7 @@ std::string AssemblyForCase(const Case& c) { %char_0 = OpConstant %char 0 %char_1 = OpConstant %char 1 - %v4uchar_0 = OpConstantComposite %v4uchar %uchar_0 %uint_0 %uchar_0 %uchar_0 + %v4uchar_0 = OpConstantComposite %v4uchar %uchar_0 %uchar_0 %uchar_0 %uchar_0 %v4uchar_1 = OpConstantComposite %v4uchar %uchar_1 %uchar_1 %uchar_1 %uchar_1 %v4char_0 = OpConstantComposite %v4char %char_0 %char_0 %char_0 %char_0 %v4char_1 = OpConstantComposite %v4char %char_1 %char_1 %char_1 %char_1 From 6f276e05ccab210584996bc40a0bef82b91f4f40 Mon Sep 17 00:00:00 2001 From: janharaldfredriksen-arm Date: Thu, 13 Apr 2023 22:58:00 +0200 Subject: [PATCH 124/523] Add support for SPV_EXT_shader_tile_image (#5188) * Update DEPS file to pull in header changes for SPV_EXT_shader_tile_image --- DEPS | 2 +- source/val/validate_annotation.cpp | 6 +- source/val/validate_function.cpp | 1 + source/val/validate_image.cpp | 63 +++- source/val/validate_mode_setting.cpp | 3 + source/val/validation_state.cpp | 1 + test/text_to_binary.extension_test.cpp | 49 +++ test/text_to_binary.type_declaration_test.cpp | 2 + test/val/val_image_test.cpp | 284 +++++++++++++++++- test/val/val_modes_test.cpp | 26 ++ 10 files changed, 430 insertions(+), 7 deletions(-) diff --git a/DEPS b/DEPS index 4fbf1a2b3e..42c4fdfb7b 100644 --- a/DEPS +++ b/DEPS @@ -11,7 +11,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': '11073deb73b3d01018308863c0bcdfd0d51d3e70', - 'spirv_headers_revision': '29ba2493125effc581532518add689613cebfec7', + 'spirv_headers_revision': 'cfbe4feef20c3c0628712c2792624f0221e378ac', } deps = { diff --git a/source/val/validate_annotation.cpp b/source/val/validate_annotation.cpp index bef753d9c8..73d0285a11 100644 --- a/source/val/validate_annotation.cpp +++ b/source/val/validate_annotation.cpp @@ -193,7 +193,8 @@ spv_result_t ValidateDecorationTarget(ValidationState_t& _, spv::Decoration dec, switch (dec) { case spv::Decoration::Location: case spv::Decoration::Component: - // Location is used for input, output and ray tracing stages. + // Location is used for input, output, tile image, and ray tracing + // stages. if (sc != spv::StorageClass::Input && sc != spv::StorageClass::Output && sc != spv::StorageClass::RayPayloadKHR && sc != spv::StorageClass::IncomingRayPayloadKHR && @@ -201,7 +202,8 @@ spv_result_t ValidateDecorationTarget(ValidationState_t& _, spv::Decoration dec, sc != spv::StorageClass::CallableDataKHR && sc != spv::StorageClass::IncomingCallableDataKHR && sc != spv::StorageClass::ShaderRecordBufferKHR && - sc != spv::StorageClass::HitObjectAttributeNV) { + sc != spv::StorageClass::HitObjectAttributeNV && + sc != spv::StorageClass::TileImageEXT) { return _.diag(SPV_ERROR_INVALID_ID, target) << _.VkErrorID(6672) << _.SpvDecorationString(dec) << " decoration must not be applied to this storage class"; diff --git a/source/val/validate_function.cpp b/source/val/validate_function.cpp index db402aa32f..639817fef4 100644 --- a/source/val/validate_function.cpp +++ b/source/val/validate_function.cpp @@ -14,6 +14,7 @@ #include +#include "source/enum_string_mapping.h" #include "source/opcode.h" #include "source/val/instruction.h" #include "source/val/validate.h" diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 0e5142248a..ded88b118e 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -210,6 +210,7 @@ uint32_t GetPlaneCoordSize(const ImageTypeInfo& info) { case spv::Dim::Dim2D: case spv::Dim::Rect: case spv::Dim::SubpassData: + case spv::Dim::TileImageDataEXT: plane_size = 2; break; case spv::Dim::Dim3D: @@ -854,6 +855,28 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Dim SubpassData requires format Unknown"; } + } else if (info.dim == spv::Dim::TileImageDataEXT) { + if (_.IsVoidType(info.sampled_type)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Dim TileImageDataEXT requires Sampled Type to be not " + "OpTypeVoid"; + } + if (info.sampled != 2) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Dim TileImageDataEXT requires Sampled to be 2"; + } + if (info.format != spv::ImageFormat::Unknown) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Dim TileImageDataEXT requires format Unknown"; + } + if (info.depth != 0) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Dim TileImageDataEXT requires Depth to be 0"; + } + if (info.arrayed != 0) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Dim TileImageDataEXT requires Arrayed to be 0"; + } } else { if (info.multisampled && (info.sampled == 2) && !_.HasCapability(spv::Capability::StorageImageMultisample)) { @@ -919,6 +942,8 @@ spv_result_t ValidateTypeSampledImage(ValidationState_t& _, } // OpenCL requires Sampled=0, checked elsewhere. // Vulkan uses the Sampled=1 case. + // If Dim is TileImageDataEXT, Sampled must be 2 and this is validated + // elsewhere. if ((info.sampled != 0) && (info.sampled != 1)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << _.VkErrorID(4657) @@ -1118,6 +1143,12 @@ spv_result_t ValidateImageTexelPointer(ValidationState_t& _, << "Image Dim SubpassData cannot be used with OpImageTexelPointer"; } + if (info.dim == spv::Dim::TileImageDataEXT) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Image Dim TileImageDataEXT cannot be used with " + "OpImageTexelPointer"; + } + const uint32_t coord_type = _.GetOperandTypeId(inst, 3); if (!coord_type || !_.IsIntScalarOrVectorType(coord_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) @@ -1624,6 +1655,19 @@ spv_result_t ValidateImageRead(ValidationState_t& _, const Instruction* inst) { spvOpcodeString(opcode)); } + if (info.dim == spv::Dim::TileImageDataEXT) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Image Dim TileImageDataEXT cannot be used with " + << spvOpcodeString(opcode); + + _.function(inst->function()->id()) + ->RegisterExecutionModelLimitation( + spv::ExecutionModel::Fragment, + std::string( + "Dim TileImageDataEXT requires Fragment execution model: ") + + spvOpcodeString(opcode)); + } + if (_.GetIdOpcode(info.sampled_type) != spv::Op::OpTypeVoid) { const uint32_t result_component_type = _.GetComponentType(actual_result_type); @@ -1686,6 +1730,11 @@ spv_result_t ValidateImageWrite(ValidationState_t& _, const Instruction* inst) { << "Image 'Dim' cannot be SubpassData"; } + if (info.dim == spv::Dim::TileImageDataEXT) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Image 'Dim' cannot be TileImageDataEXT"; + } + if (spv_result_t result = ValidateImageReadWrite(_, inst, info)) return result; @@ -1900,10 +1949,22 @@ spv_result_t ValidateImageQueryFormatOrOrder(ValidationState_t& _, << "Expected Result Type to be int scalar type"; } - if (_.GetIdOpcode(_.GetOperandTypeId(inst, 2)) != spv::Op::OpTypeImage) { + const uint32_t image_type = _.GetOperandTypeId(inst, 2); + if (_.GetIdOpcode(image_type) != spv::Op::OpTypeImage) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected operand to be of type OpTypeImage"; } + + ImageTypeInfo info; + if (!GetImageTypeInfo(_, image_type, &info)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Corrupt image type definition"; + } + + if (info.dim == spv::Dim::TileImageDataEXT) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Image 'Dim' cannot be TileImageDataEXT"; + } return SPV_SUCCESS; } diff --git a/source/val/validate_mode_setting.cpp b/source/val/validate_mode_setting.cpp index dfa46466ff..d757d4f826 100644 --- a/source/val/validate_mode_setting.cpp +++ b/source/val/validate_mode_setting.cpp @@ -502,6 +502,9 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _, case spv::ExecutionMode::DepthGreater: case spv::ExecutionMode::DepthLess: case spv::ExecutionMode::DepthUnchanged: + case spv::ExecutionMode::NonCoherentColorAttachmentReadEXT: + case spv::ExecutionMode::NonCoherentDepthAttachmentReadEXT: + case spv::ExecutionMode::NonCoherentStencilAttachmentReadEXT: case spv::ExecutionMode::PixelInterlockOrderedEXT: case spv::ExecutionMode::PixelInterlockUnorderedEXT: case spv::ExecutionMode::SampleInterlockOrderedEXT: diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index e43517850a..dbf0ba6d9b 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1572,6 +1572,7 @@ bool ValidationState_t::IsValidStorageClass( case spv::StorageClass::ShaderRecordBufferKHR: case spv::StorageClass::TaskPayloadWorkgroupEXT: case spv::StorageClass::HitObjectAttributeNV: + case spv::StorageClass::TileImageEXT: return true; default: return false; diff --git a/test/text_to_binary.extension_test.cpp b/test/text_to_binary.extension_test.cpp index 6780c7e834..55f8466601 100644 --- a/test/text_to_binary.extension_test.cpp +++ b/test/text_to_binary.extension_test.cpp @@ -1198,5 +1198,54 @@ INSTANTIATE_TEST_SUITE_P( {1, 2, 3, 4, 5, 6})}, }))); +// SPV_EXT_shader_tile_image + +INSTANTIATE_TEST_SUITE_P( + SPV_EXT_shader_tile_image, ExtensionRoundTripTest, + Combine( + Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_0, + SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_3), + ValuesIn(std::vector{ + {"OpExtension \"SPV_EXT_shader_tile_image\"\n", + MakeInstruction(spv::Op::OpExtension, + MakeVector("SPV_EXT_shader_tile_image"))}, + {"OpCapability TileImageColorReadAccessEXT\n", + MakeInstruction( + spv::Op::OpCapability, + {(uint32_t)spv::Capability::TileImageColorReadAccessEXT})}, + {"OpCapability TileImageDepthReadAccessEXT\n", + MakeInstruction( + spv::Op::OpCapability, + {(uint32_t)spv::Capability::TileImageDepthReadAccessEXT})}, + {"OpCapability TileImageStencilReadAccessEXT\n", + MakeInstruction( + spv::Op::OpCapability, + {(uint32_t)spv::Capability::TileImageStencilReadAccessEXT})}, + {"OpExecutionMode %1 NonCoherentColorAttachmentReadEXT\n", + MakeInstruction(spv::Op::OpExecutionMode, + {1, (uint32_t)spv::ExecutionMode:: + NonCoherentColorAttachmentReadEXT})}, + {"OpExecutionMode %1 NonCoherentDepthAttachmentReadEXT\n", + MakeInstruction(spv::Op::OpExecutionMode, + {1, (uint32_t)spv::ExecutionMode:: + NonCoherentDepthAttachmentReadEXT})}, + {"OpExecutionMode %1 NonCoherentStencilAttachmentReadEXT\n", + MakeInstruction(spv::Op::OpExecutionMode, + {1, (uint32_t)spv::ExecutionMode:: + NonCoherentStencilAttachmentReadEXT})}, + {"%2 = OpColorAttachmentReadEXT %1 %3\n", + MakeInstruction(spv::Op::OpColorAttachmentReadEXT, {1, 2, 3})}, + {"%2 = OpColorAttachmentReadEXT %1 %3 %4\n", + MakeInstruction(spv::Op::OpColorAttachmentReadEXT, {1, 2, 3, 4})}, + {"%2 = OpDepthAttachmentReadEXT %1\n", + MakeInstruction(spv::Op::OpDepthAttachmentReadEXT, {1, 2})}, + {"%2 = OpDepthAttachmentReadEXT %1 %3\n", + MakeInstruction(spv::Op::OpDepthAttachmentReadEXT, {1, 2, 3})}, + {"%2 = OpStencilAttachmentReadEXT %1\n", + MakeInstruction(spv::Op::OpStencilAttachmentReadEXT, {1, 2})}, + {"%2 = OpStencilAttachmentReadEXT %1 %3\n", + MakeInstruction(spv::Op::OpStencilAttachmentReadEXT, {1, 2, 3})}, + }))); + } // namespace } // namespace spvtools diff --git a/test/text_to_binary.type_declaration_test.cpp b/test/text_to_binary.type_declaration_test.cpp index 241600eeb3..770f298bc6 100644 --- a/test/text_to_binary.type_declaration_test.cpp +++ b/test/text_to_binary.type_declaration_test.cpp @@ -59,6 +59,7 @@ INSTANTIATE_TEST_SUITE_P( CASE(Rect), CASE(Buffer), CASE(SubpassData), + CASE(TileImageDataEXT), })); #undef CASE // clang-format on @@ -221,6 +222,7 @@ TEST_F(OpTypeForwardPointerTest, ValidStorageClass) { CASE(AtomicCounter); CASE(Image); CASE(StorageBuffer); + CASE(TileImageEXT); } #undef CASE diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index a97ef7cb39..aa335c869d 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -356,7 +356,8 @@ OpFunctionEnd)"; std::string GenerateKernelCode( const std::string& body, - const std::string& capabilities_and_extensions = "") { + const std::string& capabilities_and_extensions = "", + const std::string& declarations = "") { std::ostringstream ss; ss << R"( OpCapability Addresses @@ -436,7 +437,11 @@ OpMemoryModel Physical32 OpenCL %type_sampler = OpTypeSampler %ptr_sampler = OpTypePointer UniformConstant %type_sampler %uniform_sampler = OpVariable %ptr_sampler UniformConstant +)"; + ss << declarations; + + ss << R"( %main = OpFunction %void None %func %main_entry = OpLabel )"; @@ -480,10 +485,10 @@ OpCapability Int64 OpCapability Float64 )"; - ss << capabilities_and_extensions; if (!include_entry_point) { - ss << "OpCapability Linkage"; + ss << "OpCapability Linkage\n"; } + ss << capabilities_and_extensions; ss << R"( OpMemoryModel Logical GLSL450 @@ -781,6 +786,279 @@ TEST_F(ValidateImage, TypeImageWrongArrayForSubpassDataVulkan) { HasSubstr("Dim SubpassData requires Arrayed to be 0")); } +TEST_F(ValidateImage, TypeImageWrongSampledTypeForTileImageDataEXT) { + const std::string code = GetShaderHeader( + "OpCapability TileImageColorReadAccessEXT\n" + "OpExtension \"SPV_EXT_shader_tile_image\"\n", + false) + + R"( +%img_type = OpTypeImage %void TileImageDataEXT 0 0 0 2 Unknown +)"; + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Dim TileImageDataEXT requires Sampled Type to be not OpTypeVoid")); +} + +TEST_F(ValidateImage, TypeImageWrongSampledForTileImageDataEXT) { + const std::string code = GetShaderHeader( + "OpCapability TileImageColorReadAccessEXT\n" + "OpExtension \"SPV_EXT_shader_tile_image\"\n", + false) + + R"( +%img_type = OpTypeImage %f32 TileImageDataEXT 0 0 0 1 Unknown +)"; + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Dim TileImageDataEXT requires Sampled to be 2")); +} + +TEST_F(ValidateImage, TypeImageWrongFormatForTileImageDataEXT) { + const std::string code = GetShaderHeader( + "OpCapability TileImageColorReadAccessEXT\n" + "OpExtension \"SPV_EXT_shader_tile_image\"\n", + false) + + R"( +%img_type = OpTypeImage %f32 TileImageDataEXT 0 0 0 2 Rgba32f +)"; + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Dim TileImageDataEXT requires format Unknown")); +} + +TEST_F(ValidateImage, TypeImageWrongDepthForTileImageDataEXT) { + const std::string code = GetShaderHeader( + "OpCapability TileImageColorReadAccessEXT\n" + "OpExtension \"SPV_EXT_shader_tile_image\"\n", + false) + + R"( +%img_type = OpTypeImage %f32 TileImageDataEXT 1 0 0 2 Unknown +)"; + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Dim TileImageDataEXT requires Depth to be 0")); +} + +TEST_F(ValidateImage, TypeImageWrongArrayedForTileImageDataEXT) { + const std::string code = GetShaderHeader( + "OpCapability TileImageColorReadAccessEXT\n" + "OpExtension \"SPV_EXT_shader_tile_image\"\n", + false) + + R"( +%img_type = OpTypeImage %f32 TileImageDataEXT 0 1 0 2 Unknown +)"; + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Dim TileImageDataEXT requires Arrayed to be 0")); +} + +TEST_F(ValidateImage, TypeSampledImage_TileImageDataEXT_Error) { + const std::string code = GetShaderHeader( + "OpCapability TileImageColorReadAccessEXT\n" + "OpExtension \"SPV_EXT_shader_tile_image\"\n", + false) + + R"( +%img_type = OpTypeImage %f32 TileImageDataEXT 0 0 0 2 Unknown +%simg_type = OpTypeSampledImage %img_type +)"; + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Sampled image type requires an image type with " + "\"Sampled\" operand set to 0 or 1")); +} + +TEST_F(ValidateImage, ImageTexelPointerImageDimTileImageDataEXTBad) { + const std::string body = R"( +%texel_ptr = OpImageTexelPointer %ptr_Image_u32 %tile_image_u32_tid_0002 %u32_0 %u32_0 +%sum = OpAtomicIAdd %u32 %texel_ptr %u32_1 %u32_0 %u32_1 +)"; + const std::string decl = R"( +%type_image_u32_tid_0002 = OpTypeImage %u32 TileImageDataEXT 0 0 0 2 Unknown +%ptr_image_u32_tid_0002 = OpTypePointer TileImageEXT %type_image_u32_tid_0002 +%tile_image_u32_tid_0002 = OpVariable %ptr_image_u32_tid_0002 TileImageEXT +)"; + + const std::string extra = R"( +OpCapability TileImageColorReadAccessEXT +OpExtension "SPV_EXT_shader_tile_image" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_5, "GLSL450", decl) + .c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Image Dim TileImageDataEXT cannot be used with " + "OpImageTexelPointer")); +} + +TEST_F(ValidateImage, ReadTileImageDataEXT) { + const std::string body = R"( +%img = OpLoad %type_image_f32_tid_0002 %uniform_image_f32_tid_0002 +%res1 = OpImageRead %f32vec4 %img %u32vec2_01 +)"; + + const std::string decl = R"( +%type_image_f32_tid_0002 = OpTypeImage %f32 TileImageDataEXT 0 0 0 2 Unknown +%ptr_image_f32_tid_0002 = OpTypePointer UniformConstant %type_image_f32_tid_0002 +%uniform_image_f32_tid_0002 = OpVariable %ptr_image_f32_tid_0002 UniformConstant +)"; + + const std::string extra = R"( +OpCapability StorageImageReadWithoutFormat +OpCapability TileImageColorReadAccessEXT +OpExtension "SPV_EXT_shader_tile_image" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_5, "GLSL450", decl) + .c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Image Dim TileImageDataEXT cannot be used with ImageRead")); +} + +TEST_F(ValidateImage, WriteTileImageDataEXT) { + const std::string body = R"( +%img = OpLoad %type_image_f32_tid_0002 %uniform_image_f32_tid_0002 +OpImageWrite %img %u32vec2_01 %f32vec4_0000 +)"; + + const std::string decl = R"( +%type_image_f32_tid_0002 = OpTypeImage %f32 TileImageDataEXT 0 0 0 2 Unknown +%ptr_image_f32_tid_0002 = OpTypePointer UniformConstant %type_image_f32_tid_0002 +%uniform_image_f32_tid_0002 = OpVariable %ptr_image_f32_tid_0002 UniformConstant +)"; + + const std::string extra = R"( +OpCapability TileImageColorReadAccessEXT +OpExtension "SPV_EXT_shader_tile_image" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_5, "GLSL450", decl) + .c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Image 'Dim' cannot be TileImageDataEXT")); +} + +TEST_F(ValidateImage, QueryFormatTileImageDataEXT) { + const std::string body = R"( +%img = OpLoad %type_image_f32_tid_0002 %uniform_image_f32_tid_0002 +%res1 = OpImageQueryFormat %u32 %img +)"; + + const std::string decl = R"( +%type_image_f32_tid_0002 = OpTypeImage %f32 TileImageDataEXT 0 0 0 2 Unknown +%ptr_image_f32_tid_0002 = OpTypePointer UniformConstant %type_image_f32_tid_0002 +%uniform_image_f32_tid_0002 = OpVariable %ptr_image_f32_tid_0002 UniformConstant +)"; + + const std::string extra = R"( +OpCapability TileImageColorReadAccessEXT +OpExtension "SPV_EXT_shader_tile_image" +)"; + + CompileSuccessfully(GenerateKernelCode(body, extra, decl).c_str()); + + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Image 'Dim' cannot be TileImageDataEXT")); +} + +TEST_F(ValidateImage, QueryOrderTileImageDataEXT) { + const std::string body = R"( +%img = OpLoad %type_image_f32_tid_0002 %uniform_image_f32_tid_0002 +%res1 = OpImageQueryOrder %u32 %img +)"; + + const std::string decl = R"( +%type_image_f32_tid_0002 = OpTypeImage %f32 TileImageDataEXT 0 0 0 2 Unknown +%ptr_image_f32_tid_0002 = OpTypePointer UniformConstant %type_image_f32_tid_0002 +%uniform_image_f32_tid_0002 = OpVariable %ptr_image_f32_tid_0002 UniformConstant +)"; + + const std::string extra = R"( +OpCapability TileImageColorReadAccessEXT +OpExtension "SPV_EXT_shader_tile_image" +)"; + + CompileSuccessfully(GenerateKernelCode(body, extra, decl).c_str()); + + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Image 'Dim' cannot be TileImageDataEXT")); +} + +TEST_F(ValidateImage, SparseFetchTileImageDataEXT) { + const std::string body = R"( +%img = OpLoad %type_image_f32_tid_0002 %uniform_image_f32_tid_0002 +%res1 = OpImageSparseFetch %struct_u32_f32vec4 %img %u32vec2_01 +)"; + + const std::string decl = R"( +%type_image_f32_tid_0002 = OpTypeImage %f32 TileImageDataEXT 0 0 0 2 Unknown +%ptr_image_f32_tid_0002 = OpTypePointer UniformConstant %type_image_f32_tid_0002 +%uniform_image_f32_tid_0002 = OpVariable %ptr_image_f32_tid_0002 UniformConstant +)"; + + const std::string extra = R"( +OpCapability StorageImageReadWithoutFormat +OpCapability TileImageColorReadAccessEXT +OpExtension "SPV_EXT_shader_tile_image" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_5, "GLSL450", decl) + .c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Expected Image 'Sampled' parameter to be 1")); +} + +TEST_F(ValidateImage, SparseReadTileImageDataEXT) { + const std::string body = R"( +%img = OpLoad %type_image_f32_tid_0002 %uniform_image_f32_tid_0002 +%res1 = OpImageSparseRead %struct_u32_f32vec4 %img %u32vec2_01 +)"; + + const std::string decl = R"( +%type_image_f32_tid_0002 = OpTypeImage %f32 TileImageDataEXT 0 0 0 2 Unknown +%ptr_image_f32_tid_0002 = OpTypePointer UniformConstant %type_image_f32_tid_0002 +%uniform_image_f32_tid_0002 = OpVariable %ptr_image_f32_tid_0002 UniformConstant +)"; + + const std::string extra = R"( +OpCapability StorageImageReadWithoutFormat +OpCapability TileImageColorReadAccessEXT +OpExtension "SPV_EXT_shader_tile_image" +)"; + + CompileSuccessfully(GenerateShaderCode(body, extra, "Fragment", "", + SPV_ENV_UNIVERSAL_1_5, "GLSL450", decl) + .c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Image Dim TileImageDataEXT cannot be used with ImageSparseRead")); +} + TEST_F(ValidateImage, TypeImage_OpenCL_Sampled0_OK) { const std::string code = GetKernelHeader() + R"( %img_type = OpTypeImage %void 2D 0 0 0 0 Unknown ReadOnly diff --git a/test/val/val_modes_test.cpp b/test/val/val_modes_test.cpp index a50ac51646..8dc0fbc5a1 100644 --- a/test/val/val_modes_test.cpp +++ b/test/val/val_modes_test.cpp @@ -578,6 +578,11 @@ TEST_P(ValidateModeExecution, ExecutionMode) { sstr << "OpCapability Kernel\n"; if (env == SPV_ENV_UNIVERSAL_1_3) { sstr << "OpCapability SubgroupDispatch\n"; + } else if (env == SPV_ENV_UNIVERSAL_1_5) { + sstr << "OpCapability TileImageColorReadAccessEXT\n"; + sstr << "OpCapability TileImageDepthReadAccessEXT\n"; + sstr << "OpCapability TileImageStencilReadAccessEXT\n"; + sstr << "OpExtension \"SPV_EXT_shader_tile_image\"\n"; } } sstr << "OpMemoryModel Logical GLSL450\n"; @@ -701,6 +706,27 @@ INSTANTIATE_TEST_SUITE_P( "DepthLess", "DepthUnchanged"), Values(SPV_ENV_UNIVERSAL_1_0))); +INSTANTIATE_TEST_SUITE_P(ValidateModeFragmentOnlyGoodSpv15, + ValidateModeExecution, + Combine(Values(SPV_SUCCESS), Values(""), + Values("Fragment"), + Values("NonCoherentColorAttachmentReadEXT", + "NonCoherentDepthAttachmentReadEXT", + "NonCoherentStencilAttachmentReadEXT"), + Values(SPV_ENV_UNIVERSAL_1_5))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeFragmentOnlyBadSpv15, ValidateModeExecution, + Combine(Values(SPV_ERROR_INVALID_DATA), + Values("Execution mode can only be used with the Fragment " + "execution model."), + Values("Geometry", "TessellationControl", "TessellationEvaluation", + "GLCompute", "Vertex", "Kernel"), + Values("NonCoherentColorAttachmentReadEXT", + "NonCoherentDepthAttachmentReadEXT", + "NonCoherentStencilAttachmentReadEXT"), + Values(SPV_ENV_UNIVERSAL_1_5))); + INSTANTIATE_TEST_SUITE_P(ValidateModeKernelOnlyGoodSpv13, ValidateModeExecution, Combine(Values(SPV_SUCCESS), Values(""), Values("Kernel"), From 55bc37f826217d1dea3d836c6fc3aca9ccae21e1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 14 Apr 2023 10:27:42 -0400 Subject: [PATCH 125/523] Roll external/googletest/ 8fa9461cc..12a5852e4 (1 commit) (#5193) https://github.com/google/googletest/compare/8fa9461cc28e...12a5852e451b $ git log 8fa9461cc..12a5852e4 --date=short --no-merges --format='%ad %ae %s' 2022-09-15 paul.groke work around GCC 6~11 ADL bug 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 42c4fdfb7b..84e70962a0 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': '8fa9461cc28e053d66f17132808d287ae51575e2', + 'googletest_revision': '12a5852e451baabc79c63a86c634912c563d57bc', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From d5f69dba559822c2c968a959238ab037b5556af6 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Fri, 14 Apr 2023 10:59:01 -0400 Subject: [PATCH 126/523] Remove dead code (#5195) * Execution model limitation was never executed and the check actually belongs with other opcodes --- source/val/validate_image.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index ded88b118e..733556b1d2 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -1659,13 +1659,6 @@ spv_result_t ValidateImageRead(ValidationState_t& _, const Instruction* inst) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Image Dim TileImageDataEXT cannot be used with " << spvOpcodeString(opcode); - - _.function(inst->function()->id()) - ->RegisterExecutionModelLimitation( - spv::ExecutionModel::Fragment, - std::string( - "Dim TileImageDataEXT requires Fragment execution model: ") + - spvOpcodeString(opcode)); } if (_.GetIdOpcode(info.sampled_type) != spv::Op::OpTypeVoid) { From bec566a32b41f234d1ca94f92e78e3daf088ba2b Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Tue, 18 Apr 2023 19:58:12 +0100 Subject: [PATCH 127/523] opt: Fix null deref in OpMatrixTimesVector and OpVectorTimesMatrix (#5199) When some (not all) of the matrix columns are OpConstantNull --- source/opt/const_folding_rules.cpp | 56 ++++++++++++++++------------- test/opt/fold_test.cpp | 58 ++++++++++++++++++++++++------ 2 files changed, 80 insertions(+), 34 deletions(-) diff --git a/source/opt/const_folding_rules.cpp b/source/opt/const_folding_rules.cpp index 516c34b3bc..26108082f4 100644 --- a/source/opt/const_folding_rules.cpp +++ b/source/opt/const_folding_rules.cpp @@ -398,12 +398,14 @@ ConstantFoldingRule FoldVectorTimesMatrix() { if (float_type->width() == 32) { for (uint32_t i = 0; i < resultVectorSize; ++i) { float result_scalar = 0.0f; - const analysis::VectorConstant* c2_vec = - c2_components[i]->AsVectorConstant(); - for (uint32_t j = 0; j < c2_vec->GetComponents().size(); ++j) { - float c1_scalar = c1_components[j]->GetFloat(); - float c2_scalar = c2_vec->GetComponents()[j]->GetFloat(); - result_scalar += c1_scalar * c2_scalar; + if (!c2_components[i]->AsNullConstant()) { + const analysis::VectorConstant* c2_vec = + c2_components[i]->AsVectorConstant(); + for (uint32_t j = 0; j < c2_vec->GetComponents().size(); ++j) { + float c1_scalar = c1_components[j]->GetFloat(); + float c2_scalar = c2_vec->GetComponents()[j]->GetFloat(); + result_scalar += c1_scalar * c2_scalar; + } } utils::FloatProxy result(result_scalar); std::vector words = result.GetWords(); @@ -415,12 +417,14 @@ ConstantFoldingRule FoldVectorTimesMatrix() { } else if (float_type->width() == 64) { for (uint32_t i = 0; i < c2_components.size(); ++i) { double result_scalar = 0.0; - const analysis::VectorConstant* c2_vec = - c2_components[i]->AsVectorConstant(); - for (uint32_t j = 0; j < c2_vec->GetComponents().size(); ++j) { - double c1_scalar = c1_components[j]->GetDouble(); - double c2_scalar = c2_vec->GetComponents()[j]->GetDouble(); - result_scalar += c1_scalar * c2_scalar; + if (!c2_components[i]->AsNullConstant()) { + const analysis::VectorConstant* c2_vec = + c2_components[i]->AsVectorConstant(); + for (uint32_t j = 0; j < c2_vec->GetComponents().size(); ++j) { + double c1_scalar = c1_components[j]->GetDouble(); + double c2_scalar = c2_vec->GetComponents()[j]->GetDouble(); + result_scalar += c1_scalar * c2_scalar; + } } utils::FloatProxy result(result_scalar); std::vector words = result.GetWords(); @@ -491,12 +495,14 @@ ConstantFoldingRule FoldMatrixTimesVector() { for (uint32_t i = 0; i < resultVectorSize; ++i) { float result_scalar = 0.0f; for (uint32_t j = 0; j < c1_components.size(); ++j) { - float c1_scalar = c1_components[j] - ->AsVectorConstant() - ->GetComponents()[i] - ->GetFloat(); - float c2_scalar = c2_components[j]->GetFloat(); - result_scalar += c1_scalar * c2_scalar; + if (!c1_components[j]->AsNullConstant()) { + float c1_scalar = c1_components[j] + ->AsVectorConstant() + ->GetComponents()[i] + ->GetFloat(); + float c2_scalar = c2_components[j]->GetFloat(); + result_scalar += c1_scalar * c2_scalar; + } } utils::FloatProxy result(result_scalar); std::vector words = result.GetWords(); @@ -509,12 +515,14 @@ ConstantFoldingRule FoldMatrixTimesVector() { for (uint32_t i = 0; i < resultVectorSize; ++i) { double result_scalar = 0.0; for (uint32_t j = 0; j < c1_components.size(); ++j) { - double c1_scalar = c1_components[j] - ->AsVectorConstant() - ->GetComponents()[i] - ->GetDouble(); - double c2_scalar = c2_components[j]->GetDouble(); - result_scalar += c1_scalar * c2_scalar; + if (!c1_components[j]->AsNullConstant()) { + double c1_scalar = c1_components[j] + ->AsVectorConstant() + ->GetComponents()[i] + ->GetDouble(); + double c2_scalar = c2_components[j]->GetDouble(); + result_scalar += c1_scalar * c2_scalar; + } } utils::FloatProxy result(result_scalar); std::vector words = result.GetWords(); diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index 636c20cd60..eff8edf0a7 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -292,6 +292,7 @@ OpName %main "main" %v4float_null = OpConstantNull %v4float %mat4v4float_null = OpConstantComposite %mat4v4float %v4float_null %v4float_null %v4float_null %v4float_null %mat4v4float_1_2_3_4 = OpConstantComposite %mat4v4float %v4float_1_2_3_4 %v4float_1_2_3_4 %v4float_1_2_3_4 %v4float_1_2_3_4 +%mat4v4float_1_2_3_4_null = OpConstantComposite %mat4v4float %v4float_1_2_3_4 %v4float_null %v4float_1_2_3_4 %v4float_null %107 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0 %v4double_0_0_0_0 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0 %v4double_0_0_0_1 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_1 @@ -302,6 +303,7 @@ OpName %main "main" %v4double_null = OpConstantNull %v4double %mat4v4double_null = OpConstantComposite %mat4v4double %v4double_null %v4double_null %v4double_null %v4double_null %mat4v4double_1_2_3_4 = OpConstantComposite %mat4v4double %v4double_1_2_3_4 %v4double_1_2_3_4 %v4double_1_2_3_4 %v4double_1_2_3_4 +%mat4v4double_1_2_3_4_null = OpConstantComposite %mat4v4double %v4double_1_2_3_4 %v4double_null %v4double_1_2_3_4 %v4double_null %v4float_n1_2_1_3 = OpConstantComposite %v4float %float_n1 %float_2 %float_1 %float_3 %uint_0x3f800000 = OpConstant %uint 0x3f800000 %uint_0xbf800000 = OpConstant %uint 0xbf800000 @@ -1049,7 +1051,16 @@ ::testing::Values( "OpReturn\n" + "OpFunctionEnd", 2, {30.0,30.0,30.0,30.0}), - // Test case 4: OpMatrixTimesVector Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {0.0, 0.0, 0.0, 0.0} + // Test case 4: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, Null, {1.0, 2.0, 3.0, 4.0}, Null} {1.0, 2.0, 3.0, 4.0} {30.0, 0.0, 30.0, 0.0} + InstructionFoldingCase>( + Header() + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpVectorTimesMatrix %v4double %v4double_1_2_3_4 %mat4v4double_1_2_3_4_null\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {30.0,0.0,30.0,0.0}), + // Test case 5: OpMatrixTimesVector Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {0.0, 0.0, 0.0, 0.0} InstructionFoldingCase>( Header() + "%main = OpFunction %void None %void_func\n" + @@ -1058,7 +1069,7 @@ ::testing::Values( "OpReturn\n" + "OpFunctionEnd", 2, {0.0,0.0,0.0,0.0}), - // Test case 5: OpMatrixTimesVector Non-Zero Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0} + // Test case 6: OpMatrixTimesVector Non-Zero Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0} InstructionFoldingCase>( Header() + "%main = OpFunction %void None %void_func\n" + @@ -1067,7 +1078,7 @@ ::testing::Values( "OpReturn\n" + "OpFunctionEnd", 2, {0.0,0.0,0.0,0.0}), - // Test case 6: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {10.0, 20.0, 30.0, 40.0} + // Test case 7: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {10.0, 20.0, 30.0, 40.0} InstructionFoldingCase>( Header() + "%main = OpFunction %void None %void_func\n" + @@ -1075,7 +1086,16 @@ ::testing::Values( "%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4 %v4double_1_2_3_4\n" + "OpReturn\n" + "OpFunctionEnd", - 2, {10.0,20.0,30.0,40.0}) + 2, {10.0,20.0,30.0,40.0}), + // Test case 8: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, Null, {1.0, 2.0, 3.0, 4.0}, Null} {10.0, 20.0, 30.0, 40.0} + InstructionFoldingCase>( + Header() + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpMatrixTimesVector %v4double %mat4v4double_1_2_3_4_null %v4double_1_2_3_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {4.0,8.0,12.0,16.0}) )); using FloatVectorInstructionFoldingTest = @@ -1154,7 +1174,16 @@ ::testing::Values( "OpReturn\n" + "OpFunctionEnd", 2, {0.0f,0.0f,0.0f,0.0f}), - // Test case 4: OpVectorTimesMatrix Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0} + // Test case 4: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, Null, {1.0, 2.0, 3.0, 4.0}, Null} {1.0, 2.0, 3.0, 4.0} {30.0, 0.0, 30.0, 0.0} + InstructionFoldingCase>( + Header() + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpVectorTimesMatrix %v4float %v4float_1_2_3_4 %mat4v4float_1_2_3_4_null\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {30.0,0.0,30.0,0.0}), + // Test case 5: OpVectorTimesMatrix Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0} InstructionFoldingCase>( Header() + "%main = OpFunction %void None %void_func\n" + @@ -1163,7 +1192,7 @@ ::testing::Values( "OpReturn\n" + "OpFunctionEnd", 2, {0.0f,0.0f,0.0f,0.0f}), - // Test case 5: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {1.0, 2.0, 3.0, 4.0} {30.0, 30.0, 30.0, 30.0} + // Test case 6: OpVectorTimesMatrix Non-Zero Non-Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {1.0, 2.0, 3.0, 4.0} {30.0, 30.0, 30.0, 30.0} InstructionFoldingCase>( Header() + "%main = OpFunction %void None %void_func\n" + @@ -1172,7 +1201,7 @@ ::testing::Values( "OpReturn\n" + "OpFunctionEnd", 2, {30.0f,30.0f,30.0f,30.0f}), - // Test case 6: OpMatrixTimesVector Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {0.0, 0.0, 0.0, 0.0} + // Test case 7: OpMatrixTimesVector Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}} {0.0, 0.0, 0.0, 0.0} InstructionFoldingCase>( Header() + "%main = OpFunction %void None %void_func\n" + @@ -1181,7 +1210,7 @@ ::testing::Values( "OpReturn\n" + "OpFunctionEnd", 2, {0.0f,0.0f,0.0f,0.0f}), - // Test case 7: OpMatrixTimesVector Non-Zero Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0} + // Test case 8: OpMatrixTimesVector Non-Zero Zero {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {0.0, 0.0, 0.0, 0.0} {0.0, 0.0, 0.0, 0.0} InstructionFoldingCase>( Header() + "%main = OpFunction %void None %void_func\n" + @@ -1190,7 +1219,7 @@ ::testing::Values( "OpReturn\n" + "OpFunctionEnd", 2, {0.0f,0.0f,0.0f,0.0f}), - // Test case 8: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {10.0, 20.0, 30.0, 40.0} + // Test case 9: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}, {1.0, 2.0, 3.0, 4.0}} {10.0, 20.0, 30.0, 40.0} InstructionFoldingCase>( Header() + "%main = OpFunction %void None %void_func\n" + @@ -1198,7 +1227,16 @@ ::testing::Values( "%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4 %v4float_1_2_3_4\n" + "OpReturn\n" + "OpFunctionEnd", - 2, {10.0f,20.0f,30.0f,40.0f}) + 2, {10.0f,20.0f,30.0f,40.0f}), + // Test case 10: OpMatrixTimesVector Non-Zero Non-Zero {1.0, 2.0, 3.0, 4.0} {{1.0, 2.0, 3.0, 4.0}, Null, {1.0, 2.0, 3.0, 4.0}, Null} {10.0, 20.0, 30.0, 40.0} + InstructionFoldingCase>( + Header() + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpMatrixTimesVector %v4float %mat4v4float_1_2_3_4_null %v4float_1_2_3_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {4.0,8.0,12.0,16.0}) )); // clang-format on using BooleanInstructionFoldingTest = From 25ad5e19f193429b737433d5f6151062ddbc1680 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Tue, 18 Apr 2023 15:47:10 -0400 Subject: [PATCH 128/523] Do not define GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE if it is already defined. (#5200) --- source/fuzz/protobufs/spirvfuzz_protobufs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/fuzz/protobufs/spirvfuzz_protobufs.h b/source/fuzz/protobufs/spirvfuzz_protobufs.h index d798361efd..44aecfd62f 100644 --- a/source/fuzz/protobufs/spirvfuzz_protobufs.h +++ b/source/fuzz/protobufs/spirvfuzz_protobufs.h @@ -21,7 +21,9 @@ // of these header files without having to compromise on freedom from warnings // in the rest of the project. +#ifndef GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE #define GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE 1 +#endif #if defined(__clang__) #pragma clang diagnostic push From 9e627132a8f17dedab6580f666cebc141396a344 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 12:59:34 -0400 Subject: [PATCH 129/523] Roll external/googletest/ 12a5852e4..783d00fd1 (9 commits) (#5198) https://github.com/google/googletest/compare/12a5852e451b...783d00fd1986 $ git log 12a5852e4..783d00fd1 --date=short --no-merges --format='%ad %ae %s' 2023-04-21 tomhughes Use '=default' to define trivial constructor/destructors 2023-04-21 tomhughes Use the empty method to check for emptiness 2023-04-20 tomhughes Add missing std includes 2023-04-20 tomhughes Use std::make_unique 2023-04-20 tomhughes Fix spelling 2023-04-20 tomhughes Add missing std includes 2023-04-20 tomhughes Make parameter names in function declaration match the names in the definitions 2023-04-17 absl-team Update gMock Cookbook to reflect deprecation of testing::ByMove 2023-04-14 jerylvaz Suppress a clang-tidy warning in the MATCHER_P macro 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 84e70962a0..6f9633fb55 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': '12a5852e451baabc79c63a86c634912c563d57bc', + 'googletest_revision': '783d00fd19865fcbc3065e3fb3e17144761fcf5a', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From d4c0abdcad60325a2ab3c00a81847e2dbdc927a2 Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Wed, 26 Apr 2023 14:28:01 -0600 Subject: [PATCH 130/523] instrument: Change descriptor state storage format (#5178) Split per-DescriptorSet state into separate memory blocks which are accessed via an array of buffer device addresses. This is being done to make it easier to update state for a single DescriptorSet without rebuilding the old giant flat buffer. The new data format is documented as comments in include/spirv-tools/instrument.hpp --- include/spirv-tools/instrument.hpp | 47 +- source/opt/inst_bindless_check_pass.cpp | 534 ++++++- source/opt/inst_bindless_check_pass.h | 11 + source/opt/inst_buff_addr_check_pass.cpp | 18 + source/opt/inst_buff_addr_check_pass.h | 3 + source/opt/instrument_pass.cpp | 13 + source/opt/instrument_pass.h | 5 +- source/opt/ir_builder.h | 9 +- test/opt/inst_bindless_check_test.cpp | 1854 +++++++++++----------- 9 files changed, 1527 insertions(+), 967 deletions(-) diff --git a/include/spirv-tools/instrument.hpp b/include/spirv-tools/instrument.hpp index a75561b508..2e029e1554 100644 --- a/include/spirv-tools/instrument.hpp +++ b/include/spirv-tools/instrument.hpp @@ -217,26 +217,37 @@ 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 consists of a single array of -// unsigned integers we will call Data[]. This array is formatted as follows. -// -// At offset kDebugInputBindlessInitOffset in Data[] is a single uint which -// gives an offset to the start of the bindless initialization data. More -// specifically, if the following value is zero, we know that the descriptor at -// (set = s, binding = b, index = i) is not initialized; if the value is -// non-zero, and the descriptor points to a buffer, the value is the length of -// the buffer in bytes and can be used to check for out-of-bounds buffer -// references: -// Data[ i + Data[ b + Data[ s + Data[ kDebugInputBindlessInitOffset ] ] ] ] -static const int kDebugInputBindlessInitOffset = 0; - -// At offset kDebugInputBindlessOffsetLengths is some number of uints which -// provide the bindless length data. More specifically, the number of -// descriptors at (set=s, binding=b) is: -// Data[ Data[ s + kDebugInputBindlessOffsetLengths ] + b ] -static const int kDebugInputBindlessOffsetLengths = 1; +// 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 // diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp index cd712f068e..1ea37ab8d8 100644 --- a/source/opt/inst_bindless_check_pass.cpp +++ b/source/opt/inst_bindless_check_pass.cpp @@ -16,6 +16,8 @@ #include "inst_bindless_check_pass.h" +#include "source/spirv_constant.h" + namespace spvtools { namespace opt { namespace { @@ -40,37 +42,521 @@ constexpr int kSpvTypeImageMS = 4; constexpr int kSpvTypeImageSampled = 5; } // 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); + } + } +} + +// clang-format off +// GLSL: +// uint inst_bindless_read_binding_length(uint desc_set_idx, uint binding_idx) +// { +// if (desc_set_idx >= inst_bindless_input_buffer.desc_sets.length()) { +// return 0; +// } +// +// DescriptorSetData set_data = inst_bindless_input_buffer.desc_sets[desc_set_idx]; +// uvec2 ptr_as_vec = uvec2(set_data); +// if ((ptr_as_vec.x == 0u) && (_ptr_as_vec.y == 0u)) +// { +// return 0u; +// } +// uint num_bindings = set_data.num_bindings; +// if (binding_idx >= num_bindings) { +// return 0; +// } +// return set_data.data[binding_idx]; +// } +// clang-format on +uint32_t InstBindlessCheckPass::GenDebugReadLengthFunctionId() { + if (read_length_func_id_ != 0) { + return read_length_func_id_; + } + SetupInputBufferIds(); + const analysis::Integer* uint_type = GetInteger(32, false); + const std::vector param_types(2, uint_type); + + const uint32_t func_id = TakeNextId(); + std::unique_ptr func = + StartFunction(func_id, uint_type, param_types); + + const std::vector param_ids = AddParameters(*func, param_types); + + // Create block + auto new_blk_ptr = MakeUnique(NewLabel(TakeNextId())); + InstructionBuilder builder( + context(), new_blk_ptr.get(), + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + Instruction* inst; + + inst = builder.AddBinaryOp( + GetBoolId(), spv::Op::OpUGreaterThanEqual, param_ids[0], + builder.GetUintConstantId(kDebugInputBindlessMaxDescSets)); + const uint32_t desc_cmp_id = inst->result_id(); + + uint32_t error_blk_id = TakeNextId(); + uint32_t merge_blk_id = TakeNextId(); + std::unique_ptr merge_label(NewLabel(merge_blk_id)); + std::unique_ptr error_label(NewLabel(error_blk_id)); + (void)builder.AddConditionalBranch(desc_cmp_id, error_blk_id, merge_blk_id, + merge_blk_id); + + func->AddBasicBlock(std::move(new_blk_ptr)); + + // error return + new_blk_ptr = MakeUnique(std::move(error_label)); + builder.SetInsertPoint(&*new_blk_ptr); + (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, + builder.GetUintConstantId(0)); + func->AddBasicBlock(std::move(new_blk_ptr)); + + // check descriptor set table entry is non-null + new_blk_ptr = MakeUnique(std::move(merge_label)); + builder.SetInsertPoint(&*new_blk_ptr); + + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + const uint32_t desc_set_ptr_ptr = type_mgr->FindPointerToType( + desc_set_ptr_id_, spv::StorageClass::StorageBuffer); + + inst = builder.AddAccessChain(desc_set_ptr_ptr, input_buffer_id_, + {builder.GetUintConstantId(0), param_ids[0]}); + 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(); + + 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, + builder.GetUintConstantId(0)); + 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, + builder.GetUintConstantId(0)); + 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(); + + error_blk_id = TakeNextId(); + merge_blk_id = TakeNextId(); + merge_label = NewLabel(merge_blk_id); + error_label = NewLabel(error_blk_id); + (void)builder.AddConditionalBranch(is_null_id, error_blk_id, merge_blk_id, + merge_blk_id); + func->AddBasicBlock(std::move(new_blk_ptr)); + // error return + new_blk_ptr = MakeUnique(std::move(error_label)); + builder.SetInsertPoint(&*new_blk_ptr); + (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, + builder.GetUintConstantId(0)); + func->AddBasicBlock(std::move(new_blk_ptr)); + + // check binding is in range + new_blk_ptr = MakeUnique(std::move(merge_label)); + builder.SetInsertPoint(&*new_blk_ptr); + + const uint32_t uint_ptr = type_mgr->FindPointerToType( + GetUintId(), spv::StorageClass::PhysicalStorageBuffer); + + inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id, + {builder.GetUintConstantId(0)}); + 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(); + + inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual, + param_ids[1], num_bindings_id); + const uint32_t bindings_cmp_id = inst->result_id(); + + error_blk_id = TakeNextId(); + merge_blk_id = TakeNextId(); + merge_label = NewLabel(merge_blk_id); + error_label = NewLabel(error_blk_id); + (void)builder.AddConditionalBranch(bindings_cmp_id, error_blk_id, + merge_blk_id, merge_blk_id); + func->AddBasicBlock(std::move(new_blk_ptr)); + // error return + new_blk_ptr = MakeUnique(std::move(error_label)); + builder.SetInsertPoint(&*new_blk_ptr); + (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, + builder.GetUintConstantId(0)); + func->AddBasicBlock(std::move(new_blk_ptr)); + + // read binding length + new_blk_ptr = MakeUnique(std::move(merge_label)); + builder.SetInsertPoint(&*new_blk_ptr); + + inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id, + {{builder.GetUintConstantId(1), param_ids[1]}}); + 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(); + + (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, length_id); + + func->AddBasicBlock(std::move(new_blk_ptr)); + func->SetFunctionEnd(EndFunction()); + + context()->AddFunction(std::move(func)); + context()->AddDebug2Inst(NewGlobalName(func_id, "read_binding_length")); + + read_length_func_id_ = func_id; + // Make sure this function doesn't get processed by + // InstrumentPass::InstProcessCallTreeFromRoots() + param2output_func_id_[2] = func_id; + return read_length_func_id_; +} + +// clang-format off +// GLSL: +// result = inst_bindless_read_binding_length(desc_set_id, binding_id); +// clang-format on uint32_t InstBindlessCheckPass::GenDebugReadLength( uint32_t var_id, InstructionBuilder* builder) { - uint32_t desc_set_idx = - var2desc_set_[var_id] + kDebugInputBindlessOffsetLengths; - uint32_t desc_set_idx_id = builder->GetUintConstantId(desc_set_idx); - uint32_t binding_idx_id = builder->GetUintConstantId(var2binding_[var_id]); - return GenDebugDirectRead({desc_set_idx_id, binding_idx_id}, builder); + const uint32_t func_id = GenDebugReadLengthFunctionId(); + + const std::vector args = { + builder->GetUintConstantId(var2desc_set_[var_id]), + builder->GetUintConstantId(var2binding_[var_id]), + }; + return GenReadFunctionCall(func_id, args, builder); } +// clang-format off +// GLSL: +// uint inst_bindless_read_desc_init(uint desc_set_idx, uint binding_idx, uint desc_idx) +// { +// if (desc_set_idx >= uint(inst_bindless_input_buffer.desc_sets.length())) +// { +// return 0u; +// } +// DescriptorSetData set_data = inst_bindless_input_buffer.desc_sets[desc_set_idx]; +// uvec2 ptr_as_vec = uvec2(set_data) +// if ((ptr_as_vec .x == 0u) && (ptr_as_vec.y == 0u)) +// { +// return 0u; +// } +// if (binding_idx >= set_data.num_bindings) +// { +// return 0u; +// } +// if (desc_idx >= set_data.data[binding_idx]) +// { +// return 0u; +// } +// uint desc_records_start = set_data.data[set_data.num_bindings + binding_idx]; +// return set_data.data[desc_records_start + desc_idx]; +// } +// clang-format on +uint32_t InstBindlessCheckPass::GenDebugReadInitFunctionId() { + if (read_init_func_id_ != 0) { + return read_init_func_id_; + } + SetupInputBufferIds(); + const analysis::Integer* uint_type = GetInteger(32, false); + const std::vector param_types(3, uint_type); + + const uint32_t func_id = TakeNextId(); + std::unique_ptr func = + StartFunction(func_id, uint_type, param_types); + + const std::vector param_ids = AddParameters(*func, param_types); + + // Create block + auto new_blk_ptr = MakeUnique(NewLabel(TakeNextId())); + InstructionBuilder builder( + context(), new_blk_ptr.get(), + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + Instruction* inst; + + inst = builder.AddBinaryOp( + GetBoolId(), spv::Op::OpUGreaterThanEqual, param_ids[0], + builder.GetUintConstantId(kDebugInputBindlessMaxDescSets)); + const uint32_t desc_cmp_id = inst->result_id(); + + uint32_t error_blk_id = TakeNextId(); + uint32_t merge_blk_id = TakeNextId(); + std::unique_ptr merge_label(NewLabel(merge_blk_id)); + std::unique_ptr error_label(NewLabel(error_blk_id)); + (void)builder.AddConditionalBranch(desc_cmp_id, error_blk_id, merge_blk_id, + merge_blk_id); + func->AddBasicBlock(std::move(new_blk_ptr)); + + // error return + new_blk_ptr = MakeUnique(std::move(error_label)); + builder.SetInsertPoint(&*new_blk_ptr); + (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, + builder.GetUintConstantId(0)); + func->AddBasicBlock(std::move(new_blk_ptr)); + + // check descriptor set table entry is non-null + new_blk_ptr = MakeUnique(std::move(merge_label)); + builder.SetInsertPoint(&*new_blk_ptr); + + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + const uint32_t desc_set_ptr_ptr = type_mgr->FindPointerToType( + desc_set_ptr_id_, spv::StorageClass::StorageBuffer); + + inst = builder.AddAccessChain(desc_set_ptr_ptr, input_buffer_id_, + {builder.GetUintConstantId(0), param_ids[0]}); + 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(); + + 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, + builder.GetUintConstantId(0)); + 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, + builder.GetUintConstantId(0)); + 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(); + + error_blk_id = TakeNextId(); + merge_blk_id = TakeNextId(); + merge_label = NewLabel(merge_blk_id); + error_label = NewLabel(error_blk_id); + (void)builder.AddConditionalBranch(is_null_id, error_blk_id, merge_blk_id, + merge_blk_id); + func->AddBasicBlock(std::move(new_blk_ptr)); + // error return + new_blk_ptr = MakeUnique(std::move(error_label)); + builder.SetInsertPoint(&*new_blk_ptr); + (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, + builder.GetUintConstantId(0)); + func->AddBasicBlock(std::move(new_blk_ptr)); + + // check binding is in range + new_blk_ptr = MakeUnique(std::move(merge_label)); + builder.SetInsertPoint(&*new_blk_ptr); + + const uint32_t uint_ptr = type_mgr->FindPointerToType( + GetUintId(), spv::StorageClass::PhysicalStorageBuffer); + + inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id, + {builder.GetUintConstantId(0)}); + 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(); + + inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual, + param_ids[1], num_bindings_id); + const uint32_t bindings_cmp_id = inst->result_id(); + + error_blk_id = TakeNextId(); + merge_blk_id = TakeNextId(); + merge_label = NewLabel(merge_blk_id); + error_label = NewLabel(error_blk_id); + (void)builder.AddConditionalBranch(bindings_cmp_id, error_blk_id, + merge_blk_id, merge_blk_id); + func->AddBasicBlock(std::move(new_blk_ptr)); + // error return + new_blk_ptr = MakeUnique(std::move(error_label)); + builder.SetInsertPoint(&*new_blk_ptr); + (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, + builder.GetUintConstantId(0)); + func->AddBasicBlock(std::move(new_blk_ptr)); + + // read binding length + new_blk_ptr = MakeUnique(std::move(merge_label)); + builder.SetInsertPoint(&*new_blk_ptr); + + inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id, + {{builder.GetUintConstantId(1), param_ids[1]}}); + 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[2], length_id); + const uint32_t desc_idx_range_id = inst->result_id(); + + error_blk_id = TakeNextId(); + merge_blk_id = TakeNextId(); + merge_label = NewLabel(merge_blk_id); + error_label = NewLabel(error_blk_id); + (void)builder.AddConditionalBranch(desc_idx_range_id, error_blk_id, + merge_blk_id, merge_blk_id); + func->AddBasicBlock(std::move(new_blk_ptr)); + // Error return + new_blk_ptr = MakeUnique(std::move(error_label)); + builder.SetInsertPoint(&*new_blk_ptr); + (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, + builder.GetUintConstantId(0)); + func->AddBasicBlock(std::move(new_blk_ptr)); + + // Read descriptor init status + new_blk_ptr = MakeUnique(std::move(merge_label)); + builder.SetInsertPoint(&*new_blk_ptr); + + inst = builder.AddIAdd(GetUintId(), num_bindings_id, param_ids[1]); + 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[2]); + 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(); + + (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, init_status_id); + + func->AddBasicBlock(std::move(new_blk_ptr)); + func->SetFunctionEnd(EndFunction()); + + context()->AddFunction(std::move(func)); + context()->AddDebug2Inst(NewGlobalName(func_id, "read_desc_init")); + + read_init_func_id_ = func_id; + // Make sure function doesn't get processed by + // InstrumentPass::InstProcessCallTreeFromRoots() + param2output_func_id_[3] = func_id; + return read_init_func_id_; +} + +// clang-format off +// GLSL: +// result = inst_bindless_read_desc_init(desc_set_id, binding_id, desc_idx_id); +// +// clang-format on uint32_t InstBindlessCheckPass::GenDebugReadInit(uint32_t var_id, uint32_t desc_idx_id, InstructionBuilder* builder) { - uint32_t binding_idx_id = builder->GetUintConstantId(var2binding_[var_id]); - uint32_t u_desc_idx_id = GenUintCastCode(desc_idx_id, builder); - // If desc index checking is not enabled, we know the offset of initialization - // entries is 1, so we can avoid loading this value and just add 1 to the - // descriptor set. - if (!desc_idx_enabled_) { - uint32_t desc_set_idx_id = - builder->GetUintConstantId(var2desc_set_[var_id] + 1); - return GenDebugDirectRead({desc_set_idx_id, binding_idx_id, u_desc_idx_id}, - builder); - } else { - uint32_t desc_set_base_id = - builder->GetUintConstantId(kDebugInputBindlessInitOffset); - uint32_t desc_set_idx_id = - builder->GetUintConstantId(var2desc_set_[var_id]); - return GenDebugDirectRead( - {desc_set_base_id, desc_set_idx_id, binding_idx_id, u_desc_idx_id}, - builder); - } + const uint32_t func_id = GenDebugReadInitFunctionId(); + const std::vector args = { + builder->GetUintConstantId(var2desc_set_[var_id]), + builder->GetUintConstantId(var2binding_[var_id]), + GenUintCastCode(desc_idx_id, builder)}; + return GenReadFunctionCall(func_id, args, builder); } uint32_t InstBindlessCheckPass::CloneOriginalImage( diff --git a/source/opt/inst_bindless_check_pass.h b/source/opt/inst_bindless_check_pass.h index e6e6ef4f98..37d2b29e87 100644 --- a/source/opt/inst_bindless_check_pass.h +++ b/source/opt/inst_bindless_check_pass.h @@ -110,10 +110,14 @@ class InstBindlessCheckPass : public InstrumentPass { UptrVectorIterator ref_block_itr, uint32_t stage_idx, std::vector>* new_blocks); + void SetupInputBufferIds(); + uint32_t GenDebugReadLengthFunctionId(); + // Generate instructions into |builder| to read length of runtime descriptor // array |var_id| from debug input buffer and return id of value. uint32_t GenDebugReadLength(uint32_t var_id, InstructionBuilder* builder); + uint32_t GenDebugReadInitFunctionId(); // Generate instructions into |builder| to read initialization status of // descriptor array |image_id| at |index_id| from debug input buffer and // return id of value. @@ -201,6 +205,13 @@ class InstBindlessCheckPass : public InstrumentPass { // Mapping from variable to binding std::unordered_map var2binding_; + + uint32_t read_length_func_id_{0}; + uint32_t read_init_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}; }; } // namespace opt diff --git a/source/opt/inst_buff_addr_check_pass.cpp b/source/opt/inst_buff_addr_check_pass.cpp index c18f91d7fd..495470652f 100644 --- a/source/opt/inst_buff_addr_check_pass.cpp +++ b/source/opt/inst_buff_addr_check_pass.cpp @@ -19,6 +19,24 @@ 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) diff --git a/source/opt/inst_buff_addr_check_pass.h b/source/opt/inst_buff_addr_check_pass.h index fb43c397a5..2ec212bf87 100644 --- a/source/opt/inst_buff_addr_check_pass.h +++ b/source/opt/inst_buff_addr_check_pass.h @@ -41,6 +41,9 @@ 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 alignment of type |type_id|. Must be int, float, vector, // matrix, struct, array or physical pointer. Uses std430 alignment. diff --git a/source/opt/instrument_pass.cpp b/source/opt/instrument_pass.cpp index c6e405051d..9233ffd7fb 100644 --- a/source/opt/instrument_pass.cpp +++ b/source/opt/instrument_pass.cpp @@ -564,6 +564,19 @@ analysis::RuntimeArray* InstrumentPass::GetRuntimeArray( return type->AsRuntimeArray(); } +analysis::Array* InstrumentPass::GetArray(const analysis::Type* element, + uint32_t length) { + uint32_t length_id = context()->get_constant_mgr()->GetUIntConstId(length); + analysis::Array::LengthInfo length_info{ + length_id, {analysis::Array::LengthInfo::Case::kConstant, length}}; + + analysis::Array r(element, length_info); + + analysis::Type* type = context()->get_type_mgr()->GetRegisteredType(&r); + assert(type && type->AsArray()); + return type->AsArray(); +} + analysis::Function* InstrumentPass::GetFunction( const analysis::Type* return_val, const std::vector& args) { diff --git a/source/opt/instrument_pass.h b/source/opt/instrument_pass.h index 13119297cb..4bbbb09813 100644 --- a/source/opt/instrument_pass.h +++ b/source/opt/instrument_pass.h @@ -270,6 +270,7 @@ class InstrumentPass : public Pass { analysis::Integer* GetInteger(uint32_t width, bool is_signed); analysis::Struct* GetStruct(const std::vector& fields); analysis::RuntimeArray* GetRuntimeArray(const analysis::Type* element); + analysis::Array* GetArray(const analysis::Type* element, uint32_t size); analysis::Function* GetFunction( const analysis::Type* return_val, const std::vector& args); @@ -339,8 +340,8 @@ class InstrumentPass : public Pass { // If code is generated for an instruction, replace the instruction's // block with the new blocks that are generated. Continue processing at the // top of the last new block. - bool InstrumentFunction(Function* func, uint32_t stage_idx, - InstProcessFunction& pfn); + virtual bool InstrumentFunction(Function* func, uint32_t stage_idx, + InstProcessFunction& pfn); // Call |pfn| on all functions in the call tree of the function // ids in |roots|. diff --git a/source/opt/ir_builder.h b/source/opt/ir_builder.h index 93289a61a7..48e08ee7af 100644 --- a/source/opt/ir_builder.h +++ b/source/opt/ir_builder.h @@ -480,9 +480,16 @@ class InstructionBuilder { return AddInstruction(std::move(new_inst)); } - Instruction* AddLoad(uint32_t type_id, uint32_t base_ptr_id) { + Instruction* AddLoad(uint32_t type_id, uint32_t base_ptr_id, + uint32_t alignment = 0) { std::vector operands; operands.push_back({SPV_OPERAND_TYPE_ID, {base_ptr_id}}); + if (alignment != 0) { + operands.push_back( + {SPV_OPERAND_TYPE_MEMORY_ACCESS, + {static_cast(spv::MemoryAccessMask::Aligned)}}); + operands.push_back({SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER, {alignment}}); + } // TODO(1841): Handle id overflow. std::unique_ptr new_inst( diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp index 5ee6eed492..9fe4f4021a 100644 --- a/test/opt/inst_bindless_check_test.cpp +++ b/test/opt/inst_bindless_check_test.cpp @@ -252,6 +252,9 @@ static const std::string kStreamWrite5Vert = kStreamWrite5Begin + R"( // 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 @@ -259,61 +262,90 @@ static const std::string kInputDecorations = R"( )"; static const std::string kInputGlobals = R"( -; CHECK: [[input_buffer_type]] = OpTypeStruct %_runtimearr_uint +; 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 kDirectRead2 = R"( -; CHECK: %inst_bindless_direct_read_2 = OpFunction %uint None {{%\w+}} -; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint +static const std::string kReadBindingLength = R"( +; CHECK: %inst_bindless_read_binding_length = OpFunction %uint None {{%\w+}} +; CHECK: [[bl_desc_set_idx:%\w+]] = OpFunctionParameter %uint +; CHECK: [[bl_binding_idx:%\w+]] = OpFunctionParameter %uint +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[bl_desc_set_idx]] %uint_32 +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: OpReturnValue %uint_0 +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData %inst_bindless_input_buffer %uint_0 [[bl_desc_set_idx]] +; CHECK: {{%\w+}} = OpLoad %_ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData {{%\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: OpReturnValue %uint_0 +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_0 +; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 8 +; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[bl_binding_idx]] {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: OpReturnValue %uint_0 ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 [[param_1]] -; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} [[param_2]] -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} +; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 [[bl_binding_idx]] +; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 4 ; CHECK: OpReturnValue {{%\w+}} ; CHECK: OpFunctionEnd )"; -static const std::string kDirectRead3 = R"( - ;CHECK: %inst_bindless_direct_read_3 = OpFunction %uint None {{%\w+}} -; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint - ;CHECK: {{%\w+}} = OpLabel - ;CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 [[param_1]] - ;CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} - ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} [[param_2]] - ;CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 {{%\w+}} - ;CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} - ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} [[param_3]] - ;CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 {{%\w+}} - ;CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} - ;CHECK: OpReturnValue {{%\w+}} - ;CHECK: OpFunctionEnd -)"; - -static const std::string kDirectRead4 = R"( -; CHECK: %inst_bindless_direct_read_4 = OpFunction %uint None {{%\w+}} -; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint +static const std::string kReadDescInit = R"( +; CHECK: %inst_bindless_read_desc_init = OpFunction %uint None {{%\w+}} +; CHECK: [[di_desc_set_idx:%\w+]] = OpFunctionParameter %uint +; CHECK: [[di_binding_idx:%\w+]] = OpFunctionParameter %uint +; CHECK: [[di_desc_idx:%\w+]] = OpFunctionParameter %uint +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_desc_set_idx]] %uint_32 +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: OpReturnValue %uint_0 +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData %inst_bindless_input_buffer %uint_0 [[di_desc_set_idx]] +; CHECK: {{%\w+}} = OpLoad %_ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData {{%\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: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 [[param_1]] -; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} [[param_2]] -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} [[param_3]] -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} [[param_4]] -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[input_buffer_var]] %uint_0 {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} +; CHECK: OpReturnValue %uint_0 +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_0 +; CHECK: [[di_num_bindings:%\w+]] = OpLoad %uint {{%\w+}} Aligned 8 +; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_binding_idx]] [[di_num_bindings]] +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: OpReturnValue %uint_0 +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 {{%\w+}} +; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 4 +; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 {{%\w+}} +; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 4 ; CHECK: OpReturnValue {{%\w+}} ; CHECK: OpFunctionEnd )"; @@ -589,20 +621,20 @@ OpDecorate %_entryPointOutput_vColor Location 0 OpStore %_entryPointOutput_vColor %37 ; CHECK-NOT: %37 = OpImageSampleImplicitLod %v4float %36 %30 ; CHECK-NOT: OpStore %_entryPointOutput_vColor %37 -; CHECK: %40 = OpULessThan %bool %32 %uint_128 -; CHECK: OpSelectionMerge %41 None -; CHECK: OpBranchConditional %40 %42 %43 -; CHECK: %42 = OpLabel -; CHECK: %44 = OpLoad %16 %33 -; CHECK: %45 = OpSampledImage %26 %44 %35 -; CHECK: %46 = OpImageSampleImplicitLod %v4float %45 %30 -; CHECK: OpBranch %41 -; CHECK: %43 = OpLabel +; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} %uint_128 +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_56 %uint_0 %32 %uint_128 -; CHECK: OpBranch %41 -; CHECK: %41 = OpLabel -; CHECK: %104 = OpPhi %v4float %46 %42 [[null_v4float]] %43 -; CHECK: OpStore %_entryPointOutput_vColor %104 +; 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 )"; @@ -1566,12 +1598,7 @@ 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: %41 = OpTypeFunction %uint %uint %uint -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ; CHECK: %v4uint = OpTypeVector %uint 4 @@ -1593,39 +1620,40 @@ OpDecorate %_entryPointOutput_vColor Location 0 OpStore %_entryPointOutput_vColor %71 ; CHECK-NOT: %71 = OpImageSampleImplicitLod %v4float %68 %53 ; CHECK-NOT: OpStore %_entryPointOutput_vColor %71 -; CHECK: %55 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_2 %uint_2 -; CHECK: %57 = OpULessThan %bool %32 %55 -; CHECK: OpSelectionMerge %58 None -; CHECK: OpBranchConditional %57 %59 %60 -; CHECK: %59 = OpLabel -; CHECK: %61 = OpLoad %16 %33 -; CHECK: %62 = OpSampledImage %26 %61 %35 -; CHECK: %136 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_1 %uint_2 %32 -; CHECK: %137 = OpULessThan %bool %uint_0 %136 -; CHECK: OpSelectionMerge %138 None -; CHECK: OpBranchConditional %137 %139 %140 -; CHECK: %139 = OpLabel -; CHECK: %141 = OpLoad %16 %33 -; CHECK: %142 = OpSampledImage %26 %141 %35 -; CHECK: %143 = OpImageSampleImplicitLod %v4float %142 %30 -; CHECK: OpBranch %138 -; CHECK: %140 = OpLabel -; CHECK: %144 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_59 %uint_1 %32 %uint_0 -; CHECK: OpBranch %138 -; CHECK: %138 = OpLabel -; CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float %143 %139 [[null_v4float]] %140 -; CHECK: OpBranch %58 -; CHECK: %60 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_59 %uint_0 %32 %55 -; CHECK: OpBranch %58 -; CHECK: %58 = OpLabel -; CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float [[phi_result_1]] %138 [[null_v4float]] %60 +; CHECK: [[length_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_1 %uint_2 +; CHECK: {{%\w+}} = OpULessThan %bool %32 [[length_result]] +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpLoad %16 %33 +; CHECK: {{%\w+}} = OpSampledImage %26 {{%\w+}} %35 +; CHECK: [[state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %32 +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[state_result]] +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_59 %uint_1 %32 %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_59 %uint_0 %32 {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float [[phi_result_1]] {{%\w+}} [[null_v4float]] {{%\w+}} ; CHECK: OpStore %_entryPointOutput_vColor [[phi_result_2]] OpReturn OpFunctionEnd )"; - const std::string new_funcs = kDirectRead2 + kStreamWrite4Frag + kDirectRead4; + const std::string new_funcs = + kReadBindingLength + kStreamWrite4Frag + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -1681,13 +1709,7 @@ 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: %uint = OpTypeInt 32 0 -; CHECK: %28 = OpTypeFunction %uint %uint %uint %uint %uint -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ; CHECK: %v4uint = OpTypeVector %uint 4 @@ -1706,26 +1728,26 @@ OpDecorate %_entryPointOutput_vColor Location 0 OpStore %_entryPointOutput_vColor %24 ; CHECK-NOT: %24 = OpImageSampleImplicitLod %v4float %23 %20 ; CHECK-NOT: OpStore %_entryPointOutput_vColor %24 -; CHECK: %50 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -; CHECK: %52 = OpULessThan %bool %uint_0 %50 -; CHECK: OpSelectionMerge %54 None -; CHECK: OpBranchConditional %52 %55 %56 -; CHECK: %55 = OpLabel -; CHECK: %57 = OpLoad %12 %g_tColor -; CHECK: %58 = OpSampledImage %16 %57 %22 -; CHECK: %59 = OpImageSampleImplicitLod %v4float %58 %20 -; CHECK: OpBranch %54 -; CHECK: %56 = OpLabel +; CHECK: [[state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[state_result]] +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_39 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %54 -; CHECK: %54 = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %v4float %59 %55 [[null_v4float]] %56 +; 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 = kDirectRead4 + kStreamWrite4Frag; + const std::string new_funcs = kReadDescInit + kStreamWrite4Frag; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -1896,10 +1918,10 @@ OpDecorate %16 NonUniform OpDecorate %20 NonUniform ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + R"( -; CHECK: OpDecorate %130 NonUniform +; CHECK: OpDecorate {{%\w+}} NonUniform )" + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -; CHECK: OpDecorate %127 NonUniform +; CHECK: OpDecorate {{%\w+}} NonUniform %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -1914,13 +1936,7 @@ OpDecorate %20 NonUniform %nu_ii = OpVariable %_ptr_Input_int Input %int_0 = OpConstant %int 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -; CHECK: %uint = OpTypeInt 32 0 -; CHECK: %26 = OpTypeFunction %uint %uint %uint -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: %v4float = OpTypeVector %float 4 ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input @@ -1938,38 +1954,39 @@ OpDecorate %20 NonUniform OpStore %b %20 ; CHECK-NOT: %20 = OpLoad %float %19 ; CHECK-NOT: OpStore %b %20 -; CHECK: %40 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_3 -; CHECK: %42 = OpULessThan %bool %7 %40 -; CHECK: OpSelectionMerge %43 None -; CHECK: OpBranchConditional %42 %44 %45 -; CHECK: %44 = OpLabel -; CHECK: %103 = OpBitcast %uint %7 -; CHECK: %122 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_3 %103 -; CHECK: %123 = OpULessThan %bool %uint_0 %122 -; CHECK: OpSelectionMerge %124 None -; CHECK: OpBranchConditional %123 %125 %126 -; CHECK: %125 = OpLabel -; CHECK: %127 = OpLoad %float %20 -; CHECK: OpBranch %124 -; CHECK: %126 = OpLabel -; CHECK: %128 = OpBitcast %uint %7 -; CHECK: %129 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 %128 %uint_0 -; CHECK: OpBranch %124 -; CHECK: %124 = OpLabel -; CHECK: [[phi_result_1:%\w+]] = OpPhi %float %127 %125 [[null_float]] %126 -; CHECK: OpBranch %43 -; CHECK: %45 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_3 +; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpBitcast %uint %7 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_3 {{%\w+}} +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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: {{%\w+}} = OpBitcast %uint %7 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 {{%\w+}} %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel ; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result]] %40 -; CHECK: OpBranch %43 -; CHECK: %43 = OpLabel -; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] %124 [[null_float]] %45 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result]] {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}} ; CHECK: OpStore %b [[phi_result_2]] OpReturn OpFunctionEnd )"; - const std::string new_funcs = kDirectRead2 + kStreamWrite4Frag + kDirectRead4; + const std::string new_funcs = + kReadBindingLength + kStreamWrite4Frag + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -2023,11 +2040,8 @@ OpDecorate %nu_ii NonUniform OpDecorate %16 NonUniform OpDecorate %20 NonUniform ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + R"( -; CHECK: OpDecorate %130 NonUniform -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -; CHECK: OpDecorate %127 NonUniform %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -2043,12 +2057,8 @@ OpDecorate %20 NonUniform %int_0 = OpConstant %int 0 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float ; CHECK: %uint = OpTypeInt 32 0 -; CHECK: %26 = OpTypeFunction %uint %uint %uint ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: %v4float = OpTypeVector %float 4 ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input @@ -2066,38 +2076,39 @@ OpDecorate %20 NonUniform OpStore %b %20 ; CHECK-NOT: %20 = OpLoad %float %19 ; CHECK-NOT: OpStore %b %20 -; CHECK: %40 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_3 -; CHECK: %42 = OpULessThan %bool %7 %40 -; CHECK: OpSelectionMerge %43 None -; CHECK: OpBranchConditional %42 %44 %45 -; CHECK: %44 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_3 +; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel ; CHECK: [[bitcast_result_1:%\w+]] = OpBitcast %uint %7 -; CHECK: %122 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_3 [[bitcast_result_1]] -; CHECK: %123 = OpULessThan %bool %uint_0 %122 -; CHECK: OpSelectionMerge %124 None -; CHECK: OpBranchConditional %123 %125 %126 -; CHECK: %125 = OpLabel -; CHECK: %127 = OpLoad %float %20 -; CHECK: OpBranch %124 -; CHECK: %126 = OpLabel -; CHECK: %128 = OpBitcast %uint %7 -; CHECK: %129 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 %128 %uint_0 -; CHECK: OpBranch %124 -; CHECK: %124 = OpLabel -; CHECK: [[phi_result_1:%\w+]] = OpPhi %float %127 %125 [[null_float]] %126 -; CHECK: OpBranch %43 -; CHECK: %45 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_3 [[bitcast_result_1]] +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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: {{%\w+}} = OpBitcast %uint %7 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 {{%\w+}} %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel ; CHECK: [[bitcast_result_2:%\w+]] = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result_2]] %40 -; CHECK: OpBranch %43 -; CHECK: %43 = OpLabel -; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] %124 [[null_float]] %45 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result_2]] {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}} ; CHECK: OpStore %b [[phi_result_2]] OpReturn OpFunctionEnd )"; - const std::string new_funcs = kDirectRead2 + kStreamWrite4Frag + kDirectRead4; + const std::string new_funcs = + kReadBindingLength + kStreamWrite4Frag + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -2141,10 +2152,10 @@ OpDecorate %16 NonUniform OpDecorate %20 NonUniform ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + R"( -; CHECK: OpDecorate %130 NonUniform +; CHECK: OpDecorate {{%\w+}} NonUniform )" + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -; CHECK: OpDecorate %127 NonUniform +; CHECK: OpDecorate {{%\w+}} NonUniform %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -2159,13 +2170,7 @@ 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: %26 = OpTypeFunction %uint %uint %uint -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: %v4float = OpTypeVector %float 4 ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input @@ -2183,38 +2188,39 @@ OpDecorate %20 NonUniform OpStore %b %20 ; CHECK-NOT: %20 = OpLoad %float %19 ; CHECK-NOT: OpStore %b %20 -; CHECK: %40 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_3 -; CHECK: %42 = OpULessThan %bool %7 %40 -; CHECK: OpSelectionMerge %43 None -; CHECK: OpBranchConditional %42 %44 %45 -; CHECK: %44 = OpLabel -; CHECK: %103 = OpBitcast %uint %7 -; CHECK: %122 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_3 %103 -; CHECK: %123 = OpULessThan %bool %uint_0 %122 -; CHECK: OpSelectionMerge %124 None -; CHECK: OpBranchConditional %123 %125 %126 -; CHECK: %125 = OpLabel -; CHECK: %127 = OpLoad %float %20 -; CHECK: OpBranch %124 -; CHECK: %126 = OpLabel -; CHECK: %128 = OpBitcast %uint %7 -; CHECK: %129 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 %128 %uint_0 -; CHECK: OpBranch %124 -; CHECK: %124 = OpLabel -; CHECK: [[phi_result_1:%\w+]] = OpPhi %float %127 %125 [[null_float]] %126 -; CHECK: OpBranch %43 -; CHECK: %45 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_3 +; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpBitcast %uint %7 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_3 {{%\w+}} +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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: {{%\w+}} = OpBitcast %uint %7 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 {{%\w+}} %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel ; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result]] %40 -; CHECK: OpBranch %43 -; CHECK: %43 = OpLabel -; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] %124 [[null_float]] %45 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result]] {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}} ; CHECK: OpStore %b [[phi_result_2]] OpReturn OpFunctionEnd )"; - const std::string new_funcs = kDirectRead2 + kStreamWrite4Frag + kDirectRead4; + const std::string new_funcs = + kReadBindingLength + kStreamWrite4Frag + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -2273,12 +2279,8 @@ OpDecorate %uniformBuffer Binding 3 ; CHECK: %int = OpTypeInt 32 1 ; CHECK: %_ptr_Uniform_float = OpTypePointer Uniform %float ; CHECK: %uint = OpTypeInt 32 0 -; CHECK: %21 = OpTypeFunction %uint %uint %uint %uint %uint ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint -; CHECK: %bool = OpTypeBool -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: %v4float = OpTypeVector %float 4 ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input @@ -2295,24 +2297,24 @@ OpDecorate %uniformBuffer Binding 3 OpStore %b %16 ; CHECK-NOT: %16 = OpLoad %float %15 ; CHECK-NOT: OpStore %b %16 -; CHECK: %43 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_3 %uint_0 -; CHECK: %45 = OpULessThan %bool %uint_0 %43 -; CHECK: OpSelectionMerge %47 None -; CHECK: OpBranchConditional %45 %48 %49 -; CHECK: %48 = OpLabel -; CHECK: %50 = OpLoad %float %15 -; CHECK: OpBranch %47 -; CHECK: %49 = OpLabel +; CHECK: [[check_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_3 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[check_result]] +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpLoad %float %15 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_32 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %47 -; CHECK: %47 = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %float %50 %48 [[null_float]] %49 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}} ; CHECK: OpStore %b [[phi_result]] OpReturn OpFunctionEnd )"; - const std::string new_funcs = kDirectRead4 + kStreamWrite4Frag; + const std::string new_funcs = kReadDescInit + kStreamWrite4Frag; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -2383,7 +2385,6 @@ OpDecorate %b Location 1 )" + kInputGlobals + kOutputGlobals + R"( ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input ; CHECK: %v4uint = OpTypeVector %uint 4 -; CHECK: %102 = OpTypeFunction %uint %uint %uint %uint %uint )"; // clang-format on @@ -2395,35 +2396,36 @@ OpDecorate %b Location 1 %20 = OpAccessChain %_ptr_Uniform_float %storageBuffer %14 %int_0 OpStore %20 %18 ; CHECK-NOT: OpStore %20 %18 -; CHECK: %40 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_4 -; CHECK: %42 = OpULessThan %bool %7 %40 -; CHECK: OpSelectionMerge %43 None -; CHECK: OpBranchConditional %42 %44 %45 -; CHECK: %44 = OpLabel -; CHECK: %100 = OpBitcast %uint %7 -; CHECK: %119 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_4 %100 -; CHECK: %120 = OpULessThan %bool %uint_0 %119 -; CHECK: OpSelectionMerge %121 None -; CHECK: OpBranchConditional %120 %122 %123 -; CHECK: %122 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_4 +; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpBitcast %uint %7 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_4 {{%\w+}} +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel ; CHECK: OpStore %20 %19 -; CHECK: OpBranch %121 -; CHECK: %123 = OpLabel -; CHECK: %124 = OpBitcast %uint %7 -; CHECK: %125 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 %124 %uint_0 -; CHECK: OpBranch %121 -; CHECK: %121 = OpLabel -; CHECK: OpBranch %43 -; CHECK: %45 = OpLabel -; CHECK: %46 = OpBitcast %uint %7 -; CHECK: %99 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 %46 %40 -; CHECK: OpBranch %43 -; CHECK: %43 = OpLabel +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpBitcast %uint %7 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 {{%\w+}} %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpBitcast %uint %7 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 {{%\w+}} {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - const std::string new_funcs = kDirectRead2 + kStreamWrite4Frag + kDirectRead4; + const std::string new_funcs = + kReadBindingLength + kStreamWrite4Frag + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -2479,7 +2481,7 @@ OpDecorate %22 NonUniform )" + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord )" + kInputDecorations + R"( -; CHECK: OpDecorate %117 NonUniform +; CHECK: OpDecorate [[load_result:%\w+]] NonUniform %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -2514,37 +2516,37 @@ OpDecorate %22 NonUniform OpStore %b %22 ; CHECK-NOT: %22 = OpLoad %float %21 ; CHECK-NOT: OpStore %b %22 -; CHECK: %25 = OpULessThan %bool %7 %uint_128 -; CHECK: OpSelectionMerge %26 None -; CHECK: OpBranchConditional %25 %27 %28 -; CHECK: %27 = OpLabel -; CHECK: %90 = OpBitcast %uint %7 -; CHECK: %112 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_3 %90 -; CHECK: %113 = OpULessThan %bool %uint_0 %112 -; CHECK: OpSelectionMerge %114 None -; CHECK: OpBranchConditional %113 %115 %116 -; CHECK: %115 = OpLabel -; CHECK: %117 = OpLoad %float %22 -; CHECK: OpBranch %114 -; CHECK: %116 = OpLabel -; CHECK: %118 = OpBitcast %uint %7 -; CHECK: %119 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_46 %uint_1 %118 %uint_0 -; CHECK: OpBranch %114 -; CHECK: %114 = OpLabel -; CHECK: [[phi_result_1:%\w+]] = OpPhi %float %117 %115 [[null_float]] %116 -; CHECK: OpBranch %26 -; CHECK: %28 = OpLabel +; CHECK: {{%\w+}} = OpULessThan %bool %7 %uint_128 +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpBitcast %uint %7 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_3 {{%\w+}} +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: [[load_result]] = OpLoad %float %22 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpBitcast %uint %7 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_46 %uint_1 {{%\w+}} %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel ; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %7 ; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_46 %uint_0 [[bitcast_result]] %uint_128 -; CHECK: OpBranch %26 -; CHECK: %26 = OpLabel -; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] %114 [[null_float]] %28 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}} ; CHECK: OpStore %b [[phi_result_2]] OpReturn OpFunctionEnd )"; - const std::string new_funcs = kStreamWrite4Frag + kDirectRead4; + const std::string new_funcs = kStreamWrite4Frag + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -2643,64 +2645,64 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: %132 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -; CHECK: %133 = OpULessThan %bool %uint_0 %132 -; CHECK: OpSelectionMerge %134 None -; CHECK: OpBranchConditional %133 %135 %136 -; CHECK: %135 = OpLabel -; CHECK: %137 = OpLoad %uint %25 -; CHECK: OpBranch %134 -; CHECK: %136 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_47 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %134 -; CHECK: %134 = OpLabel -; CHECK: [[phi_result_1:%\w+]] = OpPhi %uint %137 %135 [[null_uint]] %136 -; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %141 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: [[phi_result_1:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} +; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} ; CHECK: %28 = OpLoad %13 %27 -; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1 -; CHECK: %50 = OpULessThan %bool %141 %48 -; CHECK: OpSelectionMerge %51 None -; CHECK: OpBranchConditional %50 %52 %53 -; CHECK: %52 = OpLabel -; CHECK: %54 = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_1 [[phi_result_1]] -; CHECK: %143 = OpULessThan %bool %uint_0 %142 -; CHECK: OpSelectionMerge %144 None -; CHECK: OpBranchConditional %143 %145 %146 -; CHECK: %145 = OpLabel -; CHECK: %147 = OpLoad %13 %27 -; CHECK: %148 = OpImageRead %v4float %147 %20 -; CHECK: OpBranch %144 -; CHECK: %146 = OpLabel -; CHECK: %149 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_50 %uint_1 %141 %uint_0 -; CHECK: OpBranch %144 -; CHECK: %144 = OpLabel -; CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float %148 %145 [[null_v4float]] %146 -; CHECK: OpBranch %51 -; CHECK: %53 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_50 %uint_0 %141 %48 -; CHECK: OpBranch %51 -; CHECK: %51 = OpLabel -; CHECK: %113 = OpPhi %v4float [[phi_result_2]] %144 [[null_v4float]] %53 -; CHECK: %30 = OpCompositeExtract %float %113 0 -; CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 -; CHECK: %151 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -; CHECK: %152 = OpULessThan %bool %uint_0 %151 -; CHECK: OpSelectionMerge %153 None -; CHECK: OpBranchConditional %152 %154 %155 -; CHECK: %154 = OpLabel -; CHECK: OpStore %31 %30 -; CHECK: OpBranch %153 -; CHECK: %155 = OpLabel -; CHECK: %157 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_53 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %153 -; CHECK: %153 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1 +; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpLoad %13 %27 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 [[phi_result_1]] +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_50 %uint_1 {{%\w+}} %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_50 %uint_0 {{%\w+}} {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpPhi %v4float [[phi_result_2]] {{%\w+}} [[null_v4float]] {{%\w+}} +; CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0 +; CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1 +; CHECK: [[desc_state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[desc_state_result]] +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: OpStore {{%\w+}} {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_53 %uint_1 %uint_0 %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; const std::string new_funcs = - kDirectRead2 + kStreamWrite4Compute + kDirectRead4; + kReadBindingLength + kStreamWrite4Compute + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -2796,63 +2798,64 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: %133 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -; CHECK: %134 = OpULessThan %bool %uint_0 %133 -; CHECK: OpSelectionMerge %135 None -; CHECK: OpBranchConditional %134 %136 %137 -; CHECK: %136 = OpLabel -; CHECK: %138 = OpLoad %uint %25 -; CHECK: OpBranch %135 -; CHECK: %137 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %135 -; CHECK: %135 = OpLabel -; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137 -; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} +; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} ; CHECK: %28 = OpLoad %13 %27 -; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1 -; CHECK: %50 = OpULessThan %bool %142 %48 -; CHECK: OpSelectionMerge %51 None -; CHECK: OpBranchConditional %50 %52 %53 -; CHECK: %52 = OpLabel -; CHECK: %54 = OpLoad %13 %27 -; CHECK: %143 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_1 %142 -; CHECK: %144 = OpULessThan %bool %uint_0 %143 -; CHECK: OpSelectionMerge %145 None -; CHECK: OpBranchConditional %144 %146 %147 -; CHECK: %146 = OpLabel -; CHECK: %148 = OpLoad %13 %27 -; CHECK: %149 = OpImageRead %v4float %148 %20 -; CHECK: OpBranch %145 -; CHECK: %147 = OpLabel -; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0 -; CHECK: OpBranch %145 -; CHECK: %145 = OpLabel -; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147 -; CHECK: OpBranch %51 -; CHECK: %53 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 -; CHECK: OpBranch %51 -; CHECK: %51 = OpLabel -; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53 -; CHECK: %30 = OpCompositeExtract %float %114 0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1 +; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpLoad %13 %27 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}} +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}} +; 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: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -; CHECK: %153 = OpULessThan %bool %uint_0 %152 -; CHECK: OpSelectionMerge %154 None -; CHECK: OpBranchConditional %153 %155 %156 -; CHECK: %155 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel ; CHECK: OpStore %31 %30 -; CHECK: OpBranch %154 -; CHECK: %156 = OpLabel -; CHECK: %158 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %154 -; CHECK: %154 = OpLabel +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - const std::string new_funcs = kDirectRead2 + kStreamWrite4Ray + kDirectRead4; + const std::string new_funcs = + kReadBindingLength + kStreamWrite4Ray + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -2949,63 +2952,64 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: %133 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -; CHECK: %134 = OpULessThan %bool %uint_0 %133 -; CHECK: OpSelectionMerge %135 None -; CHECK: OpBranchConditional %134 %136 %137 -; CHECK: %136 = OpLabel -; CHECK: %138 = OpLoad %uint %25 -; CHECK: OpBranch %135 -; CHECK: %137 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %135 -; CHECK: %135 = OpLabel -; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137 -; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} +; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} ; CHECK: %28 = OpLoad %13 %27 -; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1 -; CHECK: %50 = OpULessThan %bool %142 %48 -; CHECK: OpSelectionMerge %51 None -; CHECK: OpBranchConditional %50 %52 %53 -; CHECK: %52 = OpLabel -; CHECK: %54 = OpLoad %13 %27 -; CHECK: %143 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_1 %142 -; CHECK: %144 = OpULessThan %bool %uint_0 %143 -; CHECK: OpSelectionMerge %145 None -; CHECK: OpBranchConditional %144 %146 %147 -; CHECK: %146 = OpLabel -; CHECK: %148 = OpLoad %13 %27 -; CHECK: %149 = OpImageRead %v4float %148 %20 -; CHECK: OpBranch %145 -; CHECK: %147 = OpLabel -; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0 -; CHECK: OpBranch %145 -; CHECK: %145 = OpLabel -; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147 -; CHECK: OpBranch %51 -; CHECK: %53 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 -; CHECK: OpBranch %51 -; CHECK: %51 = OpLabel -; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53 -; CHECK: %30 = OpCompositeExtract %float %114 0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1 +; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpLoad %13 %27 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}} +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}} +; 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: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -; CHECK: %153 = OpULessThan %bool %uint_0 %152 -; CHECK: OpSelectionMerge %154 None -; CHECK: OpBranchConditional %153 %155 %156 -; CHECK: %155 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel ; CHECK: OpStore %31 %30 -; CHECK: OpBranch %154 -; CHECK: %156 = OpLabel -; CHECK: %158 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %154 -; CHECK: %154 = OpLabel +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - const std::string new_funcs = kDirectRead2 + kStreamWrite4Ray + kDirectRead4; + const std::string new_funcs = + kReadBindingLength + kStreamWrite4Ray + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -3102,63 +3106,64 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: %133 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -; CHECK: %134 = OpULessThan %bool %uint_0 %133 -; CHECK: OpSelectionMerge %135 None -; CHECK: OpBranchConditional %134 %136 %137 -; CHECK: %136 = OpLabel -; CHECK: %138 = OpLoad %uint %25 -; CHECK: OpBranch %135 -; CHECK: %137 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %135 -; CHECK: %135 = OpLabel -; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137 -; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} +; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} ; CHECK: %28 = OpLoad %13 %27 -; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1 -; CHECK: %50 = OpULessThan %bool %142 %48 -; CHECK: OpSelectionMerge %51 None -; CHECK: OpBranchConditional %50 %52 %53 -; CHECK: %52 = OpLabel -; CHECK: %54 = OpLoad %13 %27 -; CHECK: %143 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_1 %142 -; CHECK: %144 = OpULessThan %bool %uint_0 %143 -; CHECK: OpSelectionMerge %145 None -; CHECK: OpBranchConditional %144 %146 %147 -; CHECK: %146 = OpLabel -; CHECK: %148 = OpLoad %13 %27 -; CHECK: %149 = OpImageRead %v4float %148 %20 -; CHECK: OpBranch %145 -; CHECK: %147 = OpLabel -; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0 -; CHECK: OpBranch %145 -; CHECK: %145 = OpLabel -; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147 -; CHECK: OpBranch %51 -; CHECK: %53 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 -; CHECK: OpBranch %51 -; CHECK: %51 = OpLabel -; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53 -; CHECK: %30 = OpCompositeExtract %float %114 0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1 +; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpLoad %13 %27 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}} +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}} +; 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: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -; CHECK: %153 = OpULessThan %bool %uint_0 %152 -; CHECK: OpSelectionMerge %154 None -; CHECK: OpBranchConditional %153 %155 %156 -; CHECK: %155 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel ; CHECK: OpStore %31 %30 -; CHECK: OpBranch %154 -; CHECK: %156 = OpLabel -; CHECK: %158 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %154 -; CHECK: %154 = OpLabel +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - const std::string new_funcs = kDirectRead2 + kStreamWrite4Ray + kDirectRead4; + const std::string new_funcs = + kReadBindingLength + kStreamWrite4Ray + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -3255,63 +3260,64 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: %133 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -; CHECK: %134 = OpULessThan %bool %uint_0 %133 -; CHECK: OpSelectionMerge %135 None -; CHECK: OpBranchConditional %134 %136 %137 -; CHECK: %136 = OpLabel -; CHECK: %138 = OpLoad %uint %25 -; CHECK: OpBranch %135 -; CHECK: %137 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %135 -; CHECK: %135 = OpLabel -; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137 -; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +; 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: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1 -; CHECK: %50 = OpULessThan %bool %142 %48 -; CHECK: OpSelectionMerge %51 None -; CHECK: OpBranchConditional %50 %52 %53 -; CHECK: %52 = OpLabel -; CHECK: %54 = OpLoad %13 %27 -; CHECK: %143 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_1 %142 -; CHECK: %144 = OpULessThan %bool %uint_0 %143 -; CHECK: OpSelectionMerge %145 None -; CHECK: OpBranchConditional %144 %146 %147 -; CHECK: %146 = OpLabel -; CHECK: %148 = OpLoad %13 %27 -; CHECK: %149 = OpImageRead %v4float %148 %20 -; CHECK: OpBranch %145 -; CHECK: %147 = OpLabel -; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0 -; CHECK: OpBranch %145 -; CHECK: %145 = OpLabel -; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147 -; CHECK: OpBranch %51 -; CHECK: %53 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 -; CHECK: OpBranch %51 -; CHECK: %51 = OpLabel -; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53 -; CHECK: %30 = OpCompositeExtract %float %114 0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1 +; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpLoad %13 %27 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}} +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}} +; 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: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -; CHECK: %153 = OpULessThan %bool %uint_0 %152 -; CHECK: OpSelectionMerge %154 None -; CHECK: OpBranchConditional %153 %155 %156 -; CHECK: %155 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel ; CHECK: OpStore %31 %30 -; CHECK: OpBranch %154 -; CHECK: %156 = OpLabel -; CHECK: %158 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %154 -; CHECK: %154 = OpLabel +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - const std::string new_funcs = kDirectRead2 + kStreamWrite4Ray + kDirectRead4; + const std::string new_funcs = + kReadBindingLength + kStreamWrite4Ray + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -3408,63 +3414,64 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT OpStore %31 %29 -; CHECK: %133 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -; CHECK: %134 = OpULessThan %bool %uint_0 %133 -; CHECK: OpSelectionMerge %135 None -; CHECK: OpBranchConditional %134 %136 %137 -; CHECK: %136 = OpLabel -; CHECK: %138 = OpLoad %uint %25 -; CHECK: OpBranch %135 -; CHECK: %137 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %135 -; CHECK: %135 = OpLabel -; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137 -; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +; 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: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1 -; CHECK: %50 = OpULessThan %bool %142 %48 -; CHECK: OpSelectionMerge %51 None -; CHECK: OpBranchConditional %50 %52 %53 -; CHECK: %52 = OpLabel -; CHECK: %54 = OpLoad %13 %27 -; CHECK: %143 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_1 %142 -; CHECK: %144 = OpULessThan %bool %uint_0 %143 -; CHECK: OpSelectionMerge %145 None -; CHECK: OpBranchConditional %144 %146 %147 -; CHECK: %146 = OpLabel -; CHECK: %148 = OpLoad %13 %27 -; CHECK: %149 = OpImageRead %v4float %148 %20 -; CHECK: OpBranch %145 -; CHECK: %147 = OpLabel -; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0 -; CHECK: OpBranch %145 -; CHECK: %145 = OpLabel -; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147 -; CHECK: OpBranch %51 -; CHECK: %53 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 -; CHECK: OpBranch %51 -; CHECK: %51 = OpLabel -; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53 -; CHECK: %30 = OpCompositeExtract %float %114 0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1 +; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpLoad %13 %27 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}} +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}} +; 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: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -; CHECK: %153 = OpULessThan %bool %uint_0 %152 -; CHECK: OpSelectionMerge %154 None -; CHECK: OpBranchConditional %153 %155 %156 -; CHECK: %155 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel ; CHECK: OpStore %31 %30 -; CHECK: OpBranch %154 -; CHECK: %156 = OpLabel -; CHECK: %158 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %154 -; CHECK: %154 = OpLabel +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - const std::string new_funcs = kDirectRead2 + kStreamWrite4Ray + kDirectRead4; + const std::string new_funcs = + kReadBindingLength + kStreamWrite4Ray + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -3560,63 +3567,64 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: %133 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -; CHECK: %134 = OpULessThan %bool %uint_0 %133 -; CHECK: OpSelectionMerge %135 None -; CHECK: OpBranchConditional %134 %136 %137 -; CHECK: %136 = OpLabel -; CHECK: %138 = OpLoad %uint %25 -; CHECK: OpBranch %135 -; CHECK: %137 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %135 -; CHECK: %135 = OpLabel -; CHECK: %142 = OpPhi %uint %138 %136 [[null_uint]] %137 -; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images %142 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} +; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} ; CHECK: %28 = OpLoad %13 %27 -; CHECK: %48 = OpFunctionCall %uint %inst_bindless_direct_read_2 %uint_1 %uint_1 -; CHECK: %50 = OpULessThan %bool %142 %48 -; CHECK: OpSelectionMerge %51 None -; CHECK: OpBranchConditional %50 %52 %53 -; CHECK: %52 = OpLabel -; CHECK: %54 = OpLoad %13 %27 -; CHECK: %143 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_1 %142 -; CHECK: %144 = OpULessThan %bool %uint_0 %143 -; CHECK: OpSelectionMerge %145 None -; CHECK: OpBranchConditional %144 %146 %147 -; CHECK: %146 = OpLabel -; CHECK: %148 = OpLoad %13 %27 -; CHECK: %149 = OpImageRead %v4float %148 %20 -; CHECK: OpBranch %145 -; CHECK: %147 = OpLabel -; CHECK: %150 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 %142 %uint_0 -; CHECK: OpBranch %145 -; CHECK: %145 = OpLabel -; CHECK: %151 = OpPhi %v4float %149 %146 [[null_v4float]] %147 -; CHECK: OpBranch %51 -; CHECK: %53 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %142 %48 -; CHECK: OpBranch %51 -; CHECK: %51 = OpLabel -; CHECK: %114 = OpPhi %v4float %151 %145 [[null_v4float]] %53 -; CHECK: %30 = OpCompositeExtract %float %114 0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1 +; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpLoad %13 %27 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}} +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}} +; 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: %152 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -; CHECK: %153 = OpULessThan %bool %uint_0 %152 -; CHECK: OpSelectionMerge %154 None -; CHECK: OpBranchConditional %153 %155 %156 -; CHECK: %155 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; CHECK: OpSelectionMerge {{%\w+}} None +; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpLabel ; CHECK: OpStore %31 %30 -; CHECK: OpBranch %154 -; CHECK: %156 = OpLabel -; CHECK: %158 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %154 -; CHECK: %154 = OpLabel +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - const std::string new_funcs = kDirectRead2 + kStreamWrite4Ray + kDirectRead4; + const std::string new_funcs = + kReadBindingLength + kStreamWrite4Ray + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -3696,7 +3704,7 @@ OpDecorate %outColor Location 0 )" + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord )" + kInputDecorations + R"( -; CHECK: OpDecorate %151 NonUniform +; CHECK: OpDecorate [[desc_state_result:%\w+]] NonUniform %void = OpTypeVoid %3 = OpTypeFunction %void %int = OpTypeInt 32 1 @@ -3761,35 +3769,35 @@ OpStore %x %36 %50 = OpImageSampleImplicitLod %v4float %41 %49 %51 = OpCompositeExtract %float %50 0 ; CHECK-NOT: %51 = OpCompositeExtract %float %50 0 -; CHECK: %157 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -; CHECK: %158 = OpULessThan %bool %uint_0 %157 -; CHECK: OpSelectionMerge %159 None -; CHECK: OpBranchConditional %158 %160 %161 -; CHECK: %160 = OpLabel -; CHECK: %162 = OpLoad %v2float %47 -; CHECK: OpBranch %159 -; CHECK: %161 = OpLabel +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_87 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %159 -; CHECK: %159 = OpLabel -; CHECK: %166 = OpPhi %v2float %162 %160 [[null_v2float]] %161 -; CHECK: %49 = OpFMul %v2float %42 %166 -; CHECK: %167 = OpSampledImage %27 %39 %40 -; CHECK: %168 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_2 %uint_0 -; CHECK: %169 = OpULessThan %bool %uint_0 %168 -; CHECK: OpSelectionMerge %170 None -; CHECK: OpBranchConditional %169 %171 %172 -; CHECK: %171 = OpLabel -; CHECK: %173 = OpLoad %13 %uniformTex -; CHECK: %174 = OpSampledImage %27 %173 %40 -; CHECK: %175 = OpImageSampleImplicitLod %v4float %174 %49 -; CHECK: OpBranch %170 -; CHECK: %172 = OpLabel -; CHECK: %177 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_89 %uint_1 %uint_0 %uint_0 -; CHECK: OpBranch %170 -; CHECK: %170 = OpLabel -; CHECK: %178 = OpPhi %v4float %175 %171 [[null_v4float]] %172 -; CHECK: %51 = OpCompositeExtract %float %178 0 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} +; CHECK: %49 = OpFMul %v2float %42 {{%\w+}} +; CHECK: {{%\w+}} = OpSampledImage %27 %39 %40 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_2 %uint_0 +; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_89 %uint_1 %uint_0 %uint_0 +; 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 @@ -3799,7 +3807,7 @@ OpReturn OpFunctionEnd )"; - const std::string new_funcs = kStreamWrite4Frag + kDirectRead4; + const std::string new_funcs = kStreamWrite4Frag + kReadDescInit; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -3919,7 +3927,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float %MainPs = OpFunction %void None %3 %5 = OpLabel - ;CHECK: %140 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_1 %uint_0 + ;CHECK: [[desc_state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 %uint_0 ;CHECK: OpBranch %117 ;CHECK: %117 = OpLabel ;CHECK: OpBranch %116 @@ -3934,40 +3942,40 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { %86 = OpAccessChain %_ptr_Uniform_v2float %__0 %int_0 %87 = OpLoad %v2float %86 ;CHECK-NOT: %87 = OpLoad %v2float %86 - ;CHECK: %119 = OpIAdd %uint %uint_0 %uint_7 - ;CHECK: %141 = OpULessThan %bool %119 %140 - ;CHECK: OpSelectionMerge %143 None - ;CHECK: OpBranchConditional %141 %144 %145 - ;CHECK: %144 = OpLabel - ;CHECK: %146 = OpLoad %v2float %86 - ;CHECK: OpBranch %143 - ;CHECK: %145 = OpLabel - ;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_71 %uint_4 %uint_0 %119 %140 - ;CHECK: OpBranch %143 - ;CHECK: %143 = OpLabel - ;CHECK: %203 = OpPhi %v2float %146 %144 [[null_v2float]] %145 + ;CHECK: %119 = OpIAdd %uint %uint_0 %uint_7 + ;CHECK: {{%\w+}} = OpULessThan %bool %119 [[desc_state_result]] + ;CHECK: OpSelectionMerge {{%\w+}} None + ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} + ;CHECK: {{%\w+}} = OpLabel + ;CHECK: {{%\w+}} = OpLoad %v2float %86 + ;CHECK: OpBranch {{%\w+}} + ;CHECK: {{%\w+}} = OpLabel + ;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_71 %uint_4 %uint_0 %119 {{%\w+}} + ;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: %204 = OpIAdd %uint %uint_8 %uint_7 - ;CHECK: %205 = OpULessThan %bool %204 %140 - ;CHECK: OpSelectionMerge %206 None - ;CHECK: OpBranchConditional %205 %207 %208 - ;CHECK: %207 = OpLabel - ;CHECK: %209 = OpLoad %v2float %89 - ;CHECK: OpBranch %206 - ;CHECK: %208 = OpLabel - ;CHECK: %211 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_75 %uint_4 %uint_0 %204 %140 - ;CHECK: OpBranch %206 - ;CHECK: %206 = OpLabel - ;CHECK: %212 = OpPhi %v2float %209 %207 [[null_v2float]] %208 + ;CHECK: {{%\w+}} = OpIAdd %uint %uint_8 %uint_7 + ;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_75 %uint_4 %uint_0 {{%\w+}} {{%\w+}} + ;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 %203 %143 %212 %206 + ;CHECK: %115 = OpPhi %v2float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} %95 = OpFAdd %v2float %69 %115 %96 = OpLoad %49 %g_tColor %97 = OpLoad %53 %g_sAniso @@ -3976,7 +3984,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { OpStore %_entryPointOutput_vColor %100 OpReturn OpFunctionEnd -)" + kDirectRead3 + kStreamWrite5Frag; +)" + kReadDescInit + kStreamWrite5Frag; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -4106,35 +4114,35 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float %MainPs = OpFunction %void None %3 %5 = OpLabel -;CHECK: %123 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_2 %uint_0 -;CHECK: OpBranch %93 -;CHECK: %93 = OpLabel -;CHECK: OpBranch %92 -;CHECK: %92 = OpLabel +;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_2 %uint_0 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = 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: %96 = OpIMul %uint %uint_80 %80 -;CHECK: %97 = OpIAdd %uint %uint_0 %96 -;CHECK: %99 = OpIAdd %uint %97 %uint_64 -;CHECK: %101 = OpIAdd %uint %99 %uint_7 -;CHECK: %125 = OpULessThan %bool %101 %123 -;CHECK: OpSelectionMerge %127 None -;CHECK: OpBranchConditional %125 %128 %129 -;CHECK: %128 = OpLabel -;CHECK: %130 = OpLoad %v2float %81 -;CHECK: OpBranch %127 -;CHECK: %129 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_78 %uint_4 %uint_0 %101 %123 -;CHECK: OpBranch %127 -;CHECK: %127 = OpLabel -;CHECK: %186 = OpPhi %v2float %130 %128 [[null_v2float]] %129 +;CHECK: {{%\w+}} = OpIMul %uint %uint_80 %80 +;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} +;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64 +;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 +;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %v2float %81 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_78 %uint_4 %uint_0 {{%\w+}} {{%\w+}} +;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 %186 +;CHECK: %86 = OpFAdd %v2float %66 {{%\w+}} %87 = OpLoad %46 %g_tColor %88 = OpLoad %50 %g_sAniso %89 = OpSampledImage %54 %87 %88 @@ -4142,7 +4150,7 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { OpStore %_entryPointOutput_vColor %91 OpReturn OpFunctionEnd -)" + kDirectRead3 + kStreamWrite5Frag; +)" + kReadDescInit + kStreamWrite5Frag; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -4237,19 +4245,19 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { %_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: %v4uint = OpTypeVector %uint 4 -;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float +;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float +;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +;CHECK: %v4uint = OpTypeVector %uint 4 +;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float +;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float %MainPs = OpFunction %void None %3 %5 = OpLabel -;CHECK: %126 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_2 %uint_0 -;CHECK: %191 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %uint_0 -;CHECK: OpBranch %93 -;CHECK: %93 = OpLabel -;CHECK: OpBranch %92 -;CHECK: %92 = OpLabel +;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_2 %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel %66 = OpLoad %v2float %i_vTextureCoords %79 = OpAccessChain %_ptr_PushConstant_uint %__0 %int_0 %80 = OpLoad %uint %79 @@ -4258,22 +4266,22 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { %86 = OpFAdd %v2float %66 %82 ;CHECK-NOT: %82 = OpLoad %v2float %81 ;CHECK-NOT: %86 = OpFAdd %v2float %66 %82 -;CHECK: %96 = OpIMul %uint %uint_80 %80 -;CHECK: %97 = OpIAdd %uint %uint_0 %96 -;CHECK: %99 = OpIAdd %uint %97 %uint_64 -;CHECK: %101 = OpIAdd %uint %99 %uint_7 -;CHECK: %128 = OpULessThan %bool %101 %126 -;CHECK: OpSelectionMerge %130 None -;CHECK: OpBranchConditional %128 %131 %132 -;CHECK: %131 = OpLabel -;CHECK: %133 = OpLoad %v2float %81 -;CHECK: OpBranch %130 -;CHECK: %132 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_78 %uint_4 %uint_0 %101 %126 -;CHECK: OpBranch %130 -;CHECK: %130 = OpLabel -;CHECK: %190 = OpPhi %v2float %133 %131 [[null_v2float]] %132 -;CHECK: %86 = OpFAdd %v2float %66 %190 +;CHECK: {{%\w+}} = OpIMul %uint %uint_80 %80 +;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} +;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64 +;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 +;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %v2float %81 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_78 %uint_4 %uint_0 {{%\w+}} {{%\w+}} +;CHECK: OpBranch {{%\w+}} +;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 @@ -4281,23 +4289,23 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { OpStore %_entryPointOutput_vColor %91 ;CHECK-NOT: %91 = OpImageSampleImplicitLod %v4float %89 %86 ;CHECK-NOT: OpStore %_entryPointOutput_vColor %91 -;CHECK: %192 = OpULessThan %bool %uint_0 %191 -;CHECK: OpSelectionMerge %193 None -;CHECK: OpBranchConditional %192 %194 %195 -;CHECK: %194 = OpLabel -;CHECK: %196 = OpLoad %46 %g_tColor -;CHECK: %197 = OpSampledImage %54 %196 %88 -;CHECK: %198 = OpImageSampleImplicitLod %v4float %197 %86 -;CHECK: OpBranch %193 -;CHECK: %195 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_83 %uint_1 %uint_0 %uint_0 %uint_0 -;CHECK: OpBranch %193 -;CHECK: %193 = OpLabel -;CHECK: %202 = OpPhi %v4float %198 %194 [[null_v4float]] %195 -;CHECK: OpStore %_entryPointOutput_vColor %202 +;CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %46 %g_tColor +;CHECK: {{%\w+}} = OpSampledImage %54 {{%\w+}} %88 +;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %86 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_83 %uint_1 %uint_0 %uint_0 %uint_0 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK: OpStore %_entryPointOutput_vColor {{%\w+}} OpReturn OpFunctionEnd -)" + kDirectRead4 + kStreamWrite5Frag; +)" + kReadDescInit + kStreamWrite5Frag; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -4394,38 +4402,38 @@ TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { ;CHECK-NOT: %38 = OpImageSampleImplicitLod %v4float %37 %31 ;CHECK-NOT: OpStore %_entryPointOutput_vColor %38 ;CHECK: %41 = OpUConvert %uint %33 -;CHECK: %43 = OpULessThan %bool %41 %uint_128 -;CHECK: OpSelectionMerge %44 None -;CHECK: OpBranchConditional %43 %45 %46 -;CHECK: %45 = OpLabel -;CHECK: %47 = OpLoad %16 %34 -;CHECK: %48 = OpSampledImage %27 %47 %36 -;CHECK: %109 = OpUConvert %uint %33 -;CHECK: %131 = OpFunctionCall %uint %inst_bindless_direct_read_4 %uint_0 %uint_0 %uint_0 %109 -;CHECK: %132 = OpULessThan %bool %uint_0 %131 -;CHECK: OpSelectionMerge %133 None -;CHECK: OpBranchConditional %132 %134 %135 -;CHECK: %134 = OpLabel -;CHECK: %136 = OpLoad %16 %34 -;CHECK: %137 = OpSampledImage %27 %136 %36 -;CHECK: %138 = OpImageSampleImplicitLod %v4float %137 %31 -;CHECK: OpBranch %133 -;CHECK: %135 = OpLabel -;CHECK: %139 = OpUConvert %uint %33 -;CHECK: %140 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_60 %uint_1 %139 %uint_0 -;CHECK: OpBranch %133 -;CHECK: %133 = OpLabel -;CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float %138 %134 [[null_v4float]] %135 +;CHECK: {{%\w+}} = OpULessThan %bool %41 %uint_128 +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %16 %34 +;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %36 +;CHECK: {{%\w+}} = OpUConvert %uint %33 +;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 {{%\w+}} +;CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %16 %34 +;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %36 +;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %31 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpUConvert %uint %33 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_60 %uint_1 {{%\w+}} %uint_0 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} ;CHECK: OpBranch %44 ;CHECK: %46 = OpLabel ;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_60 %uint_0 %41 %uint_128 ;CHECK: OpBranch %44 ;CHECK: %44 = OpLabel -;CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float [[phi_result_1]] %133 [[null_v4float]] %46 +;CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float [[phi_result_1]] {{%\w+}} [[null_v4float]] %46 ;CHECK: OpStore %_entryPointOutput_vColor [[phi_result_2]] OpReturn OpFunctionEnd -)" + kStreamWrite4Frag + kDirectRead4; +)" + kStreamWrite4Frag + kReadDescInit; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -4558,11 +4566,11 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float %MainPs = OpFunction %void None %14 %37 = OpLabel -;CHECK: %79 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_0 %uint_0 -;CHECK: OpBranch %49 -;CHECK: %49 = OpLabel -;CHECK: OpBranch %48 -;CHECK: %48 = OpLabel +;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel %38 = OpLoad %v2float %i_vTextureCoords %39 = OpAccessChain %_ptr_PushConstant_ushort %__0 %int_0 %40 = OpLoad %ushort %39 @@ -4571,23 +4579,23 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { %43 = OpFAdd %v2float %38 %42 ;CHECK-NOT: %42 = OpLoad %v2float %41 ;CHECK-NOT: %43 = OpFAdd %v2float %38 %42 -;CHECK: %52 = OpUConvert %uint %40 -;CHECK: %53 = OpIMul %uint %uint_80 %52 -;CHECK: %54 = OpIAdd %uint %uint_0 %53 -;CHECK: %56 = OpIAdd %uint %54 %uint_64 -;CHECK: %58 = OpIAdd %uint %56 %uint_7 -;CHECK: %81 = OpULessThan %bool %58 %79 -;CHECK: OpSelectionMerge %83 None -;CHECK: OpBranchConditional %81 %84 %85 -;CHECK: %84 = OpLabel -;CHECK: %86 = OpLoad %v2float %41 -;CHECK: OpBranch %83 -;CHECK: %85 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_81 %uint_4 %uint_0 %58 %79 -;CHECK: OpBranch %83 -;CHECK: %83 = OpLabel -;CHECK: %143 = OpPhi %v2float %86 %84 [[null_v2float]] %85 -;CHECK: %43 = OpFAdd %v2float %38 %143 +;CHECK: {{%\w+}} = OpUConvert %uint %40 +;CHECK: {{%\w+}} = OpIMul %uint %uint_80 {{%\w+}} +;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} +;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64 +;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 +;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %v2float %41 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_81 %uint_4 %uint_0 {{%\w+}} {{%\w+}} +;CHECK: OpBranch {{%\w+}} +;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 @@ -4595,7 +4603,7 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { OpStore %_entryPointOutput_vColor %47 OpReturn OpFunctionEnd - )" + kDirectRead3 + kStreamWrite5Frag; + )" + kReadDescInit + kStreamWrite5Frag; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -4650,14 +4658,15 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { OpDecorate %_ Binding 0 OpDecorate %21 RelaxedPrecision ;CHECK-NOT: OpDecorate %21 RelaxedPrecision -;CHECK: OpDecorate %116 RelaxedPrecision +;CHECK: OpDecorate %v_vtxResult RelaxedPrecision +;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision OpDecorate %a_position Location 0 -;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 +;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + R"( -;CHECK: OpDecorate %61 RelaxedPrecision +;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision )" + kOutputDecorations + R"( -;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex -;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex +;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex +;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -4684,36 +4693,36 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;CHECK: [[null_float:%\w+]] = OpConstantNull %float %main = OpFunction %void None %3 %5 = OpLabel -;CHECK: %55 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_0 %uint_0 -;CHECK: OpBranch %26 -;CHECK: %26 = OpLabel -;CHECK: OpBranch %25 -;CHECK: %25 = OpLabel +;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = 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 -;CHECK: %30 = OpIMul %uint %uint_4 %int_2 -;CHECK: %31 = OpIAdd %uint %uint_0 %30 -;CHECK: %32 = OpIMul %uint %uint_16 %uint_1 -;CHECK: %33 = OpIAdd %uint %31 %32 -;CHECK: %35 = OpIAdd %uint %33 %uint_3 -;CHECK: %57 = OpULessThan %bool %35 %55 -;CHECK: OpSelectionMerge %58 None -;CHECK: OpBranchConditional %57 %59 %60 -;CHECK: %59 = OpLabel -;CHECK: %61 = OpLoad %float %20 -;CHECK: OpBranch %58 -;CHECK: %60 = OpLabel -;CHECK: {{\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_45 %uint_4 %uint_0 %35 %55 -;CHECK: OpBranch %58 -;CHECK: %58 = OpLabel -;CHECK: %116 = OpPhi %float %61 %59 [[null_float]] %60 +;CHECK: {{%\w+}} = OpIMul %uint %uint_4 %int_2 +;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} +;CHECK: {{%\w+}} = OpIMul %uint %uint_16 %uint_1 +;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 +;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} [[desc_state]] +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[load_result]] = OpLoad %float %20 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_45 %uint_4 %uint_0 {{%\w+}} {{%\w+}} +;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 %116 +;CHECK-NOT: OpStore %v_vtxResult %21 +;CHECK: OpStore %v_vtxResult [[phi_result]] OpReturn OpFunctionEnd - )" + kDirectRead3 + kStreamWrite5Vert; + )" + kReadDescInit + kStreamWrite5Vert; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -4767,15 +4776,16 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { OpDecorate %_ DescriptorSet 0 OpDecorate %_ Binding 0 OpDecorate %21 RelaxedPrecision -;CHECK-NOT: OpDecorate %21 RelaxedPrecision -;CHECK: OpDecorate %115 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 +;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + R"( -;CHECK: OpDecorate %61 RelaxedPrecision +;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision )" + kOutputDecorations + R"( -;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex -;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex +;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex +;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -4802,36 +4812,36 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { ;CHECK: [[null_float:%\w+]] = OpConstantNull %float %main = OpFunction %void None %3 %5 = OpLabel -;CHECK: %55 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_0 %uint_0 -;CHECK: OpBranch %26 -;CHECK: %26 = OpLabel -;CHECK: OpBranch %25 -;CHECK: %25 = OpLabel +;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +;CHECK: OpBranch %26 +;CHECK: %26 = OpLabel +;CHECK: OpBranch %25 +;CHECK: %25 = OpLabel %20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1 %21 = OpLoad %float %20 ;CHECK-NOT: %21 = OpLoad %float %20 -;CHECK: %29 = OpIMul %uint %uint_8 %int_2 -;CHECK: %30 = OpIAdd %uint %uint_0 %29 -;CHECK: %32 = OpIMul %uint %uint_4 %uint_1 -;CHECK: %33 = OpIAdd %uint %30 %32 -;CHECK: %35 = OpIAdd %uint %33 %uint_3 -;CHECK: %57 = OpULessThan %bool %35 %55 -;CHECK: OpSelectionMerge %58 None -;CHECK: OpBranchConditional %57 %59 %60 -;CHECK: %59 = OpLabel -;CHECK: %61 = OpLoad %float %20 -;CHECK: OpBranch %58 -;CHECK: %60 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_45 %uint_4 %uint_0 %35 %55 -;CHECK: OpBranch %58 -;CHECK: %58 = OpLabel -;CHECK: %115 = OpPhi %float %61 %59 [[null_float]] %60 +;CHECK: %29 = OpIMul %uint %uint_8 %int_2 +;CHECK: %30 = OpIAdd %uint %uint_0 %29 +;CHECK: %32 = OpIMul %uint %uint_4 %uint_1 +;CHECK: %33 = OpIAdd %uint %30 %32 +;CHECK: %35 = OpIAdd %uint %33 %uint_3 +;CHECK: {{%\w+}} = OpULessThan %bool %35 [[desc_state]] +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK:[[load_result]] = OpLoad %float %20 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_45 %uint_4 %uint_0 %35 {{%\w+}} +;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 %115 +;CHECK: OpStore %v_vtxResult [[phi_result]] OpReturn OpFunctionEnd - )" + kDirectRead3 + kStreamWrite5Vert; + )" + kReadDescInit + kStreamWrite5Vert; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -4888,14 +4898,14 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { OpDecorate %_ Binding 0 OpDecorate %26 RelaxedPrecision ;CHECK-NOT: OpDecorate %26 RelaxedPrecision -;CHECK: OpDecorate %125 RelaxedPrecision +;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision OpDecorate %a_position Location 0 -;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 +;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + R"( -;CHECK: OpDecorate %70 RelaxedPrecision +;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision )" + kOutputDecorations + R"( -;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex -;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex +;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex +;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex %void = OpTypeVoid %3 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -4927,38 +4937,38 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float %main = OpFunction %void None %3 %5 = OpLabel -;CHECK: %64 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_0 %uint_0 -;CHECK: OpBranch %31 -;CHECK: %31 = OpLabel -;CHECK: OpBranch %30 -;CHECK: %30 = OpLabel +;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +;CHECK: OpBranch %31 +;CHECK: %31 = OpLabel +;CHECK: OpBranch %30 +;CHECK: %30 = OpLabel %25 = OpAccessChain %_ptr_Uniform_v2float %_ %int_0 %int_2 %int_3 %int_1 %26 = OpLoad %v2float %25 OpStore %v_vtxResult %26 -;CHECK-NOT: %26 = OpLoad %v2float %25 -;CHECK-NOT: OpStore %v_vtxResult %26 -;CHECK: %34 = OpIMul %uint %uint_128 %int_2 -;CHECK: %35 = OpIAdd %uint %uint_0 %34 -;CHECK: %37 = OpIMul %uint %uint_32 %int_3 -;CHECK: %38 = OpIAdd %uint %35 %37 -;CHECK: %40 = OpIMul %uint %uint_4 %int_1 -;CHECK: %41 = OpIAdd %uint %38 %40 -;CHECK: %43 = OpIAdd %uint %41 %uint_19 -;CHECK: %66 = OpULessThan %bool %43 %64 -;CHECK: OpSelectionMerge %67 None -;CHECK: OpBranchConditional %66 %68 %69 -;CHECK: %68 = OpLabel -;CHECK: %70 = OpLoad %v2float %25 -;CHECK: OpBranch %67 -;CHECK: %69 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_51 %uint_4 %uint_0 %43 %64 -;CHECK: OpBranch %67 -;CHECK: %67 = OpLabel -;CHECK: %125 = OpPhi %v2float %70 %68 [[null_v2float]] %69 -;CHECK: OpStore %v_vtxResult %125 +;CHECK-NOT: %26 = OpLoad %v2float %25 +;CHECK-NOT: OpStore %v_vtxResult %26 +;CHECK: %34 = OpIMul %uint %uint_128 %int_2 +;CHECK: %35 = OpIAdd %uint %uint_0 %34 +;CHECK: %37 = OpIMul %uint %uint_32 %int_3 +;CHECK: %38 = OpIAdd %uint %35 %37 +;CHECK: %40 = OpIMul %uint %uint_4 %int_1 +;CHECK: %41 = OpIAdd %uint %38 %40 +;CHECK: %43 = OpIAdd %uint %41 %uint_19 +;CHECK: {{%\w+}} = OpULessThan %bool %43 [[desc_state]] +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[load_result]] = OpLoad %v2float %25 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_51 %uint_4 %uint_0 {{%\w+}} {{%\w+}} +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result]] = OpPhi %v2float [[load_result]] {{%\w+}} [[null_v2float]] {{%\w+}} +;CHECK: OpStore %v_vtxResult [[phi_result]] OpReturn OpFunctionEnd - )" + kDirectRead3 + kStreamWrite5Vert; + )" + kReadDescInit + kStreamWrite5Vert; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -5531,13 +5541,13 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer R"(%main = OpFunction %void None %3 %5 = OpLabel %i = OpVariable %_ptr_Function_int Function -;CHECK: OpBranch %137 -;CHECK: %137 = OpLabel -;CHECK: 65 = OpFunctionCall %uint %inst_bindless_direct_read_3 %uint_1 %uint_0 %uint_0 -;CHECK: OpBranch %40 -;CHECK: 40 = OpLabel -;CHECK: OpBranch %39 -;CHECK: 39 = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel OpStore %i %int_0 OpBranch %10 %10 = OpLabel @@ -5550,41 +5560,41 @@ OpBranch %14 %29 = OpSLessThan %bool %15 %27 ;CHECK-NOT: %27 = OpLoad %int %26 ;CHECK-NOT: %29 = OpSLessThan %bool %15 %27 -;CHECK: 43 = OpIAdd %uint %uint_8 %uint_3 -;CHECK: 66 = OpULessThan %bool %43 %65 -;CHECK: OpSelectionMerge %67 None -;CHECK: OpBranchConditional %66 %68 %69 -;CHECK: 68 = OpLabel -;CHECK: 70 = OpLoad %int %26 -;CHECK: OpBranch %67 -;CHECK: 69 = OpLabel -;CHECK: 122 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_54 %uint_4 %uint_0 %43 %65 -;CHECK: OpBranch %67 -;CHECK: 67 = OpLabel -;CHECK: 124 = OpPhi %int %70 %68 %123 %69 -;CHECK: 29 = OpSLessThan %bool %15 %124 +;CHECK: {{%\w+}} = OpIAdd %uint %uint_8 %uint_3 +;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[load_result:%\w+]] = OpLoad %int %26 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_54 %uint_4 %uint_0 {{%\w+}} {{%\w+}} +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result:%\w+]] = OpPhi %int [[load_result]] {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpSLessThan %bool %15 [[phi_result]] OpBranchConditional %29 %11 %12 %11 = OpLabel %31 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 %32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 ;CHECK-NOT: %32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 -;CHECK: 125 = OpIAdd %uint %uint_0 %uint_7 -;CHECK: 126 = OpULessThan %bool %125 %65 -;CHECK: OpSelectionMerge %127 None -;CHECK: OpBranchConditional %126 %128 %129 -;CHECK: 128 = OpLabel -;CHECK: 130 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 -;CHECK: OpBranch %127 -;CHECK: 129 = OpLabel -;CHECK: 132 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_59 %uint_4 %uint_0 %125 %65 -;CHECK: 135 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_bufStruct %134 -;CHECK: OpBranch %127 -;CHECK: 127 = OpLabel -;CHECK: 136 = OpPhi %_ptr_PhysicalStorageBuffer_bufStruct %130 %128 %135 %129 +;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 %uint_7 +;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} +;CHECK: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[load_result_2:%\w+]] = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_59 %uint_4 %uint_0 {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_bufStruct {{%\w+}} +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: [[phi_result_2:%\w+]] = OpPhi %_ptr_PhysicalStorageBuffer_bufStruct [[load_result_2]] {{%\w+}} {{%\w+}} {{%\w+}} %33 = OpLoad %int %i %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %32 %int_0 %33 ;CHECK-NOT: %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %32 %int_0 %33 -;CHECK: %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %136 %int_0 %33 +;CHECK: %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int [[phi_result_2]] %int_0 %33 OpStore %36 %int_n559035791 Aligned 16 OpBranch %13 %13 = OpLabel @@ -5595,7 +5605,7 @@ OpBranch %10 %12 = OpLabel OpReturn OpFunctionEnd)" - + kDirectRead3 + kStreamWrite5Vert; + + kReadDescInit + kStreamWrite5Vert; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); From 6110f30a36775e4d452968407f12b16694df2cc8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 27 Apr 2023 10:18:33 -0400 Subject: [PATCH 131/523] Roll external/googletest/ 783d00fd1..ccdeec888 (1 commit) (#5203) * Roll external/googletest/ 783d00fd1..dea0484e4 (2 commits) https://github.com/google/googletest/compare/783d00fd1986...dea0484e4d3b $ git log 783d00fd1..dea0484e4 --date=short --no-merges --format='%ad %ae %s' 2023-04-26 absl-team Use Abseil Flag public API for flag parsing. 2023-04-25 patryk gmock: fix issue #4222 Created with: roll-dep external/googletest * Roll external/spirv-headers/ cfbe4feef..e08a279cf (2 commits) https://github.com/KhronosGroup/SPIRV-Headers/compare/cfbe4feef20c...e08a279cf944 $ git log cfbe4feef..e08a279cf --date=short --no-merges --format='%ad %ae %s' 2023-04-19 joycebrum chore: Set minimal permissions to presubmit 2023-04-19 dmitry.sidorov Fix TileImage capabilities order 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 6f9633fb55..2c420b1441 100644 --- a/DEPS +++ b/DEPS @@ -5,13 +5,13 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': '783d00fd19865fcbc3065e3fb3e17144761fcf5a', + 'googletest_revision': 'dea0484e4d3b6a2c50055c24c5617cd662a50c5f', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', 're2_revision': '11073deb73b3d01018308863c0bcdfd0d51d3e70', - 'spirv_headers_revision': 'cfbe4feef20c3c0628712c2792624f0221e378ac', + 'spirv_headers_revision': 'e08a279cf9448085b920764db1bf27658b208795', } deps = { From baa46e103695080f56ac72847993f4ee9151cf63 Mon Sep 17 00:00:00 2001 From: ewerness-nv Date: Fri, 28 Apr 2023 06:40:46 -0700 Subject: [PATCH 132/523] Update spirv_headers to include SPV_KHR_ray_tracing_position_fetch (#5205) --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 2c420b1441..b4053156fc 100644 --- a/DEPS +++ b/DEPS @@ -11,7 +11,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': '11073deb73b3d01018308863c0bcdfd0d51d3e70', - 'spirv_headers_revision': 'e08a279cf9448085b920764db1bf27658b208795', + 'spirv_headers_revision': '7f1d2f4158704337aff1f739c8e494afc5716e7e', } deps = { From 8e1001e9387bf1c052d9947ffe0b86f4eb0eef2f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 28 Apr 2023 10:30:53 -0400 Subject: [PATCH 133/523] Roll external/googletest/ dea0484e4..0bdaac5a1 (1 commit) (#5206) https://github.com/google/googletest/compare/dea0484e4d3b...0bdaac5a1401 $ git log dea0484e4..0bdaac5a1 --date=short --no-merges --format='%ad %ae %s' 2023-04-27 tomhughes Add qualifier to avoid argument dependent lookup 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 b4053156fc..5fa14fc61e 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': 'dea0484e4d3b6a2c50055c24c5617cd662a50c5f', + 'googletest_revision': '0bdaac5a1401fffac6b64581efc639734aded793', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From 08d8fae589f74c7734732857dd6f2d6f4c5b6a1d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 1 May 2023 10:12:36 -0400 Subject: [PATCH 134/523] Roll external/googletest/ 0bdaac5a1..797b0ad2a (1 commit) (#5207) https://github.com/google/googletest/compare/0bdaac5a1401...797b0ad2a3a4 $ git log 0bdaac5a1..797b0ad2a --date=short --no-merges --format='%ad %ae %s' 2023-04-28 dinor Use GTEST_INTERNAL_CPLUSPLUS_LANG instead of __cplusplus 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 5fa14fc61e..86525ce027 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': '0bdaac5a1401fffac6b64581efc639734aded793', + 'googletest_revision': '797b0ad2a3a45608ecf5c67e6e289d377a3521ca', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From 0ce36ad7856e15b545bc7b9fc9a7c49671b40f96 Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Mon, 1 May 2023 12:23:30 -0600 Subject: [PATCH 135/523] instrument: Add set and binding to bindless error records (#5204) Add set and binding fields to the error records so that it is easier for users to figure out which descriptor caused an error. --- include/spirv-tools/instrument.hpp | 32 +- source/opt/inst_bindless_check_pass.cpp | 47 +- source/opt/inst_bindless_check_pass.h | 18 +- test/opt/inst_bindless_check_test.cpp | 646 ++++++++++++------------ 4 files changed, 394 insertions(+), 349 deletions(-) diff --git a/include/spirv-tools/instrument.hpp b/include/spirv-tools/instrument.hpp index 2e029e1554..448cf8ab79 100644 --- a/include/spirv-tools/instrument.hpp +++ b/include/spirv-tools/instrument.hpp @@ -146,23 +146,29 @@ static const int kInstValidationOutError = kInstStageOutCnt; // about the validation error. // // A bindless bounds error will output the index and the bound. -static const int kInstBindlessBoundsOutDescIndex = kInstStageOutCnt + 1; -static const int kInstBindlessBoundsOutDescBound = kInstStageOutCnt + 2; -static const int kInstBindlessBoundsOutUnused = kInstStageOutCnt + 3; -static const int kInstBindlessBoundsOutCnt = kInstStageOutCnt + 4; +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 kInstBindlessUninitOutDescIndex = kInstStageOutCnt + 1; -static const int kInstBindlessUninitOutUnused = kInstStageOutCnt + 2; -static const int kInstBindlessUninitOutUnused2 = kInstStageOutCnt + 3; -static const int kInstBindlessUninitOutCnt = kInstStageOutCnt + 4; +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 kInstBindlessBuffOOBOutDescIndex = kInstStageOutCnt + 1; -static const int kInstBindlessBuffOOBOutBuffOff = kInstStageOutCnt + 2; -static const int kInstBindlessBuffOOBOutBuffSize = kInstStageOutCnt + 3; -static const int kInstBindlessBuffOOBOutCnt = kInstStageOutCnt + 4; +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. @@ -171,7 +177,7 @@ static const int kInstBuffAddrUnallocOutDescPtrHi = kInstStageOutCnt + 2; static const int kInstBuffAddrUnallocOutCnt = kInstStageOutCnt + 3; // Maximum Output Record Member Count -static const int kInstMaxOutCnt = kInstStageOutCnt + 4; +static const int kInstMaxOutCnt = kInstStageOutCnt + 6; // Validation Error Codes // diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp index 1ea37ab8d8..e8c412ffe1 100644 --- a/source/opt/inst_bindless_check_pass.cpp +++ b/source/opt/inst_bindless_check_pass.cpp @@ -734,9 +734,18 @@ bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst, ptr_inst->GetSingleWordInOperand(kSpvAccessChainIndex0IdInIdx); break; default: - ref->desc_idx_id = 0; break; } + auto decos = + context()->get_decoration_mgr()->GetDecorationsFor(ref->var_id, false); + for (const auto& deco : decos) { + spv::Decoration d = spv::Decoration(deco->GetSingleWordInOperand(1u)); + if (d == spv::Decoration::DescriptorSet) { + ref->set = deco->GetSingleWordInOperand(2u); + } else if (d == spv::Decoration::Binding) { + ref->binding = deco->GetSingleWordInOperand(2u); + } + } return true; } // Reference is not load or store. If not an image-based reference, return. @@ -786,6 +795,16 @@ bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst, // TODO(greg-lunarg): Handle additional possibilities? return false; } + auto decos = + context()->get_decoration_mgr()->GetDecorationsFor(ref->var_id, false); + for (const auto& deco : decos) { + spv::Decoration d = spv::Decoration(deco->GetSingleWordInOperand(1u)); + if (d == spv::Decoration::DescriptorSet) { + ref->set = deco->GetSingleWordInOperand(2u); + } else if (d == spv::Decoration::Binding) { + ref->binding = deco->GetSingleWordInOperand(2u); + } + } return true; } @@ -1028,27 +1047,29 @@ void InstBindlessCheckPass::GenCheckCode( // Gen invalid block new_blk_ptr.reset(new BasicBlock(std::move(invalid_label))); builder.SetInsertPoint(&*new_blk_ptr); - uint32_t u_index_id = GenUintCastCode(ref->desc_idx_id, &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 - uint32_t u_offset_id = GenUintCastCode(offset_id, &builder); - uint32_t u_length_id = GenUintCastCode(length_id, &builder); GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx, - {error_id, u_index_id, u_offset_id, u_length_id}, + {error_id, u_set_id, u_binding_id, u_index_id, + u_offset_id, u_length_id}, &builder); } else if (buffer_bounds_enabled_ || texel_buffer_enabled_) { // Uninitialized Descriptor - Return additional unused zero so all error // modes will use same debug stream write function - uint32_t u_length_id = GenUintCastCode(length_id, &builder); - GenDebugStreamWrite( - uid2offset_[ref->ref_inst->unique_id()], stage_idx, - {error_id, u_index_id, u_length_id, builder.GetUintConstantId(0)}, - &builder); + GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx, + {error_id, u_set_id, u_binding_id, u_index_id, + u_length_id, builder.GetUintConstantId(0)}, + &builder); } else { // Uninitialized Descriptor - Normal error return - uint32_t u_length_id = GenUintCastCode(length_id, &builder); - GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx, - {error_id, u_index_id, u_length_id}, &builder); + GenDebugStreamWrite( + uid2offset_[ref->ref_inst->unique_id()], stage_idx, + {error_id, u_set_id, u_binding_id, u_index_id, u_length_id}, &builder); } // Generate a ConstantNull, converting to uint64 if the type cannot be a null. if (new_ref_id != 0) { diff --git a/source/opt/inst_bindless_check_pass.h b/source/opt/inst_bindless_check_pass.h index 37d2b29e87..f89af025a9 100644 --- a/source/opt/inst_bindless_check_pass.h +++ b/source/opt/inst_bindless_check_pass.h @@ -128,14 +128,16 @@ class InstBindlessCheckPass : public InstrumentPass { // AnalyzeDescriptorReference. It is necessary and sufficient for further // analysis and regeneration of the reference. typedef struct RefAnalysis { - uint32_t desc_load_id; - uint32_t image_id; - uint32_t load_id; - uint32_t ptr_id; - uint32_t var_id; - uint32_t desc_idx_id; - uint32_t strg_class; - Instruction* ref_inst; + uint32_t desc_load_id{0}; + uint32_t image_id{0}; + uint32_t load_id{0}; + uint32_t ptr_id{0}; + uint32_t var_id{0}; + uint32_t set{0}; + uint32_t binding{0}; + uint32_t desc_idx_id{0}; + uint32_t strg_class{0}; + Instruction* ref_inst{nullptr}; } RefAnalysis; // Return size of type |ty_id| in bytes. Use |matrix_stride| and |col_major| diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp index 9fe4f4021a..dd4b6f6075 100644 --- a/test/opt/inst_bindless_check_test.cpp +++ b/test/opt/inst_bindless_check_test.cpp @@ -41,16 +41,18 @@ static const std::string kOutputGlobals = R"( ; CHECK: [[output_buffer_var]] = OpVariable [[output_ptr_type]] StorageBuffer )"; -static const std::string kStreamWrite4Begin = R"( -; CHECK: %inst_bindless_stream_write_4 = OpFunction %void None {{%\w+}} +static const std::string kStreamWrite6Begin = R"( +; CHECK: %inst_bindless_stream_write_6 = OpFunction %void None {{%\w+}} ; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint ; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint ; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint ; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint +; CHECK: [[param_5:%\w+]] = OpFunctionParameter %uint +; CHECK: [[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_10 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10 +; CHECK: {{%\w+}} = OpAtomicIAdd %uint {{%\w+}} %uint_4 %uint_0 %uint_12 +; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_12 ; CHECK: {{%\w+}} = OpArrayLength %uint [[output_buffer_var]] 2 ; CHECK: {{%\w+}} = OpULessThanEqual %bool {{%\w+}} {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None @@ -58,7 +60,7 @@ static const std::string kStreamWrite4Begin = R"( ; 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: OpStore {{%\w+}} %uint_12 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} %uint_23 @@ -67,7 +69,7 @@ static const std::string kStreamWrite4Begin = R"( ; CHECK: OpStore {{%\w+}} [[param_1]] )"; -static const std::string kStreamWrite4End = R"( +static const std::string kStreamWrite6End = R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} [[param_2]] @@ -77,6 +79,12 @@ static const std::string kStreamWrite4End = R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_9 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} [[param_4]] +; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10 +; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} +; CHECK: OpStore {{%\w+}} [[param_5]] +; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_11 +; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} +; CHECK: OpStore {{%\w+}} [[param_6]] ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: OpReturn @@ -84,7 +92,7 @@ static const std::string kStreamWrite4End = R"( )"; // clang-format off -static const std::string kStreamWrite4Frag = kStreamWrite4Begin + R"( +static const std::string kStreamWrite6Frag = kStreamWrite6Begin + R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} %uint_4 @@ -98,9 +106,9 @@ static const std::string kStreamWrite4Frag = kStreamWrite4Begin + R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}} -)" + kStreamWrite4End; +)" + kStreamWrite6End; -static const std::string kStreamWrite4Tese = kStreamWrite4Begin + R"( +static const std::string kStreamWrite6Tese = kStreamWrite6Begin + R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} %uint_2 @@ -118,9 +126,9 @@ static const std::string kStreamWrite4Tese = kStreamWrite4Begin + R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}} -)" + kStreamWrite4End; +)" + kStreamWrite6End; -static const std::string kStreamWrite4Vert = kStreamWrite4Begin + R"( +static const std::string kStreamWrite6Vert = kStreamWrite6Begin + R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} %uint_0 @@ -132,9 +140,9 @@ static const std::string kStreamWrite4Vert = kStreamWrite4Begin + R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}} -)" + kStreamWrite4End; +)" + kStreamWrite6End; -static const std::string kStreamWrite4Compute = kStreamWrite4Begin + R"( +static const std::string kStreamWrite6Compute = kStreamWrite6Begin + R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} %uint_5 @@ -151,9 +159,9 @@ static const std::string kStreamWrite4Compute = kStreamWrite4Begin + R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}} -)" + kStreamWrite4End; +)" + kStreamWrite6End; -static const std::string kStreamWrite4Ray = kStreamWrite4Begin + R"( +static const std::string kStreamWrite6Ray = kStreamWrite6Begin + R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}} @@ -170,20 +178,22 @@ static const std::string kStreamWrite4Ray = kStreamWrite4Begin + R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}} -)" + kStreamWrite4End; +)" + kStreamWrite6End; // clang-format on -static const std::string kStreamWrite5Begin = R"( -; CHECK: %inst_bindless_stream_write_5 = OpFunction %void None {{%\w+}} +static const std::string kStreamWrite7Begin = R"( +; CHECK: %inst_bindless_stream_write_7 = OpFunction %void None {{%\w+}} ; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint ; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint ; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint ; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint ; CHECK: [[param_5:%\w+]] = OpFunctionParameter %uint +; CHECK: [[param_6:%\w+]] = OpFunctionParameter %uint +; CHECK: [[param_7:%\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_11 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_11 +; 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 @@ -191,7 +201,7 @@ static const std::string kStreamWrite5Begin = R"( ; 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_11 +; 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+}} %uint_23 @@ -200,7 +210,7 @@ static const std::string kStreamWrite5Begin = R"( ; CHECK: OpStore {{%\w+}} [[param_1]] )"; -static const std::string kStreamWrite5End = R"( +static const std::string kStreamWrite7End = R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} [[param_2]] @@ -213,6 +223,12 @@ static const std::string kStreamWrite5End = R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} [[param_5]] +; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_11 +; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} +; CHECK: OpStore {{%\w+}} [[param_6]] +; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_12 +; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} +; CHECK: OpStore {{%\w+}} [[param_7]] ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: OpReturn @@ -220,7 +236,7 @@ static const std::string kStreamWrite5End = R"( )"; // clang-format off -static const std::string kStreamWrite5Frag = kStreamWrite5Begin + R"( +static const std::string kStreamWrite7Frag = kStreamWrite7Begin + R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} %uint_4 @@ -234,9 +250,9 @@ static const std::string kStreamWrite5Frag = kStreamWrite5Begin + R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}} -)" + kStreamWrite4End; +)" + kStreamWrite7End; -static const std::string kStreamWrite5Vert = kStreamWrite5Begin + R"( +static const std::string kStreamWrite7Vert = kStreamWrite7Begin + R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} %uint_0 @@ -248,7 +264,7 @@ static const std::string kStreamWrite5Vert = kStreamWrite5Begin + R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}} -)" + kStreamWrite5End; +)" + kStreamWrite7End; // clang-format on static const std::string kInputDecorations = R"( @@ -386,8 +402,8 @@ OpName %g_sAniso "g_sAniso" OpName %i_vTextureCoords "i.vTextureCoords" OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" OpDecorate %g_tColor DescriptorSet 3 -OpDecorate %g_tColor Binding 0 -OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %g_tColor Binding 5 +OpDecorate %g_sAniso DescriptorSet 3 OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 %void = OpTypeVoid @@ -469,10 +485,10 @@ OpName %g_tColor "g_tColor" OpName %g_sAniso "g_sAniso" OpName %i_vTextureCoords "i.vTextureCoords" OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" -OpDecorate %g_tColor DescriptorSet 0 -OpDecorate %g_tColor Binding 0 -OpDecorate %g_sAniso DescriptorSet 0 -OpDecorate %g_sAniso Binding 0 +OpDecorate %g_tColor DescriptorSet 6 +OpDecorate %g_tColor Binding 4 +OpDecorate %g_sAniso DescriptorSet 6 +OpDecorate %g_sAniso Binding 4 OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 %void = OpTypeVoid @@ -630,7 +646,7 @@ OpStore %_entryPointOutput_vColor %37 ; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %30 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_56 %uint_0 %32 %uint_128 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_56 %uint_0 %uint_3 %uint_0 %32 %uint_128 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} @@ -639,7 +655,7 @@ OpReturn OpFunctionEnd )"; - const std::string output_func = kStreamWrite4Frag; + const std::string output_func = kStreamWrite6Frag; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch( @@ -697,11 +713,11 @@ OpName %g_sAniso "g_sAniso" OpName %i_vTextureCoords "i.vTextureCoords" OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" OpDecorate %g_tColor DescriptorSet 3 -OpDecorate %g_tColor Binding 0 +OpDecorate %g_tColor Binding 4 OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 OpMemberDecorate %PerViewConstantBuffer_t 1 Offset 4 OpDecorate %PerViewConstantBuffer_t Block -OpDecorate %g_sAniso DescriptorSet 0 +OpDecorate %g_sAniso DescriptorSet 3 OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 @@ -767,10 +783,10 @@ OpDecorate %_entryPointOutput_vColor Location 0 ; CHECK: %54 = OpImageSampleImplicitLod %v4float %53 %31 ; CHECK: OpBranch %49 ; CHECK: %51 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_58 %uint_0 %33 %uint_128 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_58 %uint_0 %uint_3 %uint_4 %33 %uint_128 ; CHECK: OpBranch %49 ; CHECK: %49 = OpLabel -; CHECK: %112 = OpPhi %v4float %54 %50 [[null_v4float]] %51 +; CHECK: {{%\w+}} = OpPhi %v4float %54 %50 [[null_v4float]] %51 %39 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1 %40 = OpLoad %uint %39 %41 = OpAccessChain %_ptr_UniformConstant_17 %g_tColor %40 @@ -780,26 +796,26 @@ OpDecorate %_entryPointOutput_vColor Location 0 %45 = OpFAdd %v4float %38 %44 ; CHECK-NOT: %44 = OpImageSampleImplicitLod %v4float %43 %31 ; CHECK-NOT: %45 = OpFAdd %v4float %38 %44 -; CHECK: %113 = OpULessThan %bool %40 %uint_128 -; CHECK: OpSelectionMerge %114 None -; CHECK: OpBranchConditional %113 %115 %116 -; CHECK: %115 = OpLabel -; CHECK: %117 = OpLoad %17 %41 -; CHECK: %118 = OpSampledImage %27 %117 %36 -; CHECK: %119 = OpImageSampleImplicitLod %v4float %118 %31 -; CHECK: OpBranch %114 -; CHECK: %116 = OpLabel -; CHECK: %121 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_64 %uint_0 %40 %uint_128 -; CHECK: OpBranch %114 -; CHECK: %114 = OpLabel -; CHECK: %122 = OpPhi %v4float %119 %115 [[null_v4float]] %116 -; CHECK: %45 = OpFAdd %v4float %112 %122 +; CHECK: {{%\w+}} = OpULessThan %bool %40 %uint_128 +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_64 %uint_0 %uint_3 %uint_4 %40 %uint_128 +; 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 = kStreamWrite4Frag; + const std::string output_func = kStreamWrite6Frag; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + output_func, @@ -831,7 +847,7 @@ OpName %_ "" OpName %i_vTextureCoords "i.vTextureCoords" OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" OpDecorate %g_tColor DescriptorSet 3 -OpDecorate %g_tColor Binding 0 +OpDecorate %g_tColor Binding 9 OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 OpDecorate %PerViewConstantBuffer_t Block OpDecorate %i_vTextureCoords Location 0 @@ -896,16 +912,16 @@ OpStore %_entryPointOutput_vColor %71 ; CHECK: %84 = OpImageRead %v4float %83 %53 ; CHECK: OpBranch %79 ; CHECK: %81 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %64 %uint_128 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_3 %uint_9 %64 %uint_128 ; CHECK: OpBranch %79 ; CHECK: %79 = OpLabel -; CHECK: %142 = OpPhi %v4float %84 %80 [[null_v4float]] %81 -; CHECK: OpStore %_entryPointOutput_vColor %142 +; CHECK: {{%\w+}} = OpPhi %v4float %84 %80 [[null_v4float]] %81 +; CHECK: OpStore %_entryPointOutput_vColor {{%\w+}} OpReturn OpFunctionEnd )"; - const std::string output_func = kStreamWrite4Frag; + const std::string output_func = kStreamWrite6Frag; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + output_func, @@ -935,8 +951,8 @@ OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" OpName %_ "" OpName %i_vTextureCoords "i.vTextureCoords" OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" -OpDecorate %g_tColor DescriptorSet 3 -OpDecorate %g_tColor Binding 0 +OpDecorate %g_tColor DescriptorSet 4 +OpDecorate %g_tColor Binding 11 OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 OpDecorate %PerViewConstantBuffer_t Block OpDecorate %i_vTextureCoords Location 0 @@ -998,16 +1014,16 @@ OpStore %_entryPointOutput_vColor %71 ; CHECK: %79 = OpImageSampleImplicitLod %v4float %78 %53 ; CHECK: OpBranch %75 ; CHECK: %77 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_49 %uint_0 %64 %uint_128 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_49 %uint_0 %uint_4 %uint_11 %64 %uint_128 ; CHECK: OpBranch %75 ; CHECK: %75 = OpLabel -; CHECK: %137 = OpPhi %v4float %79 %76 [[null_v4float]] %77 -; CHECK: OpStore %_entryPointOutput_vColor %137 +; CHECK: {{%\w+}} = OpPhi %v4float %79 %76 [[null_v4float]] %77 +; CHECK: OpStore %_entryPointOutput_vColor {{%\w+}} OpReturn OpFunctionEnd )"; - const std::string output_func = kStreamWrite4Frag; + const std::string output_func = kStreamWrite6Frag; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + output_func, @@ -1038,8 +1054,8 @@ OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" OpName %_ "" OpName %i_vTextureCoords "i.vTextureCoords" OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" -OpDecorate %g_tColor DescriptorSet 3 -OpDecorate %g_tColor Binding 0 +OpDecorate %g_tColor DescriptorSet 30 +OpDecorate %g_tColor Binding 2 OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 OpDecorate %PerViewConstantBuffer_t Block OpDecorate %i_vTextureCoords Location 0 @@ -1099,7 +1115,7 @@ OpStore %_entryPointOutput_vColor %80 ; CHECK: OpImageWrite %39 %28 %19 ; CHECK: OpBranch %36 ; CHECK: %38 = OpLabel -; CHECK: %95 = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 %30 %uint_128 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_30 %uint_2 %30 %uint_128 ; CHECK: OpBranch %36 ; CHECK: %36 = OpLabel ; CHECK: OpStore %_entryPointOutput_vColor %19 @@ -1107,7 +1123,7 @@ OpReturn OpFunctionEnd )"; - const std::string output_func = kStreamWrite4Frag; + const std::string output_func = kStreamWrite6Frag; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + output_func, @@ -1152,11 +1168,11 @@ OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance OpDecorate %gl_PerVertex Block -OpDecorate %texSampler1D DescriptorSet 0 -OpDecorate %texSampler1D Binding 3 +OpDecorate %texSampler1D DescriptorSet 2 +OpDecorate %texSampler1D Binding 13 OpMemberDecorate %foo 0 Offset 0 OpDecorate %foo Block -OpDecorate %__0 DescriptorSet 0 +OpDecorate %__0 DescriptorSet 7 OpDecorate %__0 Binding 5 OpDecorate %coords2D Location 0 %void = OpTypeVoid @@ -1227,18 +1243,18 @@ OpStore %40 %38 ; CHECK: %51 = OpImageSampleExplicitLod %v4float %50 %40 Lod %41 ; CHECK: OpBranch %47 ; CHECK: %49 = OpLabel -; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %37 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_74 %uint_0 [[bitcast_result]] %uint_128 +; CHECK: {{%\w+}} = OpBitcast %uint %37 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_74 %uint_0 %uint_2 %uint_13 {{%\w+}} %uint_128 ; CHECK: OpBranch %47 ; CHECK: %47 = OpLabel -; CHECK: %107 = OpPhi %v4float %51 %48 [[null_v4float]] %49 +; CHECK: {{%\w+}} = OpPhi %v4float %51 %48 [[null_v4float]] %49 ; CHECK: %43 = OpAccessChain %_ptr_Output_v4float %_ %int_0 -; CHECK: OpStore %43 %107 +; CHECK: OpStore %43 {{%\w+}} OpReturn OpFunctionEnd )"; - const std::string output_func = kStreamWrite4Vert; + const std::string output_func = kStreamWrite6Vert; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + output_func, @@ -1255,9 +1271,9 @@ TEST_F(InstBindlessTest, InstrumentTeseSimple) { // #version 450 // #extension GL_EXT_nonuniform_qualifier : enable // - // layout(std140, set = 0, binding = 0) uniform ufoo { uint index; } uniform_index_buffer; + // layout(std140, set = 9, binding = 1) uniform ufoo { uint index; } uniform_index_buffer; // - // layout(set = 0, binding = 1) buffer bfoo { vec4 val; } adds[11]; + // layout(set = 9, binding = 2) buffer bfoo { vec4 val; } adds[11]; // // layout(triangles, equal_spacing, cw) in; // @@ -1297,12 +1313,12 @@ OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance OpDecorate %gl_PerVertex Block OpMemberDecorate %bfoo 0 Offset 0 OpDecorate %bfoo Block -OpDecorate %adds DescriptorSet 0 +OpDecorate %adds DescriptorSet 9 OpDecorate %adds Binding 1 OpMemberDecorate %ufoo 0 Offset 0 OpDecorate %ufoo Block -OpDecorate %uniform_index_buffer DescriptorSet 0 -OpDecorate %uniform_index_buffer Binding 0 +OpDecorate %uniform_index_buffer DescriptorSet 9 +OpDecorate %uniform_index_buffer Binding 2 ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId @@ -1359,19 +1375,19 @@ OpDecorate %uniform_index_buffer Binding 0 ; CHECK: %38 = OpLoad %v4float %29 ; CHECK: OpBranch %35 ; CHECK: %37 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_63 %uint_0 %28 %uint_11 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_63 %uint_0 %uint_9 %uint_1 %28 %uint_11 ; CHECK: OpBranch %35 ; CHECK: %35 = OpLabel -; CHECK: %102 = OpPhi %v4float %38 %36 [[null_v4float]] %37 +; CHECK: {{%\w+}} = OpPhi %v4float %38 %36 [[null_v4float]] %37 %31 = OpAccessChain %_ptr_Output_v4float %_ %int_0 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: OpStore %31 %102 +; CHECK: OpStore %31 {{%\w+}} OpReturn OpFunctionEnd )"; - const std::string output_func = kStreamWrite4Tese; + const std::string output_func = kStreamWrite6Tese; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + output_func, @@ -1411,12 +1427,12 @@ OpName %i_0 "i" OpName %i_vTextureCoords "i.vTextureCoords" OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" OpName %param "param" -OpDecorate %g_tColor DescriptorSet 0 -OpDecorate %g_tColor Binding 0 +OpDecorate %g_tColor DescriptorSet 1 +OpDecorate %g_tColor Binding 2 OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 OpDecorate %PerViewConstantBuffer_t Block -OpDecorate %g_sAniso DescriptorSet 0 -OpDecorate %g_sAniso Binding 1 +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 @@ -1512,7 +1528,7 @@ OpLine %1 24 0 ; CHECK: OpNoLine ; CHECK: OpBranch %63 ; CHECK: %65 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_109 %uint_0 %50 %uint_128 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_109 %uint_0 %uint_1 %uint_2 %50 %uint_128 ; CHECK: OpBranch %63 ; CHECK: %63 = OpLabel ; CHECK: [[phi_result:%\w+]] = OpPhi %v4float %68 %64 [[null_v4float]] %65 @@ -1528,7 +1544,7 @@ OpReturnValue %48 OpFunctionEnd )"; - const std::string output_func = kStreamWrite4Frag; + const std::string output_func = kStreamWrite6Frag; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch( @@ -1566,7 +1582,7 @@ OpDecorate %g_tColor Binding 2 OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 OpDecorate %PerViewConstantBuffer_t Block OpDecorate %g_sAniso DescriptorSet 1 -OpDecorate %g_sAniso Binding 0 +OpDecorate %g_sAniso Binding 3 OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 @@ -1637,13 +1653,13 @@ OpStore %_entryPointOutput_vColor %71 ; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %30 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_59 %uint_1 %32 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_59 %uint_1 %uint_1 %uint_2 %32 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_59 %uint_0 %32 {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_59 %uint_0 %uint_1 %uint_2 %32 {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float [[phi_result_1]] {{%\w+}} [[null_v4float]] {{%\w+}} @@ -1653,7 +1669,7 @@ OpFunctionEnd )"; const std::string new_funcs = - kReadBindingLength + kStreamWrite4Frag + kReadDescInit; + kReadBindingLength + kStreamWrite6Frag + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -1684,10 +1700,10 @@ OpName %g_tColor "g_tColor" OpName %g_sAniso "g_sAniso" OpName %i_vTextureCoords "i.vTextureCoords" OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" -OpDecorate %g_tColor DescriptorSet 0 -OpDecorate %g_tColor Binding 0 -OpDecorate %g_sAniso DescriptorSet 0 -OpDecorate %g_sAniso Binding 0 +OpDecorate %g_tColor DescriptorSet 1 +OpDecorate %g_tColor Binding 2 +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 @@ -1728,7 +1744,7 @@ OpDecorate %_entryPointOutput_vColor Location 0 OpStore %_entryPointOutput_vColor %24 ; CHECK-NOT: %24 = OpImageSampleImplicitLod %v4float %23 %20 ; CHECK-NOT: OpStore %_entryPointOutput_vColor %24 -; CHECK: [[state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: [[state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[state_result]] ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -1738,7 +1754,7 @@ OpStore %_entryPointOutput_vColor %24 ; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_39 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_39 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} @@ -1747,7 +1763,7 @@ OpReturn OpFunctionEnd )"; - const std::string new_funcs = kReadDescInit + kStreamWrite4Frag; + const std::string new_funcs = kReadDescInit + kStreamWrite6Frag; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -1767,10 +1783,10 @@ OpExtension "SPV_EXT_descriptor_indexing" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %foo "foo" %gid %image_var %sampler_var OpExecutionMode %foo OriginUpperLeft -OpDecorate %image_var DescriptorSet 0 -OpDecorate %image_var Binding 0 -OpDecorate %sampler_var DescriptorSet 0 -OpDecorate %sampler_var Binding 1 +OpDecorate %image_var DescriptorSet 4 +OpDecorate %image_var Binding 1 +OpDecorate %sampler_var DescriptorSet 4 +OpDecorate %sampler_var Binding 2 OpDecorate %gid DescriptorSet 0 OpDecorate %gid Binding 2 OpDecorate %struct Block @@ -1826,12 +1842,12 @@ OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %foo "foo" %gid %image_var %sampler_var OpEntryPoint Fragment %foo "bar" %gid %image_var %sampler_var OpExecutionMode %foo OriginUpperLeft -OpDecorate %image_var DescriptorSet 0 -OpDecorate %image_var Binding 0 -OpDecorate %sampler_var DescriptorSet 0 -OpDecorate %sampler_var Binding 1 -OpDecorate %gid DescriptorSet 0 -OpDecorate %gid Binding 2 +OpDecorate %image_var DescriptorSet 3 +OpDecorate %image_var Binding 2 +OpDecorate %sampler_var DescriptorSet 3 +OpDecorate %sampler_var Binding 3 +OpDecorate %gid DescriptorSet 3 +OpDecorate %gid Binding 4 OpDecorate %struct Block OpMemberDecorate %struct 0 Offset 0 %void = OpTypeVoid @@ -1878,7 +1894,7 @@ TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedUBOArray) { // layout(location=0) in nonuniformEXT flat int nu_ii; // layout(location=0) out float b; // - // layout(binding=3) uniform uname { float a; } uniformBuffer[]; + // layout(set = 6, binding=3) uniform uname { float a; } uniformBuffer[]; // // void main() // { @@ -1909,7 +1925,7 @@ OpName %nu_ii "nu_ii" OpDecorate %b Location 0 OpMemberDecorate %uname 0 Offset 0 OpDecorate %uname Block -OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer DescriptorSet 6 OpDecorate %uniformBuffer Binding 3 OpDecorate %nu_ii Flat OpDecorate %nu_ii Location 0 @@ -1954,13 +1970,13 @@ OpDecorate %20 NonUniform OpStore %b %20 ; CHECK-NOT: %20 = OpLoad %float %19 ; CHECK-NOT: OpStore %b %20 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_3 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_6 %uint_3 ; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_3 {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_6 %uint_3 {{%\w+}} ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -1969,14 +1985,14 @@ OpStore %b %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 {{%\w+}} %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_1 %uint_6 %uint_3 {{%\w+}} %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result]] {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_0 %uint_6 %uint_3 [[bitcast_result]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}} @@ -1986,7 +2002,7 @@ OpFunctionEnd )"; const std::string new_funcs = - kReadBindingLength + kStreamWrite4Frag + kReadDescInit; + kReadBindingLength + kStreamWrite6Frag + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -2001,7 +2017,7 @@ TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArrayDeprecated) { // layout(location=0) in nonuniformEXT flat int nu_ii; // layout(location=0) out float b; // - // layout(binding=3) buffer bname { float b; } storageBuffer[]; + // layout(set = 7, binding=3) buffer bname { float b; } storageBuffer[]; // // void main() // { @@ -2032,7 +2048,7 @@ OpName %nu_ii "nu_ii" OpDecorate %b Location 0 OpMemberDecorate %bname 0 Offset 0 OpDecorate %bname Block -OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer DescriptorSet 7 OpDecorate %storageBuffer Binding 3 OpDecorate %nu_ii Flat OpDecorate %nu_ii Location 0 @@ -2076,13 +2092,13 @@ OpDecorate %20 NonUniform OpStore %b %20 ; CHECK-NOT: %20 = OpLoad %float %19 ; CHECK-NOT: OpStore %b %20 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_3 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_7 %uint_3 ; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[bitcast_result_1:%\w+]] = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_3 [[bitcast_result_1]] +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_7 %uint_3 [[bitcast_result_1]] ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -2091,14 +2107,14 @@ OpStore %b %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 {{%\w+}} %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_1 %uint_7 %uint_3 {{%\w+}} %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[bitcast_result_2:%\w+]] = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result_2]] {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_0 %uint_7 %uint_3 [[bitcast_result_2]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}} @@ -2108,7 +2124,7 @@ OpFunctionEnd )"; const std::string new_funcs = - kReadBindingLength + kStreamWrite4Frag + kReadDescInit; + kReadBindingLength + kStreamWrite6Frag + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -2203,14 +2219,14 @@ OpStore %b %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 {{%\w+}} %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_1 %uint_0 %uint_3 {{%\w+}} %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 [[bitcast_result]] {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_0 %uint_0 %uint_3 [[bitcast_result]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}} @@ -2220,7 +2236,7 @@ OpFunctionEnd )"; const std::string new_funcs = - kReadBindingLength + kStreamWrite4Frag + kReadDescInit; + kReadBindingLength + kStreamWrite6Frag + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -2233,7 +2249,7 @@ TEST_F(InstBindlessTest, InstInitLoadUBOScalar) { // #extension GL_EXT_nonuniform_qualifier : enable // // layout(location=0) out float b; - // layout(binding=3) uniform uname { float a; } uniformBuffer; + // layout(set=7, binding=3) uniform uname { float a; } uniformBuffer; // // void main() // { @@ -2260,7 +2276,7 @@ OpName %uniformBuffer "uniformBuffer" OpDecorate %b Location 0 OpMemberDecorate %uname 0 Offset 0 OpDecorate %uname Block -OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer DescriptorSet 7 OpDecorate %uniformBuffer Binding 3 ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + kOutputDecorations + R"( @@ -2297,7 +2313,7 @@ OpDecorate %uniformBuffer Binding 3 OpStore %b %16 ; CHECK-NOT: %16 = OpLoad %float %15 ; CHECK-NOT: OpStore %b %16 -; CHECK: [[check_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_3 %uint_0 +; CHECK: [[check_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_7 %uint_3 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[check_result]] ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -2305,7 +2321,7 @@ OpStore %b %16 ; CHECK: {{%\w+}} = OpLoad %float %15 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_32 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_32 %uint_1 %uint_7 %uint_3 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}} @@ -2314,7 +2330,7 @@ OpReturn OpFunctionEnd )"; - const std::string new_funcs = kReadDescInit + kStreamWrite4Frag; + const std::string new_funcs = kReadDescInit + kStreamWrite6Frag; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -2329,7 +2345,7 @@ TEST_F(InstBindlessTest, InstBoundsInitStoreUnsizedSSBOArray) { // layout(location=0) in nonuniformEXT flat int nu_ii; // layout(location=1) in float b; // - // layout(binding=4) buffer bname { float b; } storageBuffer[]; + // layout(set=5, binding=4) buffer bname { float b; } storageBuffer[]; // // void main() // { @@ -2358,7 +2374,7 @@ OpName %nu_ii "nu_ii" OpName %b "b" OpMemberDecorate %bname 0 Offset 0 OpDecorate %bname BufferBlock -OpDecorate %storageBuffer DescriptorSet 0 +OpDecorate %storageBuffer DescriptorSet 5 OpDecorate %storageBuffer Binding 4 OpDecorate %nu_ii Flat OpDecorate %nu_ii Location 0 @@ -2396,13 +2412,13 @@ OpDecorate %b Location 1 %20 = OpAccessChain %_ptr_Uniform_float %storageBuffer %14 %int_0 OpStore %20 %18 ; CHECK-NOT: OpStore %20 %18 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_4 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_5 %uint_4 ; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_4 {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_5 %uint_4 {{%\w+}} ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -2411,13 +2427,13 @@ OpStore %20 %18 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_1 {{%\w+}} %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_1 %uint_5 %uint_4 {{%\w+}} %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_45 %uint_0 {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_0 %uint_5 %uint_4 {{%\w+}} {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel OpReturn @@ -2425,7 +2441,7 @@ OpFunctionEnd )"; const std::string new_funcs = - kReadBindingLength + kStreamWrite4Frag + kReadDescInit; + kReadBindingLength + kStreamWrite6Frag + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -2440,7 +2456,7 @@ TEST_F(InstBindlessTest, InstBoundsInitLoadSizedUBOArray) { // layout(location=0) in nonuniformEXT flat int nu_ii; // layout(location=0) out float b; // - // layout(binding=3) uniform uname { float a; } uniformBuffer[128]; + // layout(set=1, binding=3) uniform uname { float a; } uniformBuffer[128]; // // void main() // { @@ -2470,7 +2486,7 @@ OpName %nu_ii "nu_ii" OpDecorate %b Location 0 OpMemberDecorate %uname 0 Offset 0 OpDecorate %uname Block -OpDecorate %uniformBuffer DescriptorSet 0 +OpDecorate %uniformBuffer DescriptorSet 1 OpDecorate %uniformBuffer Binding 3 OpDecorate %nu_ii Flat OpDecorate %nu_ii Location 0 @@ -2521,7 +2537,7 @@ OpStore %b %22 ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_3 {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_3 {{%\w+}} ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -2530,14 +2546,14 @@ OpStore %b %22 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_46 %uint_1 {{%\w+}} %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_46 %uint_1 %uint_1 %uint_3 {{%\w+}} %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_46 %uint_0 [[bitcast_result]] %uint_128 +; CHECK: {{%\w+}} = OpBitcast %uint %7 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_46 %uint_0 %uint_1 %uint_3 {{%\w+}} %uint_128 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}} @@ -2546,7 +2562,7 @@ OpReturn OpFunctionEnd )"; - const std::string new_funcs = kStreamWrite4Frag + kReadDescInit; + const std::string new_funcs = kStreamWrite6Frag + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -2561,12 +2577,12 @@ TEST_F(InstBindlessTest, // // layout (local_size_x = 1, local_size_y = 1) in; // - // layout(set = 0, binding = 0, std140) buffer Input { + // layout(set = 2, binding = 0, std140) buffer Input { // uint index; // float red; // } sbo; // - // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // layout(set = 2, binding = 1, rgba32f) readonly uniform image2D images[]; // // void main() // { @@ -2595,9 +2611,9 @@ OpName %images "images" OpMemberDecorate %Input 0 Offset 0 OpMemberDecorate %Input 1 Offset 4 OpDecorate %Input BufferBlock -OpDecorate %sbo DescriptorSet 0 +OpDecorate %sbo DescriptorSet 2 OpDecorate %sbo Binding 0 -OpDecorate %images DescriptorSet 0 +OpDecorate %images DescriptorSet 2 OpDecorate %images Binding 1 OpDecorate %images NonWritable ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 @@ -2645,7 +2661,7 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_0 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -2653,19 +2669,19 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpLoad %uint %25 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_47 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_47 %uint_1 %uint_2 %uint_0 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result_1:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} ; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} ; CHECK: %28 = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_2 %uint_1 ; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 [[phi_result_1]] +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_1 [[phi_result_1]] ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -2674,19 +2690,19 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_50 %uint_1 {{%\w+}} %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_50 %uint_1 %uint_2 %uint_1 {{%\w+}} %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_50 %uint_0 {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_50 %uint_0 %uint_2 %uint_1 {{%\w+}} {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %v4float [[phi_result_2]] {{%\w+}} [[null_v4float]] {{%\w+}} ; CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1 -; CHECK: [[desc_state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: [[desc_state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_0 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[desc_state_result]] ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -2694,7 +2710,7 @@ OpStore %31 %29 ; CHECK: OpStore {{%\w+}} {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_53 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_53 %uint_1 %uint_2 %uint_0 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel OpReturn @@ -2702,7 +2718,7 @@ OpFunctionEnd )"; const std::string new_funcs = - kReadBindingLength + kStreamWrite4Compute + kReadDescInit; + kReadBindingLength + kStreamWrite6Compute + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -2716,12 +2732,12 @@ TEST_F(InstBindlessTest, // #extension GL_EXT_nonuniform_qualifier : require // #extension GL_NV_ray_tracing : require // - // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // layout(set = 3, binding = 1, std140) buffer StorageBuffer { // uint index; // float red; // } sbo; // - // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // layout(set = 3, binding = 5, rgba32f) readonly uniform image2D images[]; // // void main() // { @@ -2751,10 +2767,10 @@ OpName %images "images" OpMemberDecorate %StorageBuffer 0 Offset 0 OpMemberDecorate %StorageBuffer 1 Offset 4 OpDecorate %StorageBuffer BufferBlock -OpDecorate %sbo DescriptorSet 0 -OpDecorate %sbo Binding 0 -OpDecorate %images DescriptorSet 0 -OpDecorate %images Binding 1 +OpDecorate %sbo DescriptorSet 3 +OpDecorate %sbo Binding 1 +OpDecorate %images DescriptorSet 3 +OpDecorate %images Binding 5 OpDecorate %images NonWritable ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + kOutputDecorations + R"( @@ -2798,7 +2814,7 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_3 %uint_1 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -2806,19 +2822,19 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpLoad %uint %25 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_3 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} ; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} ; CHECK: %28 = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_3 %uint_5 ; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_3 %uint_5 {{%\w+}} ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -2827,19 +2843,19 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_3 %uint_5 {{%\w+}} %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_3 %uint_5 {{%\w+}} {{%\w+}} ; 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+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_3 %uint_1 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -2847,7 +2863,7 @@ OpStore %31 %29 ; CHECK: OpStore %31 %30 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_3 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel OpReturn @@ -2855,7 +2871,7 @@ OpFunctionEnd )"; const std::string new_funcs = - kReadBindingLength + kStreamWrite4Ray + kReadDescInit; + kReadBindingLength + kStreamWrite6Ray + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -2869,12 +2885,12 @@ TEST_F(InstBindlessTest, // #extension GL_EXT_nonuniform_qualifier : require // #extension GL_NV_ray_tracing : require // - // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // layout(set = 5, binding = 1, std140) buffer StorageBuffer { // uint index; // float red; // } sbo; // - // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // layout(set = 5, binding = 3, rgba32f) readonly uniform image2D images[]; // // void main() // { @@ -2904,10 +2920,10 @@ OpName %images "images" OpMemberDecorate %StorageBuffer 0 Offset 0 OpMemberDecorate %StorageBuffer 1 Offset 4 OpDecorate %StorageBuffer BufferBlock -OpDecorate %sbo DescriptorSet 0 -OpDecorate %sbo Binding 0 -OpDecorate %images DescriptorSet 0 -OpDecorate %images Binding 1 +OpDecorate %sbo DescriptorSet 5 +OpDecorate %sbo Binding 1 +OpDecorate %images DescriptorSet 5 +OpDecorate %images Binding 3 OpDecorate %images NonWritable ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + kOutputDecorations + R"( @@ -2952,7 +2968,7 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_5 %uint_1 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -2960,19 +2976,19 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpLoad %uint %25 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_5 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} ; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} ; CHECK: %28 = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_5 %uint_3 ; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_5 %uint_3 {{%\w+}} ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -2981,19 +2997,19 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_5 %uint_3 {{%\w+}} %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_5 %uint_3 {{%\w+}} {{%\w+}} ; 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+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_5 %uint_1 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -3001,7 +3017,7 @@ OpStore %31 %29 ; CHECK: OpStore %31 %30 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_5 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel OpReturn @@ -3009,7 +3025,7 @@ OpFunctionEnd )"; const std::string new_funcs = - kReadBindingLength + kStreamWrite4Ray + kReadDescInit; + kReadBindingLength + kStreamWrite6Ray + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -3023,12 +3039,12 @@ TEST_F(InstBindlessTest, // #extension GL_EXT_nonuniform_qualifier : require // #extension GL_NV_ray_tracing : require // - // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // layout(set = 2, binding = 1, std140) buffer StorageBuffer { // uint index; // float red; // } sbo; // - // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // layout(set = 2, binding = 3, rgba32f) readonly uniform image2D images[]; // // void main() // { @@ -3058,10 +3074,10 @@ OpName %images "images" OpMemberDecorate %StorageBuffer 0 Offset 0 OpMemberDecorate %StorageBuffer 1 Offset 4 OpDecorate %StorageBuffer BufferBlock -OpDecorate %sbo DescriptorSet 0 -OpDecorate %sbo Binding 0 -OpDecorate %images DescriptorSet 0 -OpDecorate %images Binding 1 +OpDecorate %sbo DescriptorSet 2 +OpDecorate %sbo Binding 1 +OpDecorate %images DescriptorSet 2 +OpDecorate %images Binding 3 OpDecorate %images NonWritable ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + kOutputDecorations + R"( @@ -3106,7 +3122,7 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_1 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -3114,19 +3130,19 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpLoad %uint %25 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_2 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} ; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} ; CHECK: %28 = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_2 %uint_3 ; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_3 {{%\w+}} ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -3135,19 +3151,19 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_2 %uint_3 {{%\w+}} %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_2 %uint_3 {{%\w+}} {{%\w+}} ; 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+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_1 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -3155,7 +3171,7 @@ OpStore %31 %29 ; CHECK: OpStore %31 %30 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_2 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel OpReturn @@ -3163,7 +3179,7 @@ OpFunctionEnd )"; const std::string new_funcs = - kReadBindingLength + kStreamWrite4Ray + kReadDescInit; + kReadBindingLength + kStreamWrite6Ray + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -3177,12 +3193,12 @@ TEST_F(InstBindlessTest, // #extension GL_EXT_nonuniform_qualifier : require // #extension GL_NV_ray_tracing : require // - // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // layout(set = 1, binding = 2, std140) buffer StorageBuffer { // uint index; // float red; // } sbo; // - // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // layout(set = 1, binding = 3, rgba32f) readonly uniform image2D images[]; // // void main() // { @@ -3212,10 +3228,10 @@ OpName %images "images" OpMemberDecorate %StorageBuffer 0 Offset 0 OpMemberDecorate %StorageBuffer 1 Offset 4 OpDecorate %StorageBuffer BufferBlock -OpDecorate %sbo DescriptorSet 0 -OpDecorate %sbo Binding 0 -OpDecorate %images DescriptorSet 0 -OpDecorate %images Binding 1 +OpDecorate %sbo DescriptorSet 1 +OpDecorate %sbo Binding 2 +OpDecorate %images DescriptorSet 1 +OpDecorate %images Binding 3 OpDecorate %images NonWritable ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + kOutputDecorations + R"( @@ -3260,7 +3276,7 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -3268,19 +3284,19 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpLoad %uint %25 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0 ; 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+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_1 %uint_3 ; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_3 {{%\w+}} ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -3289,19 +3305,19 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_1 %uint_3 {{%\w+}} %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_1 %uint_3 {{%\w+}} {{%\w+}} ; 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+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -3309,7 +3325,7 @@ OpStore %31 %29 ; CHECK: OpStore %31 %30 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_1 %uint_2 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel OpReturn @@ -3317,7 +3333,7 @@ OpFunctionEnd )"; const std::string new_funcs = - kReadBindingLength + kStreamWrite4Ray + kReadDescInit; + kReadBindingLength + kStreamWrite6Ray + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -3331,12 +3347,12 @@ TEST_F(InstBindlessTest, // #extension GL_EXT_nonuniform_qualifier : require // #extension GL_NV_ray_tracing : require // - // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // layout(set = 1, binding = 2, std140) buffer StorageBuffer { // uint index; // float red; // } sbo; // - // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // layout(set = 1, binding = 3, rgba32f) readonly uniform image2D images[]; // // void main() // { @@ -3366,10 +3382,10 @@ OpName %images "images" OpMemberDecorate %StorageBuffer 0 Offset 0 OpMemberDecorate %StorageBuffer 1 Offset 4 OpDecorate %StorageBuffer BufferBlock -OpDecorate %sbo DescriptorSet 0 -OpDecorate %sbo Binding 0 -OpDecorate %images DescriptorSet 0 -OpDecorate %images Binding 1 +OpDecorate %sbo DescriptorSet 1 +OpDecorate %sbo Binding 2 +OpDecorate %images DescriptorSet 1 +OpDecorate %images Binding 3 OpDecorate %images NonWritable ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + kOutputDecorations + R"( @@ -3414,7 +3430,7 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT OpStore %31 %29 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -3422,19 +3438,19 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpLoad %uint %25 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0 ; 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+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_1 %uint_3 ; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_3 {{%\w+}} ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -3443,19 +3459,19 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_1 %uint_3 {{%\w+}} %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_1 %uint_3 {{%\w+}} {{%\w+}} ; 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+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -3463,7 +3479,7 @@ OpStore %31 %29 ; CHECK: OpStore %31 %30 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel OpReturn @@ -3471,7 +3487,7 @@ OpFunctionEnd )"; const std::string new_funcs = - kReadBindingLength + kStreamWrite4Ray + kReadDescInit; + kReadBindingLength + kStreamWrite6Ray + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -3485,12 +3501,12 @@ TEST_F(InstBindlessTest, // #extension GL_EXT_nonuniform_qualifier : require // #extension GL_NV_ray_tracing : require // - // layout(set = 0, binding = 0, std140) buffer StorageBuffer { + // layout(set = 1, binding = 2, std140) buffer StorageBuffer { // uint index; // float red; // } sbo; // - // layout(set = 0, binding = 1, rgba32f) readonly uniform image2D images[]; + // layout(set = 1, binding = 3, rgba32f) readonly uniform image2D images[]; // // void main() // { @@ -3520,10 +3536,10 @@ OpName %images "images" OpMemberDecorate %StorageBuffer 0 Offset 0 OpMemberDecorate %StorageBuffer 1 Offset 4 OpDecorate %StorageBuffer BufferBlock -OpDecorate %sbo DescriptorSet 0 -OpDecorate %sbo Binding 0 -OpDecorate %images DescriptorSet 0 -OpDecorate %images Binding 1 +OpDecorate %sbo DescriptorSet 1 +OpDecorate %sbo Binding 2 +OpDecorate %images DescriptorSet 1 +OpDecorate %images Binding 3 OpDecorate %images NonWritable ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 )" + kInputDecorations + kOutputDecorations + R"( @@ -3567,7 +3583,7 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -3575,19 +3591,19 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpLoad %uint %25 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_48 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} ; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} ; CHECK: %28 = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_1 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_1 %uint_3 ; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_3 {{%\w+}} ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -3596,19 +3612,19 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_1 {{%\w+}} %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_1 %uint_3 {{%\w+}} %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_51 %uint_0 {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_1 %uint_3 {{%\w+}} {{%\w+}} ; 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+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -3616,7 +3632,7 @@ OpStore %31 %29 ; CHECK: OpStore %31 %30 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_54 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel OpReturn @@ -3624,7 +3640,7 @@ OpFunctionEnd )"; const std::string new_funcs = - kReadBindingLength + kStreamWrite4Ray + kReadDescInit; + kReadBindingLength + kStreamWrite6Ray + kReadDescInit; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -3644,13 +3660,13 @@ TEST_F(InstBindlessTest, InstBoundsInitSameBlockOpReplication) { // layout(location = 0) in vec2 inTexcoord; // layout(location = 0) out vec4 outColor; // - // layout(set = 0, binding = 0) uniform Uniforms { + // layout(set = 1, binding = 0) uniform Uniforms { // vec2 var0; // } uniforms; // - // layout(set = 0, binding = 1) uniform sampler uniformSampler; - // layout(set = 0, binding = 2) uniform texture2D uniformTex; - // layout(set = 0, binding = 3) uniform texture2D uniformTexArr[8]; + // layout(set = 1, binding = 1) uniform sampler uniformSampler; + // layout(set = 1, binding = 2) uniform texture2D uniformTex; + // layout(set = 1, binding = 3) uniform texture2D uniformTexArr[8]; // // void main() { // int index = 0; @@ -3685,18 +3701,18 @@ OpName %Uniforms "Uniforms" OpMemberName %Uniforms 0 "var0" OpName %uniforms "uniforms" OpName %outColor "outColor" -OpDecorate %uniformTexArr DescriptorSet 0 +OpDecorate %uniformTexArr DescriptorSet 1 OpDecorate %uniformTexArr Binding 3 OpDecorate %19 NonUniformEXT OpDecorate %22 NonUniformEXT -OpDecorate %uniformSampler DescriptorSet 0 +OpDecorate %uniformSampler DescriptorSet 1 OpDecorate %uniformSampler Binding 1 OpDecorate %inTexcoord Location 0 -OpDecorate %uniformTex DescriptorSet 0 +OpDecorate %uniformTex DescriptorSet 1 OpDecorate %uniformTex Binding 2 OpMemberDecorate %Uniforms 0 Offset 0 OpDecorate %Uniforms Block -OpDecorate %uniforms DescriptorSet 0 +OpDecorate %uniforms DescriptorSet 1 OpDecorate %uniforms Binding 0 OpDecorate %outColor Location 0 ; CHECK: OpDecorate %63 NonUniform @@ -3769,7 +3785,7 @@ OpStore %x %36 %50 = OpImageSampleImplicitLod %v4float %41 %49 %51 = OpCompositeExtract %float %50 0 ; CHECK-NOT: %51 = OpCompositeExtract %float %50 0 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_0 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -3777,13 +3793,13 @@ OpStore %x %36 ; CHECK: {{%\w+}} = OpLoad %v2float %47 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_87 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_87 %uint_1 %uint_1 %uint_0 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} ; CHECK: %49 = OpFMul %v2float %42 {{%\w+}} ; CHECK: {{%\w+}} = OpSampledImage %27 %39 %40 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_2 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0 ; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -3793,7 +3809,7 @@ OpStore %x %36 ; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %49 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_89 %uint_1 %uint_0 %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_89 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} @@ -3807,7 +3823,7 @@ OpReturn OpFunctionEnd )"; - const std::string new_funcs = kStreamWrite4Frag + kReadDescInit; + const std::string new_funcs = kStreamWrite6Frag + kReadDescInit; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + new_funcs, @@ -3950,7 +3966,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: {{%\w+}} = OpLoad %v2float %86 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel - ;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_71 %uint_4 %uint_0 %119 {{%\w+}} + ;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_71 %uint_4 %uint_0 %uint_1 %uint_0 %119 {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} @@ -3967,7 +3983,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { ;CHECK: {{%\w+}} = OpLoad %v2float %89 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel - ;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_75 %uint_4 %uint_0 {{%\w+}} {{%\w+}} + ;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_75 %uint_4 %uint_0 %uint_1 %uint_0 {{%\w+}} {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} @@ -3984,7 +4000,7 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { OpStore %_entryPointOutput_vColor %100 OpReturn OpFunctionEnd -)" + kReadDescInit + kStreamWrite5Frag; +)" + kReadDescInit + kStreamWrite7Frag; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -4136,7 +4152,7 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { ;CHECK: {{%\w+}} = OpLoad %v2float %81 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_78 %uint_4 %uint_0 {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_78 %uint_4 %uint_0 %uint_2 %uint_0 {{%\w+}} {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} @@ -4150,7 +4166,7 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { OpStore %_entryPointOutput_vColor %91 OpReturn OpFunctionEnd -)" + kReadDescInit + kStreamWrite5Frag; +)" + kReadDescInit + kStreamWrite7Frag; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -4277,7 +4293,7 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: {{%\w+}} = OpLoad %v2float %81 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_78 %uint_4 %uint_0 {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_78 %uint_4 %uint_0 %uint_2 %uint_0 {{%\w+}} {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} @@ -4298,14 +4314,14 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %86 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_83 %uint_1 %uint_0 %uint_0 %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_83 %uint_1 %uint_0 %uint_0 %uint_0 %uint_0 %uint_0 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} ;CHECK: OpStore %_entryPointOutput_vColor {{%\w+}} OpReturn OpFunctionEnd -)" + kReadDescInit + kStreamWrite5Frag; +)" + kReadDescInit + kStreamWrite7Frag; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -4340,12 +4356,12 @@ TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { OpName %g_sAniso "g_sAniso" OpName %i_vTextureCoords "i.vTextureCoords" OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" - OpDecorate %g_tColor DescriptorSet 0 - OpDecorate %g_tColor Binding 0 + OpDecorate %g_tColor DescriptorSet 1 + OpDecorate %g_tColor Binding 2 OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 OpDecorate %PerViewConstantBuffer_t Block - OpDecorate %g_sAniso DescriptorSet 0 - OpDecorate %g_sAniso Binding 0 + 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 @@ -4386,8 +4402,8 @@ TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { )" + kInputGlobals + R"( %MainPs = OpFunction %void None %10 %30 = OpLabel -;CHECK: OpBranch %108 -;CHECK: %108 = OpLabel +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel ;CHECK: OpBranch %39 ;CHECK: %39 = OpLabel %31 = OpLoad %v2float %i_vTextureCoords @@ -4409,7 +4425,7 @@ TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { ;CHECK: {{%\w+}} = OpLoad %16 %34 ;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %36 ;CHECK: {{%\w+}} = OpUConvert %uint %33 -;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 {{%\w+}} ;CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} @@ -4420,20 +4436,20 @@ TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpUConvert %uint %33 -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_60 %uint_1 {{%\w+}} %uint_0 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_60 %uint_1 %uint_1 %uint_2 {{%\w+}} %uint_0 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} ;CHECK: OpBranch %44 ;CHECK: %46 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_4 %uint_60 %uint_0 %41 %uint_128 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_60 %uint_0 %uint_1 %uint_2 %41 %uint_128 ;CHECK: OpBranch %44 ;CHECK: %44 = OpLabel ;CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float [[phi_result_1]] {{%\w+}} [[null_v4float]] %46 ;CHECK: OpStore %_entryPointOutput_vColor [[phi_result_2]] OpReturn OpFunctionEnd -)" + kStreamWrite4Frag + kReadDescInit; +)" + kStreamWrite6Frag + kReadDescInit; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -4591,7 +4607,7 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { ;CHECK: {{%\w+}} = OpLoad %v2float %41 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_81 %uint_4 %uint_0 {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_81 %uint_4 %uint_0 %uint_0 %uint_0 {{%\w+}} {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} @@ -4603,7 +4619,7 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { OpStore %_entryPointOutput_vColor %47 OpReturn OpFunctionEnd - )" + kReadDescInit + kStreamWrite5Frag; + )" + kReadDescInit + kStreamWrite7Frag; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -4713,7 +4729,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;CHECK: [[load_result]] = OpLoad %float %20 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_45 %uint_4 %uint_0 {{%\w+}} {{%\w+}} +;CHECK: {{\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_45 %uint_4 %uint_0 %uint_0 %uint_0 {{%\w+}} {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[phi_result]] = OpPhi %float [[load_result]] {{%\w+}} [[null_float]] {{%\w+}} @@ -4722,7 +4738,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;CHECK: OpStore %v_vtxResult [[phi_result]] OpReturn OpFunctionEnd - )" + kReadDescInit + kStreamWrite5Vert; + )" + kReadDescInit + kStreamWrite7Vert; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -4832,7 +4848,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { ;CHECK:[[load_result]] = OpLoad %float %20 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_45 %uint_4 %uint_0 %35 {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_45 %uint_4 %uint_0 %uint_0 %uint_0 %35 {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[phi_result]] = OpPhi %float [[load_result]] {{%\w+}} [[null_float]] {{%\w+}} @@ -4841,7 +4857,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { ;CHECK: OpStore %v_vtxResult [[phi_result]] OpReturn OpFunctionEnd - )" + kReadDescInit + kStreamWrite5Vert; + )" + kReadDescInit + kStreamWrite7Vert; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -4860,7 +4876,7 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { // layout(location = 0) in highp vec4 a_position; // layout(location = 0) out highp vec2 v_vtxResult; // - // layout(set = 0, binding = 0, std430, row_major) uniform Block + // layout(set = 3, binding = 7, std430, row_major) uniform Block // { // lowp mat2 var[3][4]; // }; @@ -4894,8 +4910,8 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { OpMemberDecorate %Block 0 Offset 0 OpMemberDecorate %Block 0 MatrixStride 16 OpDecorate %Block Block - OpDecorate %_ DescriptorSet 0 - OpDecorate %_ Binding 0 + OpDecorate %_ DescriptorSet 3 + OpDecorate %_ Binding 7 OpDecorate %26 RelaxedPrecision ;CHECK-NOT: OpDecorate %26 RelaxedPrecision ;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision @@ -4937,7 +4953,7 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float %main = OpFunction %void None %3 %5 = OpLabel -;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 +;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_3 %uint_7 %uint_0 ;CHECK: OpBranch %31 ;CHECK: %31 = OpLabel ;CHECK: OpBranch %30 @@ -4961,14 +4977,14 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { ;CHECK: [[load_result]] = OpLoad %v2float %25 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_51 %uint_4 %uint_0 {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_51 %uint_4 %uint_3 %uint_7 %uint_0 {{%\w+}} {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[phi_result]] = OpPhi %v2float [[load_result]] {{%\w+}} [[null_v2float]] {{%\w+}} ;CHECK: OpStore %v_vtxResult [[phi_result]] OpReturn OpFunctionEnd - )" + kReadDescInit + kStreamWrite5Vert; + )" + kReadDescInit + kStreamWrite7Vert; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -5057,14 +5073,14 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { ;CHECK: %33 = OpImageRead %v4float %32 %17 ;CHECK: OpBranch %29 ;CHECK: %31 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_33 %uint_7 %uint_0 %23 %25 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_33 %uint_7 %uint_3 %uint_7 %uint_0 %23 %25 ;CHECK: OpBranch %29 ;CHECK: %29 = OpLabel -;CHECK: %94 = OpPhi %v4float %33 %30 [[null_v4float]] %31 -;CHECK: OpStore %x %94 +;CHECK: [[phi_result:%\w+]] = OpPhi %v4float %33 %30 [[null_v4float]] %31 +;CHECK: OpStore %x [[phi_result]] OpReturn OpFunctionEnd - )" + kStreamWrite5Frag; + )" + kStreamWrite7Frag; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -5154,12 +5170,12 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { ;CHECK: OpImageWrite %32 %14 %18 ;CHECK: OpBranch %29 ;CHECK: %31 = OpLabel -;CHECK: %91 = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_34 %uint_7 %uint_0 %23 %25 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_34 %uint_7 %uint_3 %uint_7 %uint_0 %23 %25 ;CHECK: OpBranch %29 ;CHECK: %29 = OpLabel OpReturn OpFunctionEnd - )" + kStreamWrite5Frag; + )" + kStreamWrite7Frag; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -5248,14 +5264,14 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { ;CHECK: %33 = OpImageFetch %v4float %32 %17 ;CHECK: OpBranch %29 ;CHECK: %31 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_32 %uint_6 %uint_0 %23 %25 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_32 %uint_6 %uint_3 %uint_7 %uint_0 %23 %25 ;CHECK: OpBranch %29 ;CHECK: %29 = OpLabel -;CHECK: %95 = OpPhi %v4float %33 %30 [[null_v4float]] %31 -;CHECK: OpStore %x %95 +;CHECK: [[phi_result:%\w+]] = OpPhi %v4float %33 %30 [[null_v4float]] %31 +;CHECK: OpStore %x [[phi_result]] OpReturn OpFunctionEnd - )" + kStreamWrite5Frag; + )" + kStreamWrite7Frag; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -5347,14 +5363,14 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { ;CHECK: %36 = OpImageFetch %v4float %35 %18 ;CHECK: OpBranch %31 ;CHECK: %33 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_34 %uint_6 %uint_0 %25 %27 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_34 %uint_6 %uint_3 %uint_7 %uint_0 %25 %27 ;CHECK: OpBranch %31 ;CHECK: %31 = OpLabel -;CHECK: %98 = OpPhi %v4float %36 %32 [[null_v4float]] %33 -;CHECK: OpStore %x %98 +;CHECK: [[phi_result:%\w+]] = OpPhi %v4float %36 %32 [[null_v4float]] %33 +;CHECK: OpStore %x [[phi_result]] OpReturn OpFunctionEnd - )" + kStreamWrite5Frag; + )" + kStreamWrite7Frag; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -5456,14 +5472,14 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { ;CHECK: %42 = OpImageFetch %v4float %41 %23 ;CHECK: OpBranch %36 ;CHECK: %38 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_42 %uint_6 %uint_0 %30 %32 +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_42 %uint_6 %uint_3 %uint_7 %uint_0 %30 %32 ;CHECK: OpBranch %36 ;CHECK: %36 = OpLabel -;CHECK: %104 = OpPhi %v4float %42 %37 [[null_v4float]] %38 -;CHECK: OpStore %x %104 +;CHECK: [[phi_result:%\w+]] = OpPhi %v4float %42 %37 [[null_v4float]] %38 +;CHECK: OpStore %x [[phi_result]] OpReturn OpFunctionEnd - )" + kStreamWrite5Frag; + )" + kStreamWrite7Frag; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -5568,7 +5584,7 @@ OpBranch %14 ;CHECK: [[load_result:%\w+]] = OpLoad %int %26 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_54 %uint_4 %uint_0 {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_54 %uint_4 %uint_0 %uint_0 %uint_0 {{%\w+}} {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[phi_result:%\w+]] = OpPhi %int [[load_result]] {{%\w+}} {{%\w+}} {{%\w+}} @@ -5586,7 +5602,7 @@ OpBranchConditional %29 %11 %12 ;CHECK: [[load_result_2:%\w+]] = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_5 %uint_59 %uint_4 %uint_0 {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_59 %uint_4 %uint_0 %uint_0 %uint_0 {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_bufStruct {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -5605,7 +5621,7 @@ OpBranch %10 %12 = OpLabel OpReturn OpFunctionEnd)" - + kReadDescInit + kStreamWrite5Vert; + + kReadDescInit + kStreamWrite7Vert; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); From a525dccbe8058c42079a67a49e7aa9973d67de27 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 09:19:52 -0400 Subject: [PATCH 136/523] roll deps (#5209) * Roll external/googletest/ 797b0ad2a..f345b2ca6 (1 commit) https://github.com/google/googletest/compare/797b0ad2a3a4...f345b2ca6adb $ git log 797b0ad2a..f345b2ca6 --date=short --no-merges --format='%ad %ae %s' 2023-04-25 julian.amann Fix spelling Created with: roll-dep external/googletest * Roll external/re2/ 11073deb7..c9cba7606 (1 commit) https://github.com/google/re2/compare/11073deb73b3...c9cba76063cf $ git log 11073deb7..c9cba7606 --date=short --no-merges --format='%ad %ae %s' 2023-05-01 junyer Add GCC 13 to the build matrix. 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 86525ce027..b2a90a5ccb 100644 --- a/DEPS +++ b/DEPS @@ -5,12 +5,12 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': '797b0ad2a3a45608ecf5c67e6e289d377a3521ca', + 'googletest_revision': 'f345b2ca6adb1b505049190867eedf24d3b5eaa3', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '11073deb73b3d01018308863c0bcdfd0d51d3e70', + 're2_revision': 'c9cba76063cf4235c1a15dd14a24a4ef8d623761', 'spirv_headers_revision': '7f1d2f4158704337aff1f739c8e494afc5716e7e', } From 17be6bb7c31c423653f9e1940e407db5c1a5c138 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 3 May 2023 10:29:01 -0400 Subject: [PATCH 137/523] Roll external/googletest/ f345b2ca6..a3580180d (2 commits) (#5210) https://github.com/google/googletest/compare/f345b2ca6adb...a3580180d169 $ git log f345b2ca6..a3580180d --date=short --no-merges --format='%ad %ae %s' 2022-11-24 luoyonggang Fixes the test gmock_output_test.py with MSVC 2023-02-09 luoyonggang Revert "Fix gmock_output_test when using MSVC" 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 b2a90a5ccb..62c05480c5 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': 'f345b2ca6adb1b505049190867eedf24d3b5eaa3', + 'googletest_revision': 'a3580180d16923d6d5f488e20b3814608a892f17', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From 2189ad7a5aadc2accb9250a1e7ed08e3b49df01b Mon Sep 17 00:00:00 2001 From: Sruthik P Date: Wed, 3 May 2023 20:55:17 +0530 Subject: [PATCH 138/523] spirv-tools: Add support for QNX (#5211) This change updates CMakeLists.txt to support building for QNX platforms. --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 75830b44c4..71cdc00c46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2015-2016 The Khronos Group Inc. +# Copyright (c) 2015-2023 The Khronos Group Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -64,6 +64,8 @@ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Fuchsia") add_definitions(-DSPIRV_FUCHSIA) elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "GNU") add_definitions(-DSPIRV_GNU) +elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "QNX") + add_definitions(-DSPIRV_QNX) else() message(FATAL_ERROR "Your platform '${CMAKE_SYSTEM_NAME}' is not supported!") endif() From 65f03bea4e414d0d80f4376ccbc0202269924f2b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 4 May 2023 13:46:10 +0200 Subject: [PATCH 139/523] Roll external/spirv-headers/ 7f1d2f415..268a06176 (2 commits) (#5214) https://github.com/KhronosGroup/SPIRV-Headers/compare/7f1d2f415870...268a061764ee $ git log 7f1d2f415..268a06176 --date=short --no-merges --format='%ad %ae %s' 2023-05-03 devillers Reserve a single block of opcodes and enumerants for Saarland University (#343) 2023-04-06 duncan.brawley Shift Codeplay opcode range to preserve alignment of opcodes and non-opcodes 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 62c05480c5..656ad18d9d 100644 --- a/DEPS +++ b/DEPS @@ -11,7 +11,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': 'c9cba76063cf4235c1a15dd14a24a4ef8d623761', - 'spirv_headers_revision': '7f1d2f4158704337aff1f739c8e494afc5716e7e', + 'spirv_headers_revision': '268a061764ee69f09a477a695bf6a11ffe311b8d', } deps = { From 01055c60cfc0cddd2724dc674ed73d09df992360 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 4 May 2023 11:13:17 -0400 Subject: [PATCH 140/523] Update the contributing guidelines (#5212) The instructions on merging a PR are out of date. They have be updated to match the current process. --- CONTRIBUTING.md | 122 +++++++++++++++++------------------------------- 1 file changed, 43 insertions(+), 79 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1eb8b689e8..893998e1b5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,9 +2,8 @@ ## 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) +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) for more. To report a new bug or request a new feature, please file a GitHub issue. Please @@ -36,9 +35,9 @@ create a new issue, as with bugs. In the issue provide ## For developers: Contributing a patch -Before we can use your code, you must sign the [Khronos Open Source Contributor -License Agreement](https://cla-assistant.io/KhronosGroup/SPIRV-Tools) (CLA), -which you can do online. The CLA is necessary mainly because you own the +Before we can use your code, you must sign the +[Khronos Open Source Contributor License Agreement](https://cla-assistant.io/KhronosGroup/SPIRV-Tools) +(CLA), which you can do online. The CLA is necessary mainly because you own the copyright to your changes, even after your contribution becomes part of our codebase, so we need your permission to use and distribute your code. We also need to be sure of various other things -- for instance that you'll tell us if @@ -51,16 +50,16 @@ See for instruction on how to get, build, and test the source. Once you have made your changes: -* Ensure the code follows the [Google C++ Style - Guide](https://google.github.io/styleguide/cppguide.html). Running - `clang-format -style=file -i [modified-files]` can help. +* Ensure the code follows the + [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html). + Running `clang-format -style=file -i [modified-files]` can help. * Create a pull request (PR) with your patch. * Make sure the PR description clearly identified the problem, explains the solution, and references the issue if applicable. * 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. + `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. * Watch the continuous builds to make sure they pass. * Request a code review. @@ -82,8 +81,8 @@ Instructions for this are given below. The formal code reviews are done on GitHub. Reviewers are to look for all of the usual things: -* Coding style follows the [Google C++ Style - Guide](https://google.github.io/styleguide/cppguide.html) +* Coding style follows the + [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) * Identify potential functional problems. * Identify code duplication. * Ensure the unit tests have enough coverage. @@ -102,84 +101,49 @@ should pay particular attention to: updated. For example, a new instruction is added, but the def-use manager is not updated. Later on, it is possible that the def-use manager will be used, and give wrong results. +* If a pass gets the id of a type from the type manager, make sure the type is + not a struct or array. It there are two structs that look the same, the type + manager can return the wrong one. ## For maintainers: Merging a PR We intend to maintain a linear history on the GitHub master 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. +find which commit introduced a bug. The +[Squash and Merge](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/about-pull-request-merges#squash-and-merge-your-commits) +button on the GitHub web interface. All other ways of merging on the web +interface have been disabled. -### Initial merge setup +Before merging, we generally require: -The following steps should be done exactly once (when you are about to merge a -PR for the first time): +1. All tests except for the smoke test pass. See + [failing smoke test](#failing-smoke-test). +1. The PR is approved by at least one of the maintainers. If the PR modifies + different parts of the code, then multiple reviewers might be necessary. -* It is assumed that upstream points to - [git@github.com](mailto:git@github.com):KhronosGroup/SPIRV-Tools.git or - https://github.com/KhronosGroup/SPIRV-Tools.git. +The squash-and-merge button will turn green when these requirements are met. +Maintainers have the to power to merge even if the button is not green, but that +is discouraged. -* Find out the local name for the main github repo in your git configuration. - For example, in this configuration, it is labeled `upstream`. +### Failing smoke test - ``` - git remote -v - [ ... ] - upstream https://github.com/KhronosGroup/SPIRV-Tools.git (fetch) - upstream https://github.com/KhronosGroup/SPIRV-Tools.git (push) - ``` +The purpose of the smoke test is to let us know if +[shaderc](https://github.com/google/shaderc) fails to build with the change. If +it fails, the maintainer needs to determine if the reason for the failure is a +problem in the current PR or if another repository needs to be changed. Most of +the time [Glslang](https://github.com/KhronosGroup/glslang) needs to be updated +to account for the change in SPIR-V Tools. -* Make sure that the `upstream` remote is set to fetch from the `refs/pull` - namespace: +The PR can still be merged if the problem is not with that PR. - ``` - git config --get-all remote.upstream.fetch - +refs/heads/*:refs/remotes/upstream/* - +refs/pull/*/head:refs/remotes/upstream/pr/* - ``` +## For maintainers: Running tests -* If the line `+refs/pull/*/head:refs/remotes/upstream/pr/*` is not present in - your configuration, you can add it with the command: +For security reasons, not all tests will run automatically. When they do not, a +maintainer will have to start the tests. - ``` - git config --local --add remote.upstream.fetch '+refs/pull/*/head:refs/remotes/upstream/pr/*' - ``` +If the Github actions tests do not run on a PR, they can be initiated by closing +and reopening the PR. -### Merge workflow - -The following steps should be done for every PR that you intend to merge: - -* Make sure your local copy of the master branch is up to date: - - ``` - git checkout master - git pull - ``` - -* Fetch all pull requests refs: - - ``` - git fetch upstream - ``` - -* Checkout the particular pull request you are going to review: - - ``` - git checkout pr/1048 - ``` - -* Rebase the PR on top of the master branch. If there are conflicts, send it - back to the author and ask them to rebase. During the interactive rebase be - sure to squash all of the commits down to a single commit. - - ``` - git rebase -i master - ``` - -* **Build and test the PR.** - -* If all of the tests pass, push the commit `git push upstream HEAD:master` - -* Close the PR and add a comment saying it was push using the commit that you - just pushed. See https://github.com/KhronosGroup/SPIRV-Tools/pull/935 as an - example. +If the kokoro tests are not run, they can be run by adding the label +`kokoro:run` to the PR. From 8993f9f52ffd57ebeeaf47257accfe4ac2e22f57 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Mon, 8 May 2023 09:39:14 -0400 Subject: [PATCH 141/523] Apply scalar replacement on vars with Pointer decorations (#5208) We want to be able to apply scalar replacement on variables that have the AliasPointer and RestrictPointer decorations. This exposed a bug that needs to be fixed as well. Scalar replacement sometimes uses the type manager to get the type id for the variables it is creating. The variable type is a pointer to a pointee type. Currently, scalar replacement uses the type manager when only if the pointee type has to be unique in the module. This is done to try to avoid the case where two type hash to the same value in the type manager, and it returns the wrong one. However, this check is not the correct check. Pointer types still have to be unique in the spir-v module. However, two unique pointer types can hash to the same value if their pointee types are isomorphic. For example, %s1 = OpTypeStruct %int %s2 = OpTypeStruct %int ; %p1 and %p2 will hash to the same value even though they are still ; considered "unique". %p1 = OpTypePointer Function %s1 %p2 = OpTypePointer Function %s2 To fix this, we now use FindPointerToType, and we modified TypeManager::IsUnique to refer to the whether or not a type will hash to a unique value and say that pointers are not unique. Fixes #5196 --- source/opt/scalar_replacement_pass.cpp | 162 ++++++++++++------------- source/opt/scalar_replacement_pass.h | 17 +++ source/opt/type_manager.cpp | 4 +- source/opt/types.cpp | 3 +- source/opt/types.h | 14 ++- test/opt/scalar_replacement_test.cpp | 48 ++++++++ test/opt/types_test.cpp | 9 +- 7 files changed, 159 insertions(+), 98 deletions(-) diff --git a/source/opt/scalar_replacement_pass.cpp b/source/opt/scalar_replacement_pass.cpp index ae1a2a363e..38c8aeccc6 100644 --- a/source/opt/scalar_replacement_pass.cpp +++ b/source/opt/scalar_replacement_pass.cpp @@ -466,9 +466,9 @@ void ScalarReplacementPass::TransferAnnotations( } void ScalarReplacementPass::CreateVariable( - uint32_t typeId, Instruction* varInst, uint32_t index, + uint32_t type_id, Instruction* var_inst, uint32_t index, std::vector* replacements) { - uint32_t ptrId = GetOrCreatePointerType(typeId); + uint32_t ptr_id = GetOrCreatePointerType(type_id); uint32_t id = TakeNextId(); if (id == 0) { @@ -476,51 +476,22 @@ void ScalarReplacementPass::CreateVariable( } std::unique_ptr variable( - new Instruction(context(), spv::Op::OpVariable, ptrId, id, + new Instruction(context(), spv::Op::OpVariable, ptr_id, id, std::initializer_list{ {SPV_OPERAND_TYPE_STORAGE_CLASS, {uint32_t(spv::StorageClass::Function)}}})); - BasicBlock* block = context()->get_instr_block(varInst); + BasicBlock* block = context()->get_instr_block(var_inst); block->begin().InsertBefore(std::move(variable)); Instruction* inst = &*block->begin(); // If varInst was initialized, make sure to initialize its replacement. - GetOrCreateInitialValue(varInst, index, inst); + GetOrCreateInitialValue(var_inst, index, inst); get_def_use_mgr()->AnalyzeInstDefUse(inst); context()->set_instr_block(inst, block); - // Copy decorations from the member to the new variable. - Instruction* typeInst = GetStorageType(varInst); - for (auto dec_inst : - get_decoration_mgr()->GetDecorationsFor(typeInst->result_id(), false)) { - uint32_t decoration; - if (dec_inst->opcode() != spv::Op::OpMemberDecorate) { - continue; - } - - if (dec_inst->GetSingleWordInOperand(1) != index) { - continue; - } - - decoration = dec_inst->GetSingleWordInOperand(2u); - switch (spv::Decoration(decoration)) { - case spv::Decoration::RelaxedPrecision: { - std::unique_ptr new_dec_inst( - new Instruction(context(), spv::Op::OpDecorate, 0, 0, {})); - new_dec_inst->AddOperand(Operand(SPV_OPERAND_TYPE_ID, {id})); - for (uint32_t i = 2; i < dec_inst->NumInOperandWords(); ++i) { - new_dec_inst->AddOperand(Operand(dec_inst->GetInOperand(i))); - } - context()->AddAnnotationInst(std::move(new_dec_inst)); - } break; - default: - break; - } - } - - // Update the DebugInfo debug information. - inst->UpdateDebugInfoFrom(varInst); + CopyDecorationsToVariable(var_inst, inst, index); + inst->UpdateDebugInfoFrom(var_inst); replacements->push_back(inst); } @@ -529,52 +500,11 @@ uint32_t ScalarReplacementPass::GetOrCreatePointerType(uint32_t id) { auto iter = pointee_to_pointer_.find(id); if (iter != pointee_to_pointer_.end()) return iter->second; - analysis::Type* pointeeTy; - std::unique_ptr pointerTy; - std::tie(pointeeTy, pointerTy) = - context()->get_type_mgr()->GetTypeAndPointerType( - id, spv::StorageClass::Function); - uint32_t ptrId = 0; - if (pointeeTy->IsUniqueType()) { - // Non-ambiguous type, just ask the type manager for an id. - ptrId = context()->get_type_mgr()->GetTypeInstruction(pointerTy.get()); - pointee_to_pointer_[id] = ptrId; - return ptrId; - } - - // Ambiguous type. We must perform a linear search to try and find the right - // type. - for (auto global : context()->types_values()) { - if (global.opcode() == spv::Op::OpTypePointer && - spv::StorageClass(global.GetSingleWordInOperand(0u)) == - spv::StorageClass::Function && - global.GetSingleWordInOperand(1u) == id) { - if (get_decoration_mgr()->GetDecorationsFor(id, false).empty()) { - // Only reuse a decoration-less pointer of the correct type. - ptrId = global.result_id(); - break; - } - } - } - - if (ptrId != 0) { - pointee_to_pointer_[id] = ptrId; - return ptrId; - } - - ptrId = TakeNextId(); - context()->AddType(MakeUnique( - context(), spv::Op::OpTypePointer, 0, ptrId, - std::initializer_list{{SPV_OPERAND_TYPE_STORAGE_CLASS, - {uint32_t(spv::StorageClass::Function)}}, - {SPV_OPERAND_TYPE_ID, {id}}})); - Instruction* ptr = &*--context()->types_values_end(); - get_def_use_mgr()->AnalyzeInstDefUse(ptr); - pointee_to_pointer_[id] = ptrId; - // Register with the type manager if necessary. - context()->get_type_mgr()->RegisterType(ptrId, *pointerTy); - - return ptrId; + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + uint32_t ptr_type_id = + type_mgr->FindPointerToType(id, spv::StorageClass::Function); + pointee_to_pointer_[id] = ptr_type_id; + return ptr_type_id; } void ScalarReplacementPass::GetOrCreateInitialValue(Instruction* source, @@ -761,6 +691,8 @@ bool ScalarReplacementPass::CheckTypeAnnotations( case spv::Decoration::AlignmentId: case spv::Decoration::MaxByteOffset: case spv::Decoration::RelaxedPrecision: + case spv::Decoration::AliasedPointer: + case spv::Decoration::RestrictPointer: break; default: return false; @@ -781,6 +713,8 @@ bool ScalarReplacementPass::CheckAnnotations(const Instruction* varInst) const { case spv::Decoration::Alignment: case spv::Decoration::AlignmentId: case spv::Decoration::MaxByteOffset: + case spv::Decoration::AliasedPointer: + case spv::Decoration::RestrictPointer: break; default: return false; @@ -1011,5 +945,69 @@ uint64_t ScalarReplacementPass::GetMaxLegalIndex( return 0; } +void ScalarReplacementPass::CopyDecorationsToVariable(Instruction* from, + Instruction* to, + uint32_t member_index) { + CopyPointerDecorationsToVariable(from, to); + CopyNecessaryMemberDecorationsToVariable(from, to, member_index); +} + +void ScalarReplacementPass::CopyPointerDecorationsToVariable(Instruction* from, + Instruction* to) { + // The RestrictPointer and AliasedPointer decorations are copied to all + // members even if the new variable does not contain a pointer. It does + // not hurt to do so. + for (auto dec_inst : + get_decoration_mgr()->GetDecorationsFor(from->result_id(), false)) { + uint32_t decoration; + decoration = dec_inst->GetSingleWordInOperand(1u); + switch (spv::Decoration(decoration)) { + case spv::Decoration::AliasedPointer: + case spv::Decoration::RestrictPointer: { + std::unique_ptr new_dec_inst(dec_inst->Clone(context())); + new_dec_inst->SetInOperand(0, {to->result_id()}); + context()->AddAnnotationInst(std::move(new_dec_inst)); + } break; + default: + break; + } + } +} + +void ScalarReplacementPass::CopyNecessaryMemberDecorationsToVariable( + Instruction* from, Instruction* to, uint32_t member_index) { + Instruction* type_inst = GetStorageType(from); + for (auto dec_inst : + get_decoration_mgr()->GetDecorationsFor(type_inst->result_id(), false)) { + uint32_t decoration; + if (dec_inst->opcode() == spv::Op::OpMemberDecorate) { + if (dec_inst->GetSingleWordInOperand(1) != member_index) { + continue; + } + + decoration = dec_inst->GetSingleWordInOperand(2u); + switch (spv::Decoration(decoration)) { + case spv::Decoration::ArrayStride: + case spv::Decoration::Alignment: + case spv::Decoration::AlignmentId: + case spv::Decoration::MaxByteOffset: + case spv::Decoration::MaxByteOffsetId: + case spv::Decoration::RelaxedPrecision: { + std::unique_ptr new_dec_inst( + new Instruction(context(), spv::Op::OpDecorate, 0, 0, {})); + new_dec_inst->AddOperand( + Operand(SPV_OPERAND_TYPE_ID, {to->result_id()})); + for (uint32_t i = 2; i < dec_inst->NumInOperandWords(); ++i) { + new_dec_inst->AddOperand(Operand(dec_inst->GetInOperand(i))); + } + context()->AddAnnotationInst(std::move(new_dec_inst)); + } break; + default: + break; + } + } + } +} + } // namespace opt } // namespace spvtools diff --git a/source/opt/scalar_replacement_pass.h b/source/opt/scalar_replacement_pass.h index 0bcd2a4e40..c73ecfd98b 100644 --- a/source/opt/scalar_replacement_pass.h +++ b/source/opt/scalar_replacement_pass.h @@ -262,9 +262,26 @@ class ScalarReplacementPass : public MemPass { // that we will be willing to split. bool IsLargerThanSizeLimit(uint64_t length) const; + // Copies all relevant decorations from `from` to `to`. This includes + // decorations applied to the variable, and to the members of the type. + // It is assumed that `to` is a variable that is intended to replace the + // `member_index`th member of `from`. + void CopyDecorationsToVariable(Instruction* from, Instruction* to, + uint32_t member_index); + + // Copies pointer related decoration from `from` to `to` if they exist. + void CopyPointerDecorationsToVariable(Instruction* from, Instruction* to); + + // Copies decorations that are needed from the `member_index` of `from` to + // `to, if there was one. + void CopyNecessaryMemberDecorationsToVariable(Instruction* from, + Instruction* to, + uint32_t member_index); + // Limit on the number of members in an object that will be replaced. // 0 means there is no limit. uint32_t max_num_elements_; + // This has to be big enough to fit "scalar-replacement=" followed by a // uint32_t number written in decimal (so 10 digits), and then a // terminating nul. diff --git a/source/opt/type_manager.cpp b/source/opt/type_manager.cpp index 6e4c054ef4..1b1aeadc8a 100644 --- a/source/opt/type_manager.cpp +++ b/source/opt/type_manager.cpp @@ -178,7 +178,7 @@ void TypeManager::RemoveId(uint32_t id) { if (iter == id_to_type_.end()) return; auto& type = iter->second; - if (!type->IsUniqueType(true)) { + if (!type->IsUniqueType()) { auto tIter = type_to_id_.find(type); if (tIter != type_to_id_.end() && tIter->second == id) { // |type| currently maps to |id|. @@ -437,7 +437,7 @@ uint32_t TypeManager::FindPointerToType(uint32_t type_id, spv::StorageClass storage_class) { Type* pointeeTy = GetType(type_id); Pointer pointerTy(pointeeTy, storage_class); - if (pointeeTy->IsUniqueType(true)) { + if (pointeeTy->IsUniqueType()) { // Non-ambiguous type. Get the pointer type through the type manager. return GetTypeInstruction(&pointerTy); } diff --git a/source/opt/types.cpp b/source/opt/types.cpp index 2f1836281b..49eec9b743 100644 --- a/source/opt/types.cpp +++ b/source/opt/types.cpp @@ -84,10 +84,9 @@ bool Type::HasSameDecorations(const Type* that) const { return CompareTwoVectors(decorations_, that->decorations_); } -bool Type::IsUniqueType(bool allowVariablePointers) const { +bool Type::IsUniqueType() const { switch (kind_) { case kPointer: - return !allowVariablePointers; case kStruct: case kArray: case kRuntimeArray: diff --git a/source/opt/types.h b/source/opt/types.h index 1f329373b1..26c058c6f8 100644 --- a/source/opt/types.h +++ b/source/opt/types.h @@ -148,12 +148,16 @@ class Type { // Returns a clone of |this| minus any decorations. std::unique_ptr RemoveDecorations() const; - // Returns true if this type must be unique. + // Returns true if this cannot hash to the same value as another type in the + // module. For example, structs are not unique types because the module could + // have two types // - // If variable pointers are allowed, then pointers are not required to be - // unique. - // TODO(alanbaker): Update this if variable pointers become a core feature. - bool IsUniqueType(bool allowVariablePointers = false) const; + // %1 = OpTypeStruct %int + // %2 = OpTypeStruct %int + // + // The only way to distinguish these types is the result id. The type manager + // will hash them to the same value. + bool IsUniqueType() const; bool operator==(const Type& other) const; diff --git a/test/opt/scalar_replacement_test.cpp b/test/opt/scalar_replacement_test.cpp index b63a6b6c11..0ba285bb62 100644 --- a/test/opt/scalar_replacement_test.cpp +++ b/test/opt/scalar_replacement_test.cpp @@ -2308,6 +2308,54 @@ TEST_F(ScalarReplacementTest, UndefImageMember) { SinglePassRunAndMatch(text, true); } +TEST_F(ScalarReplacementTest, RestrictPointer) { + // This test makes sure that a variable with the restrict pointer decoration + // is replaced, and that the pointer is applied to the new variable. + const std::string text = R"( +; CHECK: OpDecorate [[new_var:%\w+]] RestrictPointer +; CHECK: [[struct_type:%\w+]] = OpTypeStruct %int +; CHECK: [[ptr_type:%\w+]] = OpTypePointer PhysicalStorageBuffer [[struct_type]] +; CHECK: [[dup_struct_type:%\w+]] = OpTypeStruct %int +; CHECK: {{%\w+}} = OpTypePointer PhysicalStorageBuffer [[dup_struct_type]] +; CHECK: [[var_type:%\w+]] = OpTypePointer Function [[ptr_type]] +; CHECK: [[new_var]] = OpVariable [[var_type]] Function + OpCapability Shader + OpCapability PhysicalStorageBufferAddresses + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel PhysicalStorageBuffer64 GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpMemberDecorate %3 0 Offset 0 + OpDecorate %3 Block + OpMemberDecorate %4 0 Offset 0 + OpDecorate %4 Block + OpDecorate %5 RestrictPointer + %6 = OpTypeVoid + %7 = OpTypeFunction %6 + %8 = OpTypeInt 32 1 + %9 = OpConstant %8 0 + %3 = OpTypeStruct %8 + %10 = OpTypePointer PhysicalStorageBuffer %3 + %11 = OpTypeStruct %10 + %4 = OpTypeStruct %8 + %12 = OpTypePointer PhysicalStorageBuffer %4 + %13 = OpTypePointer Function %11 + %14 = OpTypePointer Function %10 + %15 = OpTypePointer Function %12 + %16 = OpUndef %11 + %2 = OpFunction %6 None %7 + %17 = OpLabel + %5 = OpVariable %13 Function + OpStore %5 %16 + %18 = OpAccessChain %14 %5 %9 + OpReturn + OpFunctionEnd + )"; + + SetTargetEnv(SPV_ENV_UNIVERSAL_1_6); + SinglePassRunAndMatch(text, true); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/test/opt/types_test.cpp b/test/opt/types_test.cpp index 4352b7cf58..4ceeb1400c 100644 --- a/test/opt/types_test.cpp +++ b/test/opt/types_test.cpp @@ -391,18 +391,13 @@ TEST(Types, IsUniqueType) { case Type::kArray: case Type::kRuntimeArray: case Type::kStruct: + case Type::kPointer: expectation = false; break; default: break; } - EXPECT_EQ(t->IsUniqueType(false), expectation) - << "expected '" << t->str() << "' to be a " - << (expectation ? "" : "non-") << "unique type"; - - // Allowing variables pointers. - if (t->AsPointer()) expectation = false; - EXPECT_EQ(t->IsUniqueType(true), expectation) + EXPECT_EQ(t->IsUniqueType(), expectation) << "expected '" << t->str() << "' to be a " << (expectation ? "" : "non-") << "unique type"; } From d6310f4168aaf57b01fc4799e3df1cb0730919e0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 8 May 2023 10:22:36 -0400 Subject: [PATCH 142/523] Roll external/googletest/ a3580180d..bc860af08 (1 commit) (#5216) https://github.com/google/googletest/compare/a3580180d169...bc860af08783 $ git log a3580180d..bc860af08 --date=short --no-merges --format='%ad %ae %s' 2023-05-05 absl-team This trips up when compiling with -Wvla otherwise. 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 656ad18d9d..9b6039e894 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': 'a3580180d16923d6d5f488e20b3814608a892f17', + 'googletest_revision': 'bc860af08783b8113005ca7697da5f5d49a8056f', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From e803fe67177cebbce014b69707243361a5d8aefe Mon Sep 17 00:00:00 2001 From: Chris Oattes Date: Mon, 8 May 2023 17:14:42 +0100 Subject: [PATCH 143/523] Don't convert struct members to half (#5201) --- source/opt/convert_to_half_pass.cpp | 8 +++++ source/opt/convert_to_half_pass.h | 1 + test/opt/convert_relaxed_to_half_test.cpp | 43 +++++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/source/opt/convert_to_half_pass.cpp b/source/opt/convert_to_half_pass.cpp index 7a4c1f4097..2c4a631e17 100644 --- a/source/opt/convert_to_half_pass.cpp +++ b/source/opt/convert_to_half_pass.cpp @@ -39,6 +39,13 @@ bool ConvertToHalfPass::IsFloat(Instruction* inst, uint32_t width) { return Pass::IsFloat(ty_id, width); } +bool ConvertToHalfPass::IsStruct(Instruction* inst) { + uint32_t ty_id = inst->type_id(); + if (ty_id == 0) return false; + Instruction* ty_inst = Pass::GetBaseType(ty_id); + return (ty_inst->opcode() == spv::Op::OpTypeStruct); +} + bool ConvertToHalfPass::IsDecoratedRelaxed(Instruction* inst) { uint32_t r_id = inst->result_id(); for (auto r_inst : get_decoration_mgr()->GetDecorationsFor(r_id, false)) @@ -294,6 +301,7 @@ bool ConvertToHalfPass::CloseRelaxInst(Instruction* inst) { bool relax = true; inst->ForEachInId([&relax, this](uint32_t* idp) { Instruction* op_inst = get_def_use_mgr()->GetDef(*idp); + if (IsStruct(op_inst)) relax = false; if (!IsFloat(op_inst, 32)) return; if (!IsRelaxed(*idp)) relax = false; }); diff --git a/source/opt/convert_to_half_pass.h b/source/opt/convert_to_half_pass.h index feabfba3e1..24a478ffc6 100644 --- a/source/opt/convert_to_half_pass.h +++ b/source/opt/convert_to_half_pass.h @@ -45,6 +45,7 @@ class ConvertToHalfPass : public Pass { // Return true if |inst| returns scalar, vector or matrix type with base // float and |width| bool IsFloat(Instruction* inst, uint32_t width); + bool IsStruct(Instruction* inst); // Return true if |inst| is decorated with RelaxedPrecision bool IsDecoratedRelaxed(Instruction* inst); diff --git a/test/opt/convert_relaxed_to_half_test.cpp b/test/opt/convert_relaxed_to_half_test.cpp index 6a06de84f7..27330e109a 100644 --- a/test/opt/convert_relaxed_to_half_test.cpp +++ b/test/opt/convert_relaxed_to_half_test.cpp @@ -1570,6 +1570,49 @@ TEST_F(ConvertToHalfTest, HandleNonRelaxedPhi) { EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result)); } +TEST_F(ConvertToHalfTest, DoNotReplaceStructMember) { + // See https://github.com/KhronosGroup/SPIRV-Tools/issues/4814 + + // This test is a case with a non-relaxed phi with a relaxed operand. + // A convert must be inserted at the end of the block associated with + // the operand. + const std::string test = + R"(OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %PSMain "PSMain" %out_var_SV_TARGET %MyConstants +OpExecutionMode %PSMain OriginUpperLeft +OpSource HLSL 600 +OpName %type_ConstantBuffer_myStruct "type.ConstantBuffer.myStruct" +OpMemberName %type_ConstantBuffer_myStruct 0 "f" +OpName %MyConstants "MyConstants" +OpName %out_var_SV_TARGET "out.var.SV_TARGET" +OpName %PSMain "PSMain" +OpDecorate %out_var_SV_TARGET Location 0 +OpDecorate %MyConstants DescriptorSet 1 +OpDecorate %MyConstants Binding 2 +OpMemberDecorate %type_ConstantBuffer_myStruct 0 Offset 0 +OpDecorate %type_ConstantBuffer_myStruct Block +%float = OpTypeFloat 32 +%type_ConstantBuffer_myStruct = OpTypeStruct %float +%_ptr_Uniform_type_ConstantBuffer_myStruct = OpTypePointer Uniform %type_ConstantBuffer_myStruct +%_ptr_Output_float = OpTypePointer Output %float +%void = OpTypeVoid +%9 = OpTypeFunction %void +%MyConstants = OpVariable %_ptr_Uniform_type_ConstantBuffer_myStruct Uniform +%out_var_SV_TARGET = OpVariable %_ptr_Output_float Output +%PSMain = OpFunction %void None %9 +%10 = OpLabel +%11 = OpLoad %type_ConstantBuffer_myStruct %MyConstants +%12 = OpCompositeExtract %float %11 0 +OpStore %out_var_SV_TARGET %12 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(test, test, true); +} + } // namespace } // namespace opt } // namespace spvtools From 51892874ba08f3ac0d9b1fcf3893c8516693a88e Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 10 May 2023 04:03:40 -0400 Subject: [PATCH 144/523] Run ADCE when the printf extension is used. (#5215) This is for https://github.com/microsoft/DirectXShaderCompiler/issues/5136. --- source/opt/aggressive_dead_code_elim_pass.cpp | 3 ++- test/opt/aggressive_dead_code_elim_test.cpp | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp index 51a65245fb..16456386b2 100644 --- a/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/source/opt/aggressive_dead_code_elim_pass.cpp @@ -156,7 +156,8 @@ bool AggressiveDCEPass::AllExtensionsSupported() const { "Expecting an import of an extension's instruction set."); const std::string extension_name = inst.GetInOperand(0).AsString(); if (spvtools::utils::starts_with(extension_name, "NonSemantic.") && - extension_name != "NonSemantic.Shader.DebugInfo.100") { + (extension_name != "NonSemantic.Shader.DebugInfo.100") && + (extension_name != "NonSemantic.DebugPrintf")) { return false; } } diff --git a/test/opt/aggressive_dead_code_elim_test.cpp b/test/opt/aggressive_dead_code_elim_test.cpp index 0d941519cd..83aab3c46a 100644 --- a/test/opt/aggressive_dead_code_elim_test.cpp +++ b/test/opt/aggressive_dead_code_elim_test.cpp @@ -7857,6 +7857,33 @@ TEST_F(AggressiveDCETest, RemoveOutputFalse) { SinglePassRunAndMatch(text, true, false, false); } +TEST_F(AggressiveDCETest, RemoveWhenUsingPrintfExtension) { + // Remove dead n_out output variable from module + const std::string text = R"( +; CHECK: OpExtInstImport "NonSemantic.DebugPrintf" +; CHECK-NOT: OpVariable + OpCapability Shader + %1 = OpExtInstImport "NonSemantic.DebugPrintf" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 8 8 1 + OpSource HLSL 660 + OpName %main "main" + %uint = OpTypeInt 32 0 + %void = OpTypeVoid + %5 = OpTypeFunction %void +%_ptr_Function_uint = OpTypePointer Function %uint + %main = OpFunction %void None %5 + %7 = OpLabel + %8 = OpVariable %_ptr_Function_uint Function + OpReturn + OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_VULKAN_1_3); + SinglePassRunAndMatch(text, true); +} + } // namespace } // namespace opt } // namespace spvtools From 7c39951f6ee11ab929a54fddb8ef79ffd4525c18 Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Mon, 15 May 2023 22:53:37 +0900 Subject: [PATCH 145/523] spirv-val: Label Interface Location/Component VUIDs (#5221) --- source/val/validate_interfaces.cpp | 3 +++ source/val/validation_state.cpp | 4 ++++ test/val/val_interfaces_test.cpp | 32 ++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/source/val/validate_interfaces.cpp b/source/val/validate_interfaces.cpp index 35666984d0..48f9e7d875 100644 --- a/source/val/validate_interfaces.cpp +++ b/source/val/validate_interfaces.cpp @@ -388,6 +388,7 @@ spv_result_t GetLocationsForVariable( for (uint32_t i = start; i < end; ++i) { if (!locs->insert(i).second) { return _.diag(SPV_ERROR_INVALID_DATA, entry_point) + << (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721)) << "Entry-point has conflicting " << storage_class << " location assignment at location " << i / 4 << ", component " << i % 4; @@ -459,6 +460,7 @@ spv_result_t GetLocationsForVariable( uint32_t check = 4 * l + c; if (!locations->insert(check).second) { return _.diag(SPV_ERROR_INVALID_DATA, entry_point) + << (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721)) << "Entry-point has conflicting " << storage_class << " location assignment at location " << l << ", component " << c; @@ -476,6 +478,7 @@ spv_result_t GetLocationsForVariable( for (uint32_t l = start; l < end; ++l) { if (!locations->insert(l).second) { return _.diag(SPV_ERROR_INVALID_DATA, entry_point) + << (is_output ? _.VkErrorID(8722) : _.VkErrorID(8721)) << "Entry-point has conflicting " << storage_class << " location assignment at location " << l / 4 << ", component " << l % 4; diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index dbf0ba6d9b..6072589ccd 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -2180,6 +2180,10 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-Component-07703); case 7951: return VUID_WRAP(VUID-StandaloneSpirv-SubgroupVoteKHR-07951); + case 8721: + return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-08721); + case 8722: + return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-08722); default: return ""; // unknown id } diff --git a/test/val/val_interfaces_test.cpp b/test/val/val_interfaces_test.cpp index 1756528729..39c6739c3e 100644 --- a/test/val/val_interfaces_test.cpp +++ b/test/val/val_interfaces_test.cpp @@ -583,6 +583,8 @@ OpFunctionEnd CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721")); EXPECT_THAT(getDiagnosticString(), HasSubstr("Entry-point has conflicting input location assignment " "at location 0")); @@ -611,6 +613,8 @@ OpFunctionEnd CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08722")); EXPECT_THAT( getDiagnosticString(), HasSubstr("Entry-point has conflicting output location assignment " @@ -698,6 +702,8 @@ OpFunctionEnd CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721")); EXPECT_THAT(getDiagnosticString(), HasSubstr("Entry-point has conflicting input location assignment " "at location 1")); @@ -731,6 +737,8 @@ OpFunctionEnd CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721")); EXPECT_THAT(getDiagnosticString(), HasSubstr("Entry-point has conflicting input location assignment " "at location 1")); @@ -761,6 +769,8 @@ OpFunctionEnd CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721")); EXPECT_THAT(getDiagnosticString(), HasSubstr("Entry-point has conflicting input location assignment " "at location 1")); @@ -791,6 +801,8 @@ OpFunctionEnd CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721")); EXPECT_THAT(getDiagnosticString(), HasSubstr("Entry-point has conflicting input location assignment " "at location 2")); @@ -821,6 +833,8 @@ OpFunctionEnd CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721")); EXPECT_THAT(getDiagnosticString(), HasSubstr("Entry-point has conflicting input location assignment " "at location 3")); @@ -853,6 +867,8 @@ OpFunctionEnd CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721")); EXPECT_THAT(getDiagnosticString(), HasSubstr("Entry-point has conflicting input location assignment " "at location 1")); @@ -885,6 +901,8 @@ OpFunctionEnd CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721")); EXPECT_THAT(getDiagnosticString(), HasSubstr("Entry-point has conflicting input location assignment " "at location 5")); @@ -917,6 +935,8 @@ OpFunctionEnd CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721")); EXPECT_THAT(getDiagnosticString(), HasSubstr("Entry-point has conflicting input location assignment " "at location 7")); @@ -949,6 +969,8 @@ OpFunctionEnd CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721")); EXPECT_THAT(getDiagnosticString(), HasSubstr("Entry-point has conflicting input location assignment " "at location 1")); @@ -981,6 +1003,8 @@ OpFunctionEnd CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721")); EXPECT_THAT(getDiagnosticString(), HasSubstr("Entry-point has conflicting input location assignment " "at location 3")); @@ -1015,6 +1039,8 @@ OpFunctionEnd CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721")); EXPECT_THAT(getDiagnosticString(), HasSubstr("Entry-point has conflicting input location assignment " "at location 15")); @@ -1074,6 +1100,8 @@ OpFunctionEnd CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08721")); EXPECT_THAT(getDiagnosticString(), HasSubstr("Entry-point has conflicting input location assignment " "at location 1, component 1")); @@ -1189,6 +1217,8 @@ OpFunctionEnd CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08722")); EXPECT_THAT( getDiagnosticString(), HasSubstr("Entry-point has conflicting output location assignment " @@ -1358,6 +1388,8 @@ OpFunctionEnd CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08722")); EXPECT_THAT(getDiagnosticString(), HasSubstr("Entry-point has conflicting output location " "assignment at location 1, component 1")); From 17a26b45ffdad78c3468f8ffdded3bcf24afa2bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Petit?= Date: Mon, 15 May 2023 14:56:48 +0100 Subject: [PATCH 146/523] Improve an error message in the assembler (#5219) Signed-off-by: Kevin Petit --- source/text.cpp | 3 ++- test/text_to_binary.pipe_storage_test.cpp | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/source/text.cpp b/source/text.cpp index 8f77d624ab..9c77422f33 100644 --- a/source/text.cpp +++ b/source/text.cpp @@ -544,7 +544,8 @@ spv_result_t spvTextEncodeOpcode(const spvtools::AssemblyGrammar& grammar, std::string equal_sign; error = context->getWord(&equal_sign, &nextPosition); if ("=" != equal_sign) - return context->diagnostic() << "'=' expected after result id."; + return context->diagnostic() << "'=' expected after result id but found '" + << equal_sign << "'."; // The after the '=' sign. context->setPosition(nextPosition); diff --git a/test/text_to_binary.pipe_storage_test.cpp b/test/text_to_binary.pipe_storage_test.cpp index 2a41d427d9..ef899a2756 100644 --- a/test/text_to_binary.pipe_storage_test.cpp +++ b/test/text_to_binary.pipe_storage_test.cpp @@ -41,7 +41,7 @@ TEST_F(OpTypePipeStorageTest, ArgumentCount) { Eq(MakeInstruction(spv::Op::OpTypePipeStorage, {1}))); EXPECT_THAT(CompileFailure("%res = OpTypePipeStorage %1 %2 %3 %4 %5", SPV_ENV_UNIVERSAL_1_1), - Eq("'=' expected after result id.")); + Eq("'=' expected after result id but found '%2'.")); } using OpConstantPipeStorageTest = spvtest::TextToBinaryTest; @@ -72,7 +72,7 @@ TEST_F(OpConstantPipeStorageTest, ArgumentCount) { Eq(MakeInstruction(spv::Op::OpConstantPipeStorage, {1, 2, 3, 4, 5}))); EXPECT_THAT(CompileFailure("%1 = OpConstantPipeStorage %2 3 4 5 %6 %7", SPV_ENV_UNIVERSAL_1_1), - Eq("'=' expected after result id.")); + Eq("'=' expected after result id but found '%7'.")); } TEST_F(OpConstantPipeStorageTest, ArgumentTypes) { @@ -118,7 +118,7 @@ TEST_F(OpCreatePipeFromPipeStorageTest, ArgumentCount) { Eq(MakeInstruction(spv::Op::OpCreatePipeFromPipeStorage, {1, 2, 3}))); EXPECT_THAT(CompileFailure("%1 = OpCreatePipeFromPipeStorage %2 %3 %4 %5", SPV_ENV_UNIVERSAL_1_1), - Eq("'=' expected after result id.")); + Eq("'=' expected after result id but found '%5'.")); } TEST_F(OpCreatePipeFromPipeStorageTest, ArgumentTypes) { From e7c6084fd1d6d6f5ac393e842728d8be309688ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 16 May 2023 17:06:35 +0200 Subject: [PATCH 147/523] Prepare release 2023.3 (#5222) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Roll external/googletest/ bc860af08..bb2941fcc (1 commit) https://github.com/google/googletest/compare/bc860af08783...bb2941fcc611 $ git log bc860af08..bb2941fcc --date=short --no-merges --format='%ad %ae %s' 2023-05-11 absl-team Give CreateArgvFromArgs internal linkage Created with: roll-dep external/googletest * Prepare release v2023.3 Signed-off-by: Nathan Gauër --------- Signed-off-by: Nathan Gauër --- CHANGES | 23 +++++++++++++++++++++++ DEPS | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index dbe31a0c03..c11067a242 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,28 @@ Revision history for SPIRV-Tools +v2023.3 2023-15-15 + - General + - Update spirv_headers to include SPV_KHR_ray_tracing_position_fetch (#5205) + - spirv-tools: Add support for QNX (#5211) + - build: set std=c++17 for BUILD.gn (#5162) + - Optimizer + - Run ADCE when the printf extension is used. (#5215) + - Don't convert struct members to half (#5201) + - Apply scalar replacement on vars with Pointer decorations (#5208) + - opt: Fix null deref in OpMatrixTimesVector and OpVectorTimesMatrix (#5199) + - instrument: Add set and binding to bindless error records (#5204) + - instrument: Change descriptor state storage format (#5178) + - Fix LICMPass (#5087) + - Add Vulkan memory model to allow lists (#5173) + - Do not remove control barrier after spv1.3 (#5174) + - Validator + - spirv-val: Label Interface Location/Component VUIDs (#5221) + - Add support for SPV_EXT_shader_tile_image (#5188) + - Fix vector OpConstantComposite type validation (#5191) + - spirv-val: Label new Vulkan VUID 07951 (#5154) + - Fuzz + - Do not define GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE if it is already defined. (#5200) + v2023.2 2023-03-10 - General - build: move from c++11 to c++17 (#4983) diff --git a/DEPS b/DEPS index 9b6039e894..353887e759 100644 --- a/DEPS +++ b/DEPS @@ -5,7 +5,7 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': 'bc860af08783b8113005ca7697da5f5d49a8056f', + 'googletest_revision': 'bb2941fcc611b9e4eaf16f156e8c723348bf0931', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From e357a36ccfac9a1fa71e00b04237d117b53093b6 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 24 May 2023 10:19:36 -0400 Subject: [PATCH 148/523] Disable RE2 autoroll (#5234) RE2 now depends on Abseil. We need to figure out how to add that dependency. Disable the autoroll for now. https://github.com/KhronosGroup/SPIRV-Tools/issues/5233 --- utils/roll_deps.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/utils/roll_deps.sh b/utils/roll_deps.sh index 6289c94e40..b931b5aa12 100755 --- a/utils/roll_deps.sh +++ b/utils/roll_deps.sh @@ -29,10 +29,12 @@ function ExitIfIsInterestingError() { } -# We are not rolling google test for now. The latest version requires C++14. +# We are not rolling re2 for now. The latest version requires Abseil, and we +# need time to determine the best way to do that. See +# https://github.com/KhronosGroup/SPIRV-Tools/issues/5233. dependencies=("external/effcee/" "external/googletest/" - "external/re2/" +# "external/re2/" "external/spirv-headers/") From 44c9da6fee936ac20f6c99f5ef33b8f3a1b5329c Mon Sep 17 00:00:00 2001 From: Steve Urquhart <53908460+SteveUrquhart@users.noreply.github.com> Date: Wed, 24 May 2023 10:30:10 -0400 Subject: [PATCH 149/523] Remove const zero image operands (#5232) --- source/opt/folding_rules.cpp | 8 ++++++-- test/opt/fold_test.cpp | 8 +++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/source/opt/folding_rules.cpp b/source/opt/folding_rules.cpp index 7730ac1d27..293236d9f2 100644 --- a/source/opt/folding_rules.cpp +++ b/source/opt/folding_rules.cpp @@ -2884,8 +2884,12 @@ FoldingRule UpdateImageOperands() { "Offset and ConstOffset may not be used together"); if (offset_operand_index < inst->NumOperands()) { if (constants[offset_operand_index]) { - image_operands = - image_operands | uint32_t(spv::ImageOperandsMask::ConstOffset); + if (constants[offset_operand_index]->IsZero()) { + inst->RemoveInOperand(offset_operand_index); + } else { + image_operands = image_operands | + uint32_t(spv::ImageOperandsMask::ConstOffset); + } image_operands = image_operands & ~uint32_t(spv::ImageOperandsMask::Offset); inst->SetInOperand(operand_index, {image_operands}); diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index eff8edf0a7..77442b6586 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -8448,6 +8448,7 @@ std::string ImageOperandsTestBody(const std::string& image_instruction) { %v3int = OpTypeVector %int 3 %Texture = OpVariable %_ptr_UniformConstant_type_2d_image UniformConstant %gSampler = OpVariable %_ptr_UniformConstant_type_sampler UniformConstant + %110 = OpConstantComposite %v2int %5 %5 %101 = OpConstantComposite %v2int %int_n1 %int_n1 %20 = OpConstantComposite %v2float %float_0 %float_0 %main = OpFunction %void None %22 @@ -8507,7 +8508,12 @@ ::testing::Values( InstructionFoldingCase(ImageOperandsTestBody( " OpImageWrite %88 %5 %101 Offset %101 \n" "; CHECK: OpImageWrite %88 %5 %101 ConstOffset %101 \n") - , 0 /* No result-id */, true) + , 0 /* No result-id */, true), + // Test case 8: OpImageFetch with zero constant Offset + InstructionFoldingCase(ImageOperandsTestBody( + " %89 = OpImageFetch %10 %88 %101 Lod|Offset %5 %110 \n" + "; CHECK: %89 = OpImageFetch %10 %88 %101 Lod %5 \n") + , 89, true) )); } // namespace From dcfea36ab7c0cc399f7f7f52b8c4f742dea138df Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 24 May 2023 10:56:37 -0400 Subject: [PATCH 150/523] Have the macos bazel build us git-sync-deps (#5235) --- kokoro/macos-clang-release-bazel/build.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/kokoro/macos-clang-release-bazel/build.sh b/kokoro/macos-clang-release-bazel/build.sh index 2465d9c602..74f9e2365f 100644 --- a/kokoro/macos-clang-release-bazel/build.sh +++ b/kokoro/macos-clang-release-bazel/build.sh @@ -30,11 +30,7 @@ SRC=$PWD/github/SPIRV-Tools git config --global --add safe.directory $SRC cd $SRC -git clone --depth=1 https://github.com/KhronosGroup/SPIRV-Headers external/spirv-headers -git clone https://github.com/google/googletest external/googletest -cd external && cd googletest && git reset --hard 1fb1bb23bb8418dc73a5a9a82bbed31dc610fec7 && cd .. && cd .. -git clone --depth=1 https://github.com/google/effcee external/effcee -git clone --depth=1 https://github.com/google/re2 external/re2 +/usr/bin/python3 utils/git-sync-deps --treeless # Get bazel 5.0.0 gsutil cp gs://bazel/5.0.0/release/bazel-5.0.0-darwin-x86_64 . From 60c546f3ff8e54eae3005a6ab81d6406e35c5d55 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 24 May 2023 11:00:43 -0400 Subject: [PATCH 151/523] Roll external/googletest/ bc860af08..bb2941fcc (1 commit) (#5220) * Roll external/googletest/ bb2941fcc..458046912 (8 commits) https://github.com/google/googletest/compare/bb2941fcc611...458046912236 $ git log bb2941fcc..458046912 --date=short --no-merges --format='%ad %ae %s' 2023-05-21 shlomi Add CXX_STANDARD_REQUIRED to CMake quickstart 2023-05-17 dinor Fix typo in version number example in README 2023-05-16 dinor Explicitly document googletest release tag format 2023-05-11 131433627+yagneshprajapati Update README.md 2023-05-11 131433627+yagneshprajapati Update README.md 2023-05-11 131433627+yagneshprajapati Update README.md 2023-05-08 pateldeev Add missing absl dependency from build. 2023-05-07 131433627+yagneshprajapati Update README.md Created with: roll-dep external/googletest * Roll external/spirv-headers/ 268a06176..bdbfd019b (1 commit) https://github.com/KhronosGroup/SPIRV-Headers/compare/268a061764ee...bdbfd019be69 $ git log 268a06176..bdbfd019b --date=short --no-merges --format='%ad %ae %s' 2023-05-05 kevin.petit Make the generated operators for masks constexpr 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 353887e759..3f6a6ea4ee 100644 --- a/DEPS +++ b/DEPS @@ -5,13 +5,13 @@ vars = { 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', - 'googletest_revision': 'bb2941fcc611b9e4eaf16f156e8c723348bf0931', + 'googletest_revision': '45804691223635953f311cf31a10c632553bbfc3', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', 're2_revision': 'c9cba76063cf4235c1a15dd14a24a4ef8d623761', - 'spirv_headers_revision': '268a061764ee69f09a477a695bf6a11ffe311b8d', + 'spirv_headers_revision': 'bdbfd019be6952fd8fa9bd5606a8798a7530c853', } deps = { From 82b1a87b21fca29f14af97e111afa8d4c644b499 Mon Sep 17 00:00:00 2001 From: Pankaj Mistry <63069047+pmistryNV@users.noreply.github.com> Date: Wed, 24 May 2023 08:01:11 -0700 Subject: [PATCH 152/523] Add SPV_NV_bindless_texture to spirv optimizations (#5231) --- source/opt/aggressive_dead_code_elim_pass.cpp | 1 + .../opt/local_access_chain_convert_pass.cpp | 3 +- source/opt/local_single_block_elim_pass.cpp | 109 +++++++++--------- source/opt/local_single_store_elim_pass.cpp | 103 +++++++++-------- 4 files changed, 112 insertions(+), 104 deletions(-) diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp index 16456386b2..3f982f8856 100644 --- a/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/source/opt/aggressive_dead_code_elim_pass.cpp @@ -994,6 +994,7 @@ void AggressiveDCEPass::InitExtensions() { "SPV_KHR_non_semantic_info", "SPV_KHR_uniform_group_instructions", "SPV_KHR_fragment_shader_barycentric", + "SPV_NV_bindless_texture", }); } diff --git a/source/opt/local_access_chain_convert_pass.cpp b/source/opt/local_access_chain_convert_pass.cpp index 6ec0c2d387..81837ed15d 100644 --- a/source/opt/local_access_chain_convert_pass.cpp +++ b/source/opt/local_access_chain_convert_pass.cpp @@ -426,7 +426,8 @@ void LocalAccessChainConvertPass::InitExtensions() { "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_integer_dot_product", "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_KHR_fragment_shader_barycentric", "SPV_KHR_vulkan_memory_model", + "SPV_NV_bindless_texture"}); } bool LocalAccessChainConvertPass::AnyIndexIsOutOfBounds( diff --git a/source/opt/local_single_block_elim_pass.cpp b/source/opt/local_single_block_elim_pass.cpp index 063d1b95c1..77c9e2b1cd 100644 --- a/source/opt/local_single_block_elim_pass.cpp +++ b/source/opt/local_single_block_elim_pass.cpp @@ -233,59 +233,62 @@ Pass::Status LocalSingleBlockLoadStoreElimPass::Process() { void LocalSingleBlockLoadStoreElimPass::InitExtensions() { extensions_allowlist_.clear(); - extensions_allowlist_.insert({"SPV_AMD_shader_explicit_vertex_parameter", - "SPV_AMD_shader_trinary_minmax", - "SPV_AMD_gcn_shader", - "SPV_KHR_shader_ballot", - "SPV_AMD_shader_ballot", - "SPV_AMD_gpu_shader_half_float", - "SPV_KHR_shader_draw_parameters", - "SPV_KHR_subgroup_vote", - "SPV_KHR_8bit_storage", - "SPV_KHR_16bit_storage", - "SPV_KHR_device_group", - "SPV_KHR_multiview", - "SPV_NVX_multiview_per_view_attributes", - "SPV_NV_viewport_array2", - "SPV_NV_stereo_view_rendering", - "SPV_NV_sample_mask_override_coverage", - "SPV_NV_geometry_shader_passthrough", - "SPV_AMD_texture_gather_bias_lod", - "SPV_KHR_storage_buffer_storage_class", - "SPV_KHR_variable_pointers", - "SPV_AMD_gpu_shader_int16", - "SPV_KHR_post_depth_coverage", - "SPV_KHR_shader_atomic_counter_ops", - "SPV_EXT_shader_stencil_export", - "SPV_EXT_shader_viewport_index_layer", - "SPV_AMD_shader_image_load_store_lod", - "SPV_AMD_shader_fragment_mask", - "SPV_EXT_fragment_fully_covered", - "SPV_AMD_gpu_shader_half_float_fetch", - "SPV_GOOGLE_decorate_string", - "SPV_GOOGLE_hlsl_functionality1", - "SPV_GOOGLE_user_type", - "SPV_NV_shader_subgroup_partitioned", - "SPV_EXT_demote_to_helper_invocation", - "SPV_EXT_descriptor_indexing", - "SPV_NV_fragment_shader_barycentric", - "SPV_NV_compute_shader_derivatives", - "SPV_NV_shader_image_footprint", - "SPV_NV_shading_rate", - "SPV_NV_mesh_shader", - "SPV_NV_ray_tracing", - "SPV_KHR_ray_tracing", - "SPV_KHR_ray_query", - "SPV_EXT_fragment_invocation_density", - "SPV_EXT_physical_storage_buffer", - "SPV_KHR_terminate_invocation", - "SPV_KHR_subgroup_uniform_control_flow", - "SPV_KHR_integer_dot_product", - "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"}); + extensions_allowlist_.insert({ + "SPV_AMD_shader_explicit_vertex_parameter", + "SPV_AMD_shader_trinary_minmax", + "SPV_AMD_gcn_shader", + "SPV_KHR_shader_ballot", + "SPV_AMD_shader_ballot", + "SPV_AMD_gpu_shader_half_float", + "SPV_KHR_shader_draw_parameters", + "SPV_KHR_subgroup_vote", + "SPV_KHR_8bit_storage", + "SPV_KHR_16bit_storage", + "SPV_KHR_device_group", + "SPV_KHR_multiview", + "SPV_NVX_multiview_per_view_attributes", + "SPV_NV_viewport_array2", + "SPV_NV_stereo_view_rendering", + "SPV_NV_sample_mask_override_coverage", + "SPV_NV_geometry_shader_passthrough", + "SPV_AMD_texture_gather_bias_lod", + "SPV_KHR_storage_buffer_storage_class", + "SPV_KHR_variable_pointers", + "SPV_AMD_gpu_shader_int16", + "SPV_KHR_post_depth_coverage", + "SPV_KHR_shader_atomic_counter_ops", + "SPV_EXT_shader_stencil_export", + "SPV_EXT_shader_viewport_index_layer", + "SPV_AMD_shader_image_load_store_lod", + "SPV_AMD_shader_fragment_mask", + "SPV_EXT_fragment_fully_covered", + "SPV_AMD_gpu_shader_half_float_fetch", + "SPV_GOOGLE_decorate_string", + "SPV_GOOGLE_hlsl_functionality1", + "SPV_GOOGLE_user_type", + "SPV_NV_shader_subgroup_partitioned", + "SPV_EXT_demote_to_helper_invocation", + "SPV_EXT_descriptor_indexing", + "SPV_NV_fragment_shader_barycentric", + "SPV_NV_compute_shader_derivatives", + "SPV_NV_shader_image_footprint", + "SPV_NV_shading_rate", + "SPV_NV_mesh_shader", + "SPV_NV_ray_tracing", + "SPV_KHR_ray_tracing", + "SPV_KHR_ray_query", + "SPV_EXT_fragment_invocation_density", + "SPV_EXT_physical_storage_buffer", + "SPV_KHR_terminate_invocation", + "SPV_KHR_subgroup_uniform_control_flow", + "SPV_KHR_integer_dot_product", + "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", + }); } } // namespace opt diff --git a/source/opt/local_single_store_elim_pass.cpp b/source/opt/local_single_store_elim_pass.cpp index a0de44c70f..e6a3f318b7 100644 --- a/source/opt/local_single_store_elim_pass.cpp +++ b/source/opt/local_single_store_elim_pass.cpp @@ -86,56 +86,59 @@ Pass::Status LocalSingleStoreElimPass::Process() { } void LocalSingleStoreElimPass::InitExtensionAllowList() { - extensions_allowlist_.insert({"SPV_AMD_shader_explicit_vertex_parameter", - "SPV_AMD_shader_trinary_minmax", - "SPV_AMD_gcn_shader", - "SPV_KHR_shader_ballot", - "SPV_AMD_shader_ballot", - "SPV_AMD_gpu_shader_half_float", - "SPV_KHR_shader_draw_parameters", - "SPV_KHR_subgroup_vote", - "SPV_KHR_8bit_storage", - "SPV_KHR_16bit_storage", - "SPV_KHR_device_group", - "SPV_KHR_multiview", - "SPV_NVX_multiview_per_view_attributes", - "SPV_NV_viewport_array2", - "SPV_NV_stereo_view_rendering", - "SPV_NV_sample_mask_override_coverage", - "SPV_NV_geometry_shader_passthrough", - "SPV_AMD_texture_gather_bias_lod", - "SPV_KHR_storage_buffer_storage_class", - "SPV_KHR_variable_pointers", - "SPV_AMD_gpu_shader_int16", - "SPV_KHR_post_depth_coverage", - "SPV_KHR_shader_atomic_counter_ops", - "SPV_EXT_shader_stencil_export", - "SPV_EXT_shader_viewport_index_layer", - "SPV_AMD_shader_image_load_store_lod", - "SPV_AMD_shader_fragment_mask", - "SPV_EXT_fragment_fully_covered", - "SPV_AMD_gpu_shader_half_float_fetch", - "SPV_GOOGLE_decorate_string", - "SPV_GOOGLE_hlsl_functionality1", - "SPV_NV_shader_subgroup_partitioned", - "SPV_EXT_descriptor_indexing", - "SPV_NV_fragment_shader_barycentric", - "SPV_NV_compute_shader_derivatives", - "SPV_NV_shader_image_footprint", - "SPV_NV_shading_rate", - "SPV_NV_mesh_shader", - "SPV_NV_ray_tracing", - "SPV_KHR_ray_query", - "SPV_EXT_fragment_invocation_density", - "SPV_EXT_physical_storage_buffer", - "SPV_KHR_terminate_invocation", - "SPV_KHR_subgroup_uniform_control_flow", - "SPV_KHR_integer_dot_product", - "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"}); + extensions_allowlist_.insert({ + "SPV_AMD_shader_explicit_vertex_parameter", + "SPV_AMD_shader_trinary_minmax", + "SPV_AMD_gcn_shader", + "SPV_KHR_shader_ballot", + "SPV_AMD_shader_ballot", + "SPV_AMD_gpu_shader_half_float", + "SPV_KHR_shader_draw_parameters", + "SPV_KHR_subgroup_vote", + "SPV_KHR_8bit_storage", + "SPV_KHR_16bit_storage", + "SPV_KHR_device_group", + "SPV_KHR_multiview", + "SPV_NVX_multiview_per_view_attributes", + "SPV_NV_viewport_array2", + "SPV_NV_stereo_view_rendering", + "SPV_NV_sample_mask_override_coverage", + "SPV_NV_geometry_shader_passthrough", + "SPV_AMD_texture_gather_bias_lod", + "SPV_KHR_storage_buffer_storage_class", + "SPV_KHR_variable_pointers", + "SPV_AMD_gpu_shader_int16", + "SPV_KHR_post_depth_coverage", + "SPV_KHR_shader_atomic_counter_ops", + "SPV_EXT_shader_stencil_export", + "SPV_EXT_shader_viewport_index_layer", + "SPV_AMD_shader_image_load_store_lod", + "SPV_AMD_shader_fragment_mask", + "SPV_EXT_fragment_fully_covered", + "SPV_AMD_gpu_shader_half_float_fetch", + "SPV_GOOGLE_decorate_string", + "SPV_GOOGLE_hlsl_functionality1", + "SPV_NV_shader_subgroup_partitioned", + "SPV_EXT_descriptor_indexing", + "SPV_NV_fragment_shader_barycentric", + "SPV_NV_compute_shader_derivatives", + "SPV_NV_shader_image_footprint", + "SPV_NV_shading_rate", + "SPV_NV_mesh_shader", + "SPV_NV_ray_tracing", + "SPV_KHR_ray_query", + "SPV_EXT_fragment_invocation_density", + "SPV_EXT_physical_storage_buffer", + "SPV_KHR_terminate_invocation", + "SPV_KHR_subgroup_uniform_control_flow", + "SPV_KHR_integer_dot_product", + "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", + }); } bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) { std::vector users; From f29e11dcb68a9a7db470a78e52cad169a2c61274 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Wed, 24 May 2023 12:28:45 -0700 Subject: [PATCH 153/523] diff: Don't give up entry point matching too early. (#5224) Addresses one case mentioned in #5218. --- source/diff/diff.cpp | 25 +++++++++---------- .../multiple_same_entry_points_autogen.cpp | 9 +++---- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/source/diff/diff.cpp b/source/diff/diff.cpp index 6daed321d1..c8bb27edca 100644 --- a/source/diff/diff.cpp +++ b/source/diff/diff.cpp @@ -101,6 +101,13 @@ class IdMap { return from < id_map_.size() && id_map_[from] != 0; } + bool IsMapped(const opt::Instruction* from_inst) const { + assert(from_inst != nullptr); + assert(!from_inst->HasResultId()); + + return inst_map_.find(from_inst) != inst_map_.end(); + } + // Map any ids in src and dst that have not been mapped to new ids in dst and // src respectively. void MapUnmatchedIds(IdMap& other_way); @@ -150,6 +157,9 @@ class SrcDstIdMap { bool IsSrcMapped(uint32_t src) { return src_to_dst_.IsMapped(src); } bool IsDstMapped(uint32_t dst) { return dst_to_src_.IsMapped(dst); } + bool IsDstMapped(const opt::Instruction* dst_inst) { + return dst_to_src_.IsMapped(dst_inst); + } // Map any ids in src and dst that have not been mapped to new ids in dst and // src respectively. @@ -1419,7 +1429,6 @@ void Differ::MatchTypeForwardPointersByName(const IdGroup& src, GroupIdsAndMatch( src, dst, "", &Differ::GetSanitizedName, [this](const IdGroup& src_group, const IdGroup& dst_group) { - // Match only if there's a unique forward declaration with this debug // name. if (src_group.size() == 1 && dst_group.size() == 1) { @@ -1598,7 +1607,6 @@ void Differ::MatchFunctionParamIds(const opt::Function* src_func, GroupIdsAndMatch( src_params, dst_params, "", &Differ::GetSanitizedName, [this](const IdGroup& src_group, const IdGroup& dst_group) { - // There shouldn't be two parameters with the same name, so the ids // should match. There is nothing restricting the SPIR-V however to have // two parameters with the same name, so be resilient against that. @@ -1613,7 +1621,6 @@ void Differ::MatchFunctionParamIds(const opt::Function* src_func, src_params, dst_params, 0, &Differ::GroupIdsHelperGetTypeId, [this](const IdGroup& src_group_by_type_id, const IdGroup& dst_group_by_type_id) { - const size_t shared_param_count = std::min(src_group_by_type_id.size(), dst_group_by_type_id.size()); @@ -2064,9 +2071,10 @@ void Differ::MatchEntryPointIds() { } // Otherwise match them by name. - bool matched = false; for (const opt::Instruction* src_inst : src_insts) { for (const opt::Instruction* dst_inst : dst_insts) { + if (id_map_.IsDstMapped(dst_inst)) continue; + const opt::Operand& src_name = src_inst->GetOperand(2); const opt::Operand& dst_name = dst_inst->GetOperand(2); @@ -2075,13 +2083,9 @@ void Differ::MatchEntryPointIds() { uint32_t dst_id = dst_inst->GetSingleWordOperand(1); id_map_.MapIds(src_id, dst_id); id_map_.MapInsts(src_inst, dst_inst); - matched = true; break; } } - if (matched) { - break; - } } } } @@ -2126,7 +2130,6 @@ void Differ::MatchTypeForwardPointers() { spv::StorageClass::Max, &Differ::GroupIdsHelperGetTypePointerStorageClass, [this](const IdGroup& src_group_by_storage_class, const IdGroup& dst_group_by_storage_class) { - // Group them further by the type they are pointing to and loop over // them. GroupIdsAndMatch( @@ -2134,7 +2137,6 @@ void Differ::MatchTypeForwardPointers() { spv::Op::Max, &Differ::GroupIdsHelperGetTypePointerTypeOp, [this](const IdGroup& src_group_by_type_op, const IdGroup& dst_group_by_type_op) { - // Group them even further by debug info, if possible and match by // debug name. MatchTypeForwardPointersByName(src_group_by_type_op, @@ -2378,7 +2380,6 @@ void Differ::MatchFunctions() { GroupIdsAndMatch( src_func_ids, dst_func_ids, "", &Differ::GetSanitizedName, [this](const IdGroup& src_group, const IdGroup& dst_group) { - // If there is a single function with this name in src and dst, it's a // definite match. if (src_group.size() == 1 && dst_group.size() == 1) { @@ -2392,7 +2393,6 @@ void Differ::MatchFunctions() { &Differ::GroupIdsHelperGetTypeId, [this](const IdGroup& src_group_by_type_id, const IdGroup& dst_group_by_type_id) { - if (src_group_by_type_id.size() == 1 && dst_group_by_type_id.size() == 1) { id_map_.MapIds(src_group_by_type_id[0], @@ -2437,7 +2437,6 @@ void Differ::MatchFunctions() { src_func_ids, dst_func_ids, 0, &Differ::GroupIdsHelperGetTypeId, [this](const IdGroup& src_group_by_type_id, const IdGroup& dst_group_by_type_id) { - BestEffortMatchFunctions(src_group_by_type_id, dst_group_by_type_id, src_func_insts_, dst_func_insts_); }); diff --git a/test/diff/diff_files/multiple_same_entry_points_autogen.cpp b/test/diff/diff_files/multiple_same_entry_points_autogen.cpp index 9d011661c6..00bee6be3a 100644 --- a/test/diff/diff_files/multiple_same_entry_points_autogen.cpp +++ b/test/diff/diff_files/multiple_same_entry_points_autogen.cpp @@ -125,9 +125,8 @@ TEST(DiffTest, MultipleSameEntryPoints) { OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 -+OpEntryPoint Vertex %12 "main2" %13 %14 %15 OpEntryPoint Vertex %4 "main1" %8 %10 --OpEntryPoint Vertex %12 "main2" %13 %14 %15 + OpEntryPoint Vertex %12 "main2" %13 %14 %15 OpSource ESSL 310 OpName %4 "main1" OpName %12 "main2" @@ -257,9 +256,8 @@ TEST(DiffTest, MultipleSameEntryPointsNoDebug) { OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 -+OpEntryPoint Vertex %12 "main2" %13 %14 %15 OpEntryPoint Vertex %4 "main1" %8 %10 --OpEntryPoint Vertex %12 "main2" %13 %14 %15 + OpEntryPoint Vertex %12 "main2" %13 %14 %15 OpSource ESSL 310 OpDecorate %8 Location 0 OpDecorate %10 Location 0 @@ -304,9 +302,8 @@ TEST(DiffTest, MultipleSameEntryPointsDumpIds) { OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 -+OpEntryPoint Vertex %12 "main2" %13 %14 %15 OpEntryPoint Vertex %4 "main1" %8 %10 --OpEntryPoint Vertex %12 "main2" %13 %14 %15 + OpEntryPoint Vertex %12 "main2" %13 %14 %15 OpSource ESSL 310 OpName %4 "main1" OpName %12 "main2" From 235800182707c95f8886dcc0c6b0853abd4886a9 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 25 May 2023 09:00:30 -0400 Subject: [PATCH 154/523] Add Abseil as a dep and update RE2 (#5236) * Add Abseil as a dep and update RE2 The latest version of RE2 requires Abseil. This PR adds Abseil as an external dependence, and update RE2 to use it. * Remove debug code and add comment. --- .gitignore | 1 + DEPS | 5 +++++ external/CMakeLists.txt | 9 +++++++++ 3 files changed, 15 insertions(+) diff --git a/.gitignore b/.gitignore index ec709ba79d..d9c6a1a496 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ compile_commands.json /build*/ /buildtools/ +/external/abseil_cpp/ /external/googletest /external/SPIRV-Headers /external/spirv-headers diff --git a/DEPS b/DEPS index 3f6a6ea4ee..889b2ca657 100644 --- a/DEPS +++ b/DEPS @@ -3,6 +3,8 @@ use_relative_paths = True vars = { 'github': 'https://github.com', + 'abseil_revision': '79ca5d7aad63973c83a4962a66ab07cd623131ea', + 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', 'googletest_revision': '45804691223635953f311cf31a10c632553bbfc3', @@ -15,6 +17,9 @@ vars = { } deps = { + 'external/abseil_cpp': + Var('github') + '/abseil/abseil-cpp.git@' + Var('abseil_revision'), + 'external/effcee': Var('github') + '/google/effcee.git@' + Var('effcee_revision'), diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 6ee37d9ea5..c412d16f20 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -97,6 +97,15 @@ if (NOT ${SPIRV_SKIP_TESTS}) # If already configured, then use that. Otherwise, prefer to find it under 're2' # in this directory. if (NOT TARGET re2) + + # RE2 depends on Abseil, so we need to add it. + if(NOT TARGET absl::base) + set(ABSL_INTERNAL_AT_LEAST_CXX17 ON) + set(ABSL_PROPAGATE_CXX_STD ON) + set(ABSL_ENABLE_INSTALL ON) + add_subdirectory(abseil_cpp EXCLUDE_FROM_ALL) + endif() + # If we are configuring RE2, then turn off its testing. It takes a long time and # does not add much value for us. If an enclosing project configured RE2, then it # has already chosen whether to enable RE2 testing. From af27ece7502e43ec4ae6033beacb8df3f1de7f42 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 25 May 2023 09:07:22 -0400 Subject: [PATCH 155/523] Check if const is zero before getting components. (#5217) * Check if const is zero before getting components. Two folding rules try to cast a constant to a MatrixConstant before checking if it is a Null constant. This leads to the null pointer being dereferneced. The solution is to move the check for zero earlier. Fixes https://github.com/microsoft/DirectXShaderCompiler/issues/5063 --- source/opt/const_folding_rules.cpp | 24 ++++++++++++------------ test/opt/fold_test.cpp | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/source/opt/const_folding_rules.cpp b/source/opt/const_folding_rules.cpp index 26108082f4..e3414de3b6 100644 --- a/source/opt/const_folding_rules.cpp +++ b/source/opt/const_folding_rules.cpp @@ -376,13 +376,7 @@ ConstantFoldingRule FoldVectorTimesMatrix() { assert(c1->type()->AsVector()->element_type() == element_type && c2->type()->AsMatrix()->element_type() == vector_type); - // Get a float vector that is the result of vector-times-matrix. - std::vector c1_components = - c1->GetVectorComponents(const_mgr); - std::vector c2_components = - c2->AsMatrixConstant()->GetComponents(); uint32_t resultVectorSize = result_type->AsVector()->element_count(); - std::vector ids; if ((c1 && c1->IsZero()) || (c2 && c2->IsZero())) { @@ -395,6 +389,12 @@ ConstantFoldingRule FoldVectorTimesMatrix() { return const_mgr->GetConstant(vector_type, ids); } + // Get a float vector that is the result of vector-times-matrix. + std::vector c1_components = + c1->GetVectorComponents(const_mgr); + std::vector c2_components = + c2->AsMatrixConstant()->GetComponents(); + if (float_type->width() == 32) { for (uint32_t i = 0; i < resultVectorSize; ++i) { float result_scalar = 0.0f; @@ -472,13 +472,7 @@ ConstantFoldingRule FoldMatrixTimesVector() { assert(c1->type()->AsMatrix()->element_type() == vector_type); assert(c2->type()->AsVector()->element_type() == element_type); - // Get a float vector that is the result of matrix-times-vector. - std::vector c1_components = - c1->AsMatrixConstant()->GetComponents(); - std::vector c2_components = - c2->GetVectorComponents(const_mgr); uint32_t resultVectorSize = result_type->AsVector()->element_count(); - std::vector ids; if ((c1 && c1->IsZero()) || (c2 && c2->IsZero())) { @@ -491,6 +485,12 @@ ConstantFoldingRule FoldMatrixTimesVector() { return const_mgr->GetConstant(vector_type, ids); } + // Get a float vector that is the result of matrix-times-vector. + std::vector c1_components = + c1->AsMatrixConstant()->GetComponents(); + std::vector c2_components = + c2->GetVectorComponents(const_mgr); + if (float_type->width() == 32) { for (uint32_t i = 0; i < resultVectorSize; ++i) { float result_scalar = 0.0f; diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index 77442b6586..d6e7ce26e0 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -290,7 +290,7 @@ OpName %main "main" %v4float_1_1_1_1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 %v4float_1_2_3_4 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4 %v4float_null = OpConstantNull %v4float -%mat4v4float_null = OpConstantComposite %mat4v4float %v4float_null %v4float_null %v4float_null %v4float_null +%mat4v4float_null = OpConstantNull %mat4v4float %mat4v4float_1_2_3_4 = OpConstantComposite %mat4v4float %v4float_1_2_3_4 %v4float_1_2_3_4 %v4float_1_2_3_4 %v4float_1_2_3_4 %mat4v4float_1_2_3_4_null = OpConstantComposite %mat4v4float %v4float_1_2_3_4 %v4float_null %v4float_1_2_3_4 %v4float_null %107 = OpConstantComposite %v4double %double_0 %double_0 %double_0 %double_0 @@ -301,7 +301,7 @@ OpName %main "main" %v4double_1_2_3_4 = OpConstantComposite %v4double %double_1 %double_2 %double_3 %double_4 %v4double_1_1_1_0p5 = OpConstantComposite %v4double %double_1 %double_1 %double_1 %double_0p5 %v4double_null = OpConstantNull %v4double -%mat4v4double_null = OpConstantComposite %mat4v4double %v4double_null %v4double_null %v4double_null %v4double_null +%mat4v4double_null = OpConstantNull %mat4v4double %mat4v4double_1_2_3_4 = OpConstantComposite %mat4v4double %v4double_1_2_3_4 %v4double_1_2_3_4 %v4double_1_2_3_4 %v4double_1_2_3_4 %mat4v4double_1_2_3_4_null = OpConstantComposite %mat4v4double %v4double_1_2_3_4 %v4double_null %v4double_1_2_3_4 %v4double_null %v4float_n1_2_1_3 = OpConstantComposite %v4float %float_n1 %float_2 %float_1 %float_3 From e0936b646cdd2c7bb930501a26f2b95b2f684455 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 25 May 2023 09:34:36 -0400 Subject: [PATCH 156/523] Roll external/spirv-headers/ bdbfd019b..69155b22b (1 commit) (#5238) https://github.com/KhronosGroup/SPIRV-Headers/compare/bdbfd019be69...69155b22b3b1 $ git log bdbfd019b..69155b22b --date=short --no-merges --format='%ad %ae %s' 2023-05-18 jjfumero Name and url for the TornadoVM SPIR-V Library Tool updated 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 889b2ca657..788017ac88 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': 'c9cba76063cf4235c1a15dd14a24a4ef8d623761', - 'spirv_headers_revision': 'bdbfd019be6952fd8fa9bd5606a8798a7530c853', + 'spirv_headers_revision': '69155b22b3b1f2d0cfed48f59167d9792de1fd79', } deps = { From 3e82fa067d5d96d4ba539819363bc05db1d12476 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Fri, 26 May 2023 10:49:33 -0400 Subject: [PATCH 157/523] Revert "Disable RE2 autoroll (#5234)" (#5239) This reverts commit e357a36ccfac9a1fa71e00b04237d117b53093b6. --- utils/roll_deps.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/utils/roll_deps.sh b/utils/roll_deps.sh index b931b5aa12..d19ee000e5 100755 --- a/utils/roll_deps.sh +++ b/utils/roll_deps.sh @@ -29,12 +29,9 @@ function ExitIfIsInterestingError() { } -# We are not rolling re2 for now. The latest version requires Abseil, and we -# need time to determine the best way to do that. See -# https://github.com/KhronosGroup/SPIRV-Tools/issues/5233. dependencies=("external/effcee/" "external/googletest/" -# "external/re2/" + "external/re2/" "external/spirv-headers/") From 1021ec302f568cd83fee9f4eaa763dadb66e40b0 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Fri, 26 May 2023 10:50:09 -0400 Subject: [PATCH 158/523] Add Abseil dep to the README (#5242) --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 92e4d3c06d..fc9d6c773f 100644 --- a/README.md +++ b/README.md @@ -292,16 +292,18 @@ For some kinds of development, you may need the latest sources from the third-pa git clone https://github.com/google/googletest.git spirv-tools/external/googletest git clone https://github.com/google/effcee.git spirv-tools/external/effcee git clone https://github.com/google/re2.git spirv-tools/external/re2 + git clone https://github.com/abseil/abseil-cpp.git spirv-tools/external/abseil_cpp #### Dependency on Effcee Some tests depend on the [Effcee][effcee] library for stateful matching. -Effcee itself depends on [RE2][re2]. +Effcee itself depends on [RE2][re2], and RE2 depends on [Abseil][abseil-cpp]. * If SPIRV-Tools is configured as part of a larger project that already uses Effcee, then that project should include Effcee before SPIRV-Tools. -* Otherwise, SPIRV-Tools expects Effcee sources to appear in `external/effcee` - and RE2 sources to appear in `external/re2`. +* Otherwise, SPIRV-Tools expects Effcee sources to appear in `external/effcee`, + RE2 sources to appear in `external/re2`, and Abseil sources to appear in + `external/abseil_cpp`. ### Source code organization @@ -313,6 +315,9 @@ Effcee itself depends on [RE2][re2]. * `external/re2`: Location of [RE2][re2] sources, if the `re2` library is not already configured by an enclosing project. (The Effcee project already requires RE2.) +* `external/abseil_cpp`: Location of [Abseil][abseil-cpp] sources, if Abseil is + not already configured by an enclosing project. + (The RE2 project already requires Abseil.) * `include/`: API clients should add this directory to the include search path * `external/spirv-headers`: Intended location for [SPIR-V headers][spirv-headers], not provided From 23cb9b96cc2acf93e55839136b2c9643cbef6df6 Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Mon, 29 May 2023 22:20:07 +0900 Subject: [PATCH 159/523] spirv-val: Remove VUID from 1.3.251 spec (#5244) --- source/val/validate_image.cpp | 1 - source/val/validation_state.cpp | 2 -- test/val/val_image_test.cpp | 2 -- 3 files changed, 5 deletions(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 733556b1d2..8062d962c3 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -297,7 +297,6 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, spv::ImageOperandsMask::ConstOffsets | spv::ImageOperandsMask::Offsets)) > 1) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << _.VkErrorID(4662) << "Image Operands Offset, ConstOffset, ConstOffsets, Offsets " "cannot be used together"; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 6072589ccd..5a138d95dc 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -2048,8 +2048,6 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpImageTexelPointer-04658); case 4659: return VUID_WRAP(VUID-StandaloneSpirv-OpImageQuerySizeLod-04659); - case 4662: - return VUID_WRAP(VUID-StandaloneSpirv-Offset-04662); case 4663: return VUID_WRAP(VUID-StandaloneSpirv-Offset-04663); case 4664: diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index aa335c869d..9aceaf5774 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -2177,8 +2177,6 @@ TEST_F(ValidateImage, SampleImplicitLodVulkanMoreThanOneOffset) { CompileSuccessfully( GenerateShaderCode(body, "", "Fragment", "", SPV_ENV_VULKAN_1_0).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); - EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-StandaloneSpirv-Offset-04662")); EXPECT_THAT( getDiagnosticString(), HasSubstr("Image Operands Offset, ConstOffset, ConstOffsets, Offsets " From 06bbd7f53a72cf82b4362331ec80a20f70991fc3 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Mon, 29 May 2023 14:18:37 -0400 Subject: [PATCH 160/523] Update deps in sva (#5246) Depenabot is not able to update these deps to avoid security issues. I'm updating all of them manually. This was done by running `yarn upgrade --latest`. I do not claim to understand the changes to `yarn.lock`. --- tools/sva/package.json | 10 +- tools/sva/yarn.lock | 2212 +++++++++++++++++----------------------- 2 files changed, 959 insertions(+), 1263 deletions(-) diff --git a/tools/sva/package.json b/tools/sva/package.json index 3072d4cc86..15feacae93 100644 --- a/tools/sva/package.json +++ b/tools/sva/package.json @@ -15,11 +15,11 @@ "bundle": "rollup -c" }, "devDependencies": { - "chai": "^4.2.0", - "eslint": "^6.3.0", + "chai": "^4.3.7", + "eslint": "^8.41.0", "esm": "^3.2.25", - "mocha": "^6.2.0", - "rollup": "^1.21.4", - "serve": "^11.1.0" + "mocha": "^10.2.0", + "rollup": "^3.23.0", + "serve": "^14.2.0" } } diff --git a/tools/sva/yarn.lock b/tools/sva/yarn.lock index 2dc95d8a48..d25a286b6c 100644 --- a/tools/sva/yarn.lock +++ b/tools/sva/yarn.lock @@ -2,158 +2,206 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" - integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== dependencies: - "@babel/highlight" "^7.0.0" + eslint-visitor-keys "^3.3.0" -"@babel/highlight@^7.0.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" - integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ== - dependencies: - chalk "^2.0.0" - esutils "^2.0.2" - js-tokens "^4.0.0" - -"@types/estree@0.0.39": - version "0.0.39" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" - integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== +"@eslint-community/regexpp@^4.4.0": + version "4.5.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884" + integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ== -"@types/node@^12.7.5": - version "12.7.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.5.tgz#e19436e7f8e9b4601005d73673b6dc4784ffcc2f" - integrity sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w== +"@eslint/eslintrc@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.3.tgz#4910db5505f4d503f27774bf356e3704818a0331" + integrity sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.5.2" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.41.0": + version "8.41.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.41.0.tgz#080321c3b68253522f7646b55b577dd99d2950b3" + integrity sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA== + +"@humanwhocodes/config-array@^0.11.8": + version "0.11.8" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9" + integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@zeit/schemas@2.6.0": - version "2.6.0" - resolved "https://registry.yarnpkg.com/@zeit/schemas/-/schemas-2.6.0.tgz#004e8e553b4cd53d538bd38eac7bcbf58a867fe3" - integrity sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg== +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== -accepts@~1.3.5: - version "1.3.7" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" - integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== dependencies: - mime-types "~2.1.24" - negotiator "0.6.2" + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" -acorn-jsx@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.2.tgz#84b68ea44b373c4f8686023a551f61a21b7c4a4f" - integrity sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw== - -acorn@^7.0.0: - version "7.1.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" - integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== +"@nodelib/fs.stat@2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -ajv@6.5.3: - version "6.5.3" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9" - integrity sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg== +"@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== dependencies: - fast-deep-equal "^2.0.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@zeit/schemas@2.29.0": + version "2.29.0" + resolved "https://registry.yarnpkg.com/@zeit/schemas/-/schemas-2.29.0.tgz#a59ae6ebfdf4ddc66a876872dd736baa58b6696c" + integrity sha512-g5QiLIfbg3pLuYUJPlisNKY+epQJTcMDsOnVNkscrDP1oi7vmJnzOANYJI/1pZcVJ6umUkBv3aFtlg1UvUHGzA== + +accepts@~1.3.5: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.8.0: + version "8.8.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + +ajv@8.11.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" uri-js "^4.2.2" -ajv@^6.10.0, ajv@^6.10.2: - version "6.10.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" - integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: - fast-deep-equal "^2.0.1" + fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-align@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" - integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38= +ansi-align@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" + integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== dependencies: - string-width "^2.0.0" + string-width "^4.1.0" -ansi-colors@3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" - integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== -ansi-escapes@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: - color-convert "^1.9.0" + normalize-path "^3.0.0" + picomatch "^2.0.4" -arch@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/arch/-/arch-2.1.1.tgz#8f5c2731aa35a30929221bb0640eed65175ec84e" - integrity sha512-BLM56aPo9vLLFVa8+/+pJLnrZ7QGGTVHWsCwieAWT9o9K8UeGaQbzZbGoabWLOo2ksBCztoXdqBZBplqLDDCSg== +arch@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" + integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== -arg@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arg/-/arg-2.0.0.tgz#c06e7ff69ab05b3a4a03ebe0407fac4cba657545" - integrity sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w== +arg@5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c" + integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -boxen@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" - integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw== - dependencies: - ansi-align "^2.0.0" - camelcase "^4.0.0" - chalk "^2.0.1" - cli-boxes "^1.0.0" - string-width "^2.0.0" - term-size "^1.2.0" - widest-line "^2.0.0" + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +boxen@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-7.0.0.tgz#9e5f8c26e716793fc96edcf7cf754cdf5e3fbf32" + integrity sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg== + dependencies: + ansi-align "^3.0.1" + camelcase "^7.0.0" + chalk "^5.0.1" + cli-boxes "^3.0.0" + string-width "^5.1.2" + type-fest "^2.13.0" + widest-line "^4.0.1" + wrap-ansi "^8.0.1" brace-expansion@^1.1.7: version "1.1.11" @@ -163,6 +211,20 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" @@ -171,163 +233,154 @@ browser-stdout@1.3.1: bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" - integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -camelcase@^5.0.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== +camelcase@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-7.0.1.tgz#f02e50af9fd7782bc8b88a3558c32fd3a388f048" + integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw== -chai@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.2.0.tgz#760aa72cf20e3795e84b12877ce0e83737aa29e5" - integrity sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw== +chai@^4.3.7: + version "4.3.7" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.7.tgz#ec63f6df01829088e8bf55fca839bcd464a8ec51" + integrity sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A== dependencies: assertion-error "^1.1.0" check-error "^1.0.2" - deep-eql "^3.0.1" + deep-eql "^4.1.2" get-func-name "^2.0.0" - pathval "^1.1.0" + loupe "^2.3.1" + pathval "^1.1.1" type-detect "^4.0.5" -chalk@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" - integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ== +chalk-template@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/chalk-template/-/chalk-template-0.4.0.tgz#692c034d0ed62436b9062c1707fadcd0f753204b" + integrity sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg== dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" + chalk "^4.1.2" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== +chalk@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.1.tgz#ca57d71e82bb534a296df63bbacc4a1c22b2a4b6" + integrity sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w== + +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" + ansi-styles "^4.1.0" + supports-color "^7.1.0" -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +chalk@^5.0.1: + version "5.2.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.2.0.tgz#249623b7d66869c673699fb66d65723e54dfcfb3" + integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== check-error@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= - -cli-boxes@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" - integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM= - -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - dependencies: - restore-cursor "^2.0.0" - -cli-width@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= + integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== + +chokidar@3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +cli-boxes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-3.0.0.tgz#71a10c716feeba005e4504f36329ef0b17cf3145" + integrity sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g== -clipboardy@1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-1.2.3.tgz#0526361bf78724c1f20be248d428e365433c07ef" - integrity sha512-2WNImOvCRe6r63Gk9pShfkwXsVtKCroMAevIbiae021mS850UkWPbevxsBz3tnvjZIEGvlwaqCPsw+4ulzNgJA== +clipboardy@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-3.0.0.tgz#f3876247404d334c9ed01b6f269c11d09a5e3092" + integrity sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg== dependencies: - arch "^2.1.0" - execa "^0.8.0" + arch "^2.2.0" + execa "^5.1.1" + is-wsl "^2.2.0" -cliui@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" - integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi "^2.0.0" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: - color-name "1.1.3" + color-name "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -compressible@~2.0.14: - version "2.0.17" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.17.tgz#6e8c108a16ad58384a977f3a482ca20bff2f38c1" - integrity sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw== +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== dependencies: - mime-db ">= 1.40.0 < 2" + mime-db ">= 1.43.0 < 2" -compression@1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db" - integrity sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg== +compression@1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== dependencies: accepts "~1.3.5" bytes "3.0.0" - compressible "~2.0.14" + compressible "~2.0.16" debug "2.6.9" - on-headers "~1.0.1" + on-headers "~1.0.2" safe-buffer "5.1.2" vary "~1.1.2" concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" - integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= - -cross-spawn@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" + integrity sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA== -cross-spawn@^6.0.0, cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== +cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" debug@2.6.9: version "2.6.9" @@ -336,29 +389,22 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - -debug@^4.0.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== +debug@4.3.4, debug@^4.1.1, debug@^4.3.2: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: - ms "^2.1.1" + ms "2.1.2" -decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== -deep-eql@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" - integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== +deep-eql@^4.1.2: + version "4.1.3" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" + integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== dependencies: type-detect "^4.0.0" @@ -367,22 +413,15 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - -define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -diff@3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" - integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== doctrine@^3.0.0: version "3.0.0" @@ -391,287 +430,222 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - -end-of-stream@^1.1.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" - integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== - dependencies: - once "^1.4.0" - -es-abstract@^1.5.1: - version "1.14.2" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.14.2.tgz#7ce108fad83068c8783c3cdf62e504e084d8c497" - integrity sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg== - dependencies: - es-to-primitive "^1.2.0" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.0" - is-callable "^1.1.4" - is-regex "^1.0.4" - object-inspect "^1.6.0" - object-keys "^1.1.1" - string.prototype.trimleft "^2.0.0" - string.prototype.trimright "^2.0.0" - -es-to-primitive@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" - integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== -eslint-scope@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" - integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== - dependencies: - esrecurse "^4.1.0" - estraverse "^4.1.1" +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -eslint-utils@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab" - integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q== - dependencies: - eslint-visitor-keys "^1.0.0" +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== -eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" - integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== -eslint@^6.3.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.4.0.tgz#5aa9227c3fbe921982b2eda94ba0d7fae858611a" - integrity sha512-WTVEzK3lSFoXUovDHEbkJqCVPEPwbhCq4trDktNI6ygs7aO41d4cDT0JFAT5MivzZeVLWlg7vHL+bgrQv/t3vA== - dependencies: - "@babel/code-frame" "^7.0.0" +escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-scope@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b" + integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994" + integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== + +eslint@^8.41.0: + version "8.41.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.41.0.tgz#3062ca73363b4714b16dbc1e60f035e6134b6f1c" + integrity sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.4.0" + "@eslint/eslintrc" "^2.0.3" + "@eslint/js" "8.41.0" + "@humanwhocodes/config-array" "^0.11.8" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" ajv "^6.10.0" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" doctrine "^3.0.0" - eslint-scope "^5.0.0" - eslint-utils "^1.4.2" - eslint-visitor-keys "^1.1.0" - espree "^6.1.1" - esquery "^1.0.1" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.0" + eslint-visitor-keys "^3.4.1" + espree "^9.5.2" + esquery "^1.4.2" esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^11.7.0" - ignore "^4.0.6" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" - inquirer "^6.4.1" is-glob "^4.0.0" - js-yaml "^3.13.1" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.14" - minimatch "^3.0.4" - mkdirp "^0.5.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.8.2" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^6.1.2" - strip-ansi "^5.2.0" - strip-json-comments "^3.0.1" - table "^5.2.3" + optionator "^0.9.1" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" text-table "^0.2.0" - v8-compile-cache "^2.0.3" esm@^3.2.25: version "3.2.25" resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== -espree@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.1.tgz#7f80e5f7257fc47db450022d723e356daeb1e5de" - integrity sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ== +espree@^9.5.2: + version "9.5.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.2.tgz#e994e7dc33a082a7a82dceaf12883a829353215b" + integrity sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw== dependencies: - acorn "^7.0.0" - acorn-jsx "^5.0.2" - eslint-visitor-keys "^1.1.0" - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" -esquery@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" - integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== dependencies: - estraverse "^4.0.0" + estraverse "^5.1.0" -esrecurse@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" - integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== dependencies: - estraverse "^4.1.0" + estraverse "^5.2.0" -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -execa@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" - integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -execa@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da" - integrity sha1-2NdrvBtVIX7RkP1t1J08d07PyNo= - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= +execa@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-levenshtein@~2.0.4: +fast-levenshtein@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fast-url-parser@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" - integrity sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0= + integrity sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ== dependencies: punycode "^1.3.2" -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== dependencies: - escape-string-regexp "^1.0.5" + reusify "^1.0.4" -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== dependencies: - flat-cache "^2.0.1" + flat-cache "^3.0.4" -find-up@3.0.0, find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== dependencies: - locate-path "^3.0.0" + to-regex-range "^5.0.1" -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== +find-up@5.0.0, find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" + locate-path "^6.0.0" + path-exists "^4.0.0" -flat@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" - integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw== +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== dependencies: - is-buffer "~2.0.3" + flatted "^3.1.0" + rimraf "^3.0.2" -flatted@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" - integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -get-caller-file@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" - integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== -get-caller-file@^2.0.1: +get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== @@ -679,31 +653,31 @@ get-caller-file@^2.0.1: 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 sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= + integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== -get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== dependencies: - pump "^3.0.0" + is-glob "^4.0.3" -glob-parent@^5.0.0: +glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" -glob@7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== +glob@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -713,65 +687,53 @@ glob@7.1.3: path-is-absolute "^1.0.0" glob@^7.1.3: - version "7.1.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" - integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.4" + minimatch "^3.1.1" once "^1.3.0" path-is-absolute "^1.0.0" -globals@^11.7.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +globals@^13.19.0: + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" -has-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" - integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -has@^1.0.1, has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== he@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +ignore@^5.2.0: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== -import-fresh@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.1.0.tgz#6d33fa1dcef6df930fae003446f33415af905118" - integrity sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ== +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" @@ -779,12 +741,12 @@ import-fresh@^3.0.0: imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" @@ -795,193 +757,147 @@ inherits@2: integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== ini@~1.3.0: - version "1.3.7" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" - integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== - -inquirer@^6.4.1: - version "6.5.2" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" - integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== - dependencies: - ansi-escapes "^3.2.0" - chalk "^2.4.2" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^3.0.3" - figures "^2.0.0" - lodash "^4.17.12" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^6.4.0" - string-width "^2.1.0" - strip-ansi "^5.1.0" - through "^2.3.6" - -invert-kv@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" - integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -is-buffer@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" - integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw== - -is-callable@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" - integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" -is-date-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-glob@^4.0.0, is-glob@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" -is-promise@^2.1.0: +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-plain-obj@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== -is-regex@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= - dependencies: - has "^1.0.1" +is-port-reachable@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-port-reachable/-/is-port-reachable-4.0.0.tgz#dac044091ef15319c8ab2f34604d8794181f8c2d" + integrity sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig== -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-symbol@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" - integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== dependencies: - has-symbols "^1.0.0" + is-docker "^2.0.0" isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -js-yaml@3.13.1, js-yaml@^3.13.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== +js-yaml@4.1.0, js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: - argparse "^1.0.7" - esprima "^4.0.0" + argparse "^2.0.1" json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -lcid@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" - integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== - dependencies: - invert-kv "^2.0.0" - -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + prelude-ls "^1.2.1" + type-check "~0.4.0" -log-symbols@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== dependencies: - chalk "^2.0.1" + p-locate "^5.0.0" -lru-cache@^4.0.1: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -map-age-cleaner@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" - integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== dependencies: - p-defer "^1.0.0" + chalk "^4.1.0" + is-unicode-supported "^0.1.0" -mem@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" - integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== +loupe@^2.3.1: + version "2.3.6" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" + integrity sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA== dependencies: - map-age-cleaner "^0.1.1" - mimic-fn "^2.0.0" - p-is-promise "^2.0.0" + get-func-name "^2.0.0" -mime-db@1.40.0: - version "1.40.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" - integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -"mime-db@>= 1.40.0 < 2": - version "1.41.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.41.0.tgz#9110408e1f6aa1b34aef51f2c9df3caddf46b6a0" - integrity sha512-B5gxBI+2K431XW8C2rcc/lhppbuji67nf9v39eH8pkWoZDxnAL0PxdpH32KYRScniF8qDHBDlI+ipgg5WrCUYw== +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== mime-db@~1.33.0: version "1.33.0" @@ -995,237 +911,150 @@ mime-types@2.1.18: dependencies: mime-db "~1.33.0" -mime-types@~2.1.24: - version "2.1.24" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" - integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== +mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: - mime-db "1.40.0" + mime-db "1.52.0" -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - -mimic-fn@^2.0.0: +mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimatch@3.0.4, minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== +minimatch@3.1.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= +minimatch@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== + dependencies: + brace-expansion "^2.0.1" minimist@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= - -mkdirp@0.5.1, mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= - dependencies: - minimist "0.0.8" + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -mocha@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.0.tgz#f896b642843445d1bb8bca60eabd9206b8916e56" - integrity sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ== +mocha@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8" + integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg== dependencies: - ansi-colors "3.2.3" + ansi-colors "4.1.1" browser-stdout "1.3.1" - debug "3.2.6" - diff "3.5.0" - escape-string-regexp "1.0.5" - find-up "3.0.0" - glob "7.1.3" - growl "1.10.5" + chokidar "3.5.3" + debug "4.3.4" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" he "1.2.0" - js-yaml "3.13.1" - log-symbols "2.2.0" - minimatch "3.0.4" - mkdirp "0.5.1" - ms "2.1.1" - node-environment-flags "1.0.5" - object.assign "4.1.0" - strip-json-comments "2.0.1" - supports-color "6.0.0" - which "1.3.1" - wide-align "1.1.3" - yargs "13.2.2" - yargs-parser "13.0.0" - yargs-unparser "1.5.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "5.0.1" + ms "2.1.3" + nanoid "3.3.3" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + workerpool "6.2.1" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@^2.1.1: +ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= +ms@2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" + integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - -negotiator@0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" - integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -node-environment-flags@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" - integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ== - dependencies: - object.getownpropertydescriptors "^2.0.3" - semver "^5.7.0" - -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -object-inspect@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" - integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== - -object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== -object.assign@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -object.getownpropertydescriptors@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" - integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== dependencies: - define-properties "^1.1.2" - es-abstract "^1.5.1" + path-key "^3.0.0" -on-headers@~1.0.1: +on-headers@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== -once@^1.3.0, once@^1.3.1, once@^1.4.0: +once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: - mimic-fn "^1.0.0" + mimic-fn "^2.1.0" -optionator@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.4" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - wordwrap "~1.0.0" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" -os-locale@^3.0.0, os-locale@^3.1.0: +p-limit@^3.0.2: version "3.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" - integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: - execa "^1.0.0" - lcid "^2.0.0" - mem "^4.0.0" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= - -p-defer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" - integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= + yocto-queue "^0.1.0" -p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - -p-is-promise@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" - integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== - -p-limit@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" - integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== - dependencies: - p-try "^2.0.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== dependencies: - p-limit "^2.0.0" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + p-limit "^3.0.2" parent-module@^1.0.0: version "1.0.1" @@ -1234,73 +1063,72 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-is-inside@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" - integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== path-to-regexp@2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45" integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ== -pathval@^1.1.0: +pathval@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - -pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== punycode@^1.3.2: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== punycode@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" range-parser@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= + integrity sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A== rc@^1.0.1, rc@^1.1.6: version "1.2.8" @@ -1312,10 +1140,12 @@ rc@^1.0.1, rc@^1.1.6: minimist "^1.2.0" strip-json-comments "~2.0.1" -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" registry-auth-token@3.3.2: version "3.3.2" @@ -1328,451 +1158,317 @@ registry-auth-token@3.3.2: registry-url@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" - integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI= + integrity sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA== dependencies: rc "^1.0.1" require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== -require-main-filename@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" - integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" -rollup@^1.21.4: - version "1.21.4" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.21.4.tgz#00a41a30f90095db890301b226cbe2918e4cf54d" - integrity sha512-Pl512XVCmVzgcBz5h/3Li4oTaoDcmpuFZ+kdhS/wLreALz//WuDAMfomD3QEYl84NkDu6Z6wV9twlcREb4qQsw== - dependencies: - "@types/estree" "0.0.39" - "@types/node" "^12.7.5" - acorn "^7.0.0" +rollup@^3.23.0: + version "3.23.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.23.0.tgz#b8d6146dac4bf058ee817f92820988e9b358b564" + integrity sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ== + optionalDependencies: + fsevents "~2.3.2" -run-async@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" - integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= - dependencies: - is-promise "^2.1.0" - -rxjs@^6.4.0: - version "6.5.3" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.3.tgz#510e26317f4db91a7eb1de77d9dd9ba0a4899a3a" - integrity sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA== +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== dependencies: - tslib "^1.9.0" + queue-microtask "^1.2.2" safe-buffer@5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.0.1: - version "5.2.0" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" - integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== - -"safer-buffer@>= 2.1.2 < 3": - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +safe-buffer@^5.0.1, safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -semver@^5.5.0, semver@^5.7.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^6.1.2: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" -serve-handler@6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.0.tgz#f1606dc6ff8f9029a1ee042c11dfe7903a5cb92e" - integrity sha512-63N075Tn3PsFYcu0NVV7tb367UbiW3gnC+/50ohL4oqOhAG6bmbaWqiRcXQgbzqc0ALBjSAzg7VTfa0Qw4E3hA== +serve-handler@6.1.5: + version "6.1.5" + resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.5.tgz#a4a0964f5c55c7e37a02a633232b6f0d6f068375" + integrity sha512-ijPFle6Hwe8zfmBxJdE+5fta53fdIY0lHISJvuikXB3VYFafRjMRpOffSPvCYsbKyBA7pvy9oYr/BT1O3EArlg== dependencies: bytes "3.0.0" content-disposition "0.5.2" fast-url-parser "1.1.3" mime-types "2.1.18" - minimatch "3.0.4" + minimatch "3.1.2" path-is-inside "1.0.2" path-to-regexp "2.2.1" range-parser "1.2.0" -serve@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/serve/-/serve-11.1.0.tgz#1bfe2f4a08d0130cbf44711cdb7996cb742172e0" - integrity sha512-+4wpDtOSS+4ZLyDWMxThutA3iOTawX2+yDovOI8cjOUOmemyvNlHyFAsezBlSgbZKTYChI3tzA1Mh0z6XZ62qA== - dependencies: - "@zeit/schemas" "2.6.0" - ajv "6.5.3" - arg "2.0.0" - boxen "1.3.0" - chalk "2.4.1" - clipboardy "1.2.3" - compression "1.7.3" - serve-handler "6.1.0" - update-check "1.5.2" - -set-blocking@^2.0.0: +serve@^14.2.0: + version "14.2.0" + resolved "https://registry.yarnpkg.com/serve/-/serve-14.2.0.tgz#3d768e88fa13ad8644f2393599189707176e66b8" + integrity sha512-+HOw/XK1bW8tw5iBilBz/mJLWRzM8XM6MPxL4J/dKzdxq1vfdEWSwhaR7/yS8EJp5wzvP92p1qirysJvnEtjXg== + dependencies: + "@zeit/schemas" "2.29.0" + ajv "8.11.0" + arg "5.0.2" + boxen "7.0.0" + chalk "5.0.1" + chalk-template "0.4.0" + clipboardy "3.0.0" + compression "1.7.4" + is-port-reachable "4.0.0" + serve-handler "6.1.5" + update-check "1.5.4" + +shebang-command@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + shebang-regex "^3.0.0" -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" +signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -string.prototype.trimleft@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" - integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw== +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: - define-properties "^1.1.3" - function-bind "^1.1.1" + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" -string.prototype.trimright@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" - integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg== +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: - define-properties "^1.1.3" - function-bind "^1.1.1" + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: - ansi-regex "^2.0.0" + ansi-regex "^5.0.1" -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== dependencies: - ansi-regex "^3.0.0" + ansi-regex "^6.0.1" -strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= +strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -strip-json-comments@2.0.1, strip-json-comments@~2.0.1: +strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -strip-json-comments@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" - integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== - -supports-color@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" - integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg== - dependencies: - has-flag "^3.0.0" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== dependencies: - has-flag "^3.0.0" + has-flag "^4.0.0" -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -term-size@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" - integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk= - dependencies: - execa "^0.7.0" + has-flag "^4.0.0" text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: - os-tmpdir "~1.0.2" + is-number "^7.0.0" -tslib@^1.9.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" - integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== dependencies: - prelude-ls "~1.1.2" + prelude-ls "^1.2.1" type-detect@^4.0.0, type-detect@^4.0.5: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -update-check@1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/update-check/-/update-check-1.5.2.tgz#2fe09f725c543440b3d7dabe8971f2d5caaedc28" - integrity sha512-1TrmYLuLj/5ZovwUS7fFd1jMH3NnFDN1y1A8dboedIDt7zs/zJMo6TwwlhYKkSeEwzleeiSBV5/3c9ufAQWDaQ== +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^2.13.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" + integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== + +update-check@1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/update-check/-/update-check-1.5.4.tgz#5b508e259558f1ad7dbc8b4b0457d4c9d28c8743" + integrity sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ== dependencies: registry-auth-token "3.3.2" registry-url "3.1.0" uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" -v8-compile-cache@^2.0.3: - version "2.1.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" - integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== - vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - -which@1.3.1, which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" -wide-align@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== +widest-line@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-4.0.1.tgz#a0fc673aaba1ea6f0a0d35b3c2795c9a9cc2ebf2" + integrity sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig== dependencies: - string-width "^1.0.2 || 2" + string-width "^5.0.1" -widest-line@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc" - integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA== - dependencies: - string-width "^2.1.1" +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== -wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= +workerpool@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" + integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^8.0.1: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" - integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== - -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - -yargs-parser@13.0.0: - version "13.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b" - integrity sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yargs-parser@^11.1.1: - version "11.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" - integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== -yargs-parser@^13.0.0: - version "13.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" - integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-unparser@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.5.0.tgz#f2bb2a7e83cbc87bb95c8e572828a06c9add6e0d" - integrity sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw== - dependencies: - flat "^4.1.0" - lodash "^4.17.11" - yargs "^12.0.5" - -yargs@13.2.2: - version "13.2.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.2.tgz#0c101f580ae95cea7f39d927e7770e3fdc97f993" - integrity sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA== - dependencies: - cliui "^4.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - os-locale "^3.1.0" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.0.0" - -yargs@^12.0.5: - version "12.0.5" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" - integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== - dependencies: - cliui "^4.0.0" - decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^1.0.1" - os-locale "^3.0.0" +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1 || ^4.0.0" - yargs-parser "^11.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== From 673d8bfcb6b1cd18977da539d8809237f7fb14e1 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Mon, 29 May 2023 14:23:43 -0400 Subject: [PATCH 161/523] Checkout abseil in the smoketest (#5248) Now that shaderc knows about abseil, we want to check it out. Hopefully this fixes the smoketest. --- kokoro/scripts/linux/build-docker.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/kokoro/scripts/linux/build-docker.sh b/kokoro/scripts/linux/build-docker.sh index f2a06e07c9..77430398de 100755 --- a/kokoro/scripts/linux/build-docker.sh +++ b/kokoro/scripts/linux/build-docker.sh @@ -131,6 +131,7 @@ elif [ $TOOL = "cmake-smoketest" ]; then git clone https://github.com/KhronosGroup/SPIRV-Headers.git spirv-headers git clone https://github.com/google/re2 git clone https://github.com/google/effcee + git clone https://github.com/abseil/abseil-cpp abseil_cpp cd $SHADERC_DIR mkdir build From cf62673e4222ca1a3f4271ce71ed1bad6d1d39f7 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Tue, 30 May 2023 09:08:09 -0400 Subject: [PATCH 162/523] Error for invalid location type (#5249) Fixes https://crbug.com/oss-fuzz/56754 * When checking locations, produce an error if the type cannot be assigned a location --- source/val/validate_interfaces.cpp | 13 +++++++------ test/val/val_interfaces_test.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/source/val/validate_interfaces.cpp b/source/val/validate_interfaces.cpp index 48f9e7d875..7699b01428 100644 --- a/source/val/validate_interfaces.cpp +++ b/source/val/validate_interfaces.cpp @@ -174,7 +174,8 @@ spv_result_t NumConsumedLocations(ValidationState_t& _, const Instruction* type, break; } default: - break; + return _.diag(SPV_ERROR_INVALID_DATA, type) + << "Invalid type to assign a location"; } return SPV_SUCCESS; @@ -363,12 +364,12 @@ spv_result_t GetLocationsForVariable( sub_type = _.FindDef(sub_type_id); } - for (uint32_t array_idx = 0; array_idx < array_size; ++array_idx) { - uint32_t num_locations = 0; - if (auto error = NumConsumedLocations(_, sub_type, &num_locations)) - return error; + uint32_t num_locations = 0; + if (auto error = NumConsumedLocations(_, sub_type, &num_locations)) + return error; + uint32_t num_components = NumConsumedComponents(_, sub_type); - uint32_t num_components = NumConsumedComponents(_, sub_type); + for (uint32_t array_idx = 0; array_idx < array_size; ++array_idx) { uint32_t array_location = location + (num_locations * array_idx); uint32_t start = array_location * 4; if (kMaxLocations <= start) { diff --git a/test/val/val_interfaces_test.cpp b/test/val/val_interfaces_test.cpp index 39c6739c3e..09203b35ce 100644 --- a/test/val/val_interfaces_test.cpp +++ b/test/val/val_interfaces_test.cpp @@ -1570,6 +1570,35 @@ OpFunctionEnd "Interface struct has no Block decoration but has BuiltIn members.")); } +TEST_F(ValidateInterfacesTest, InvalidLocationTypePointer) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Vertex %1 "Aiqn0" %2 %3 + OpDecorate %2 Location 0 + %void = OpTypeVoid + %5 = OpTypeFunction %void + %float = OpTypeFloat 32 +%_ptr_Private_void = OpTypePointer Private %void + %uint = OpTypeInt 32 0 +%uint_4278132784 = OpConstant %uint 4278132784 +%_arr__ptr_Private_void_uint_4278132784 = OpTypeArray %_ptr_Private_void %uint_4278132784 +%_ptr_Output__arr__ptr_Private_void_uint_4278132784 = OpTypePointer Output %_arr__ptr_Private_void_uint_4278132784 + %2 = OpVariable %_ptr_Output__arr__ptr_Private_void_uint_4278132784 Output +%_ptr_Output__ptr_Private_void = OpTypePointer Output %_ptr_Private_void + %3 = OpVariable %_ptr_Output__arr__ptr_Private_void_uint_4278132784 Output + %1 = OpFunction %void None %5 + %15 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Invalid type to assign a location")); +} + } // namespace } // namespace val } // namespace spvtools From 8841d560c420839f3f9ad55a0920266abb1575bb Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Tue, 30 May 2023 09:29:04 -0400 Subject: [PATCH 163/523] Add c++ version to .bazelrc (#5247) I finally found out how to add platform specific options to the bazelrc file. I will use that to add the c++ language level to the bazelrc flie. --- .bazelrc | 4 ++++ .github/workflows/bazel.yml | 8 ++++---- README.md | 9 +-------- 3 files changed, 9 insertions(+), 12 deletions(-) create mode 100644 .bazelrc diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 0000000000..ff6db819b6 --- /dev/null +++ b/.bazelrc @@ -0,0 +1,4 @@ +build --enable_platform_specific_config +build:linux --cxxopt=-std=c++17 +build:macos --cxxopt=-std=c++17 +build:windows --cxxopt=/std:c++17 diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 88700c44c2..752b662bec 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -30,13 +30,13 @@ jobs: key: bazel-cache-${{ runner.os }} - name: Build All (Windows) if: ${{matrix.os == 'windows-latest' }} - run: bazel --output_user_root=~/.bazel/cache build --cxxopt=/std:c++17 //... + run: bazel --output_user_root=~/.bazel/cache build //... - name: Test All (Windows) if: ${{matrix.os == 'windows-latest' }} - run: bazel --output_user_root=~/.bazel/cache test --cxxopt=/std:c++17 //... + run: bazel --output_user_root=~/.bazel/cache test //... - name: Build All (Linux, MacOS) if: ${{ matrix.os != 'windows-latest' }} - run: bazel --output_user_root=~/.bazel/cache build --cxxopt=-std=c++17 //... + run: bazel --output_user_root=~/.bazel/cache build //... - name: Test All (Linux, MacOS) if: ${{ matrix.os != 'windows-latest' }} - run: bazel --output_user_root=~/.bazel/cache test --cxxopt=-std=c++17 //... + run: bazel --output_user_root=~/.bazel/cache test //... diff --git a/README.md b/README.md index fc9d6c773f..67793bd55b 100644 --- a/README.md +++ b/README.md @@ -386,15 +386,8 @@ fuzzer tests. ### Build using Bazel You can also use [Bazel](https://bazel.build/) to build the project. -On linux: ```sh -cd -bazel build --cxxopt=-std=c++17 :all -``` - -On windows: -```sh -bazel build --cxxopt=/std:c++17 :all +bazel build :all ``` ### Build a node.js package using Emscripten From 9ed2ac257dbd51a7974b3b9ef19497cb1c14ebe5 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Tue, 30 May 2023 06:30:01 -0700 Subject: [PATCH 164/523] Fix pairing of function parameters. (#5225) - Consider prior type pairings when attempting to pair function parameters by type. - Pair all parameters that have matching types, not just the first. - Update diff tests. Fixes #5218. --- source/diff/diff.cpp | 93 ++++++++++++++++++- ...different_decorations_fragment_autogen.cpp | 44 ++++----- .../different_decorations_vertex_autogen.cpp | 71 +++++++------- ...erent_function_parameter_count_autogen.cpp | 22 ++--- 4 files changed, 149 insertions(+), 81 deletions(-) diff --git a/source/diff/diff.cpp b/source/diff/diff.cpp index c8bb27edca..1cfffa96e4 100644 --- a/source/diff/diff.cpp +++ b/source/diff/diff.cpp @@ -348,6 +348,59 @@ class Differ { std::function match_group); + // Bucket `src_ids` and `dst_ids` by the key ids returned by `get_group`, and + // then call `match_group` on pairs of buckets whose key ids are matched with + // each other. + // + // For example, suppose we want to pair up groups of instructions with the + // same type. Naturally, the source instructions refer to their types by their + // ids in the source, and the destination instructions use destination type + // ids, so simply comparing source and destination type ids as integers, as + // `GroupIdsAndMatch` would do, is meaningless. But if a prior call to + // `MatchTypeIds` has established type matches between the two modules, then + // we can consult those to pair source and destination buckets whose types are + // equivalent. + // + // Suppose our input groups are as follows: + // + // - src_ids: { 1 -> 100, 2 -> 300, 3 -> 100, 4 -> 200 } + // - dst_ids: { 5 -> 10, 6 -> 20, 7 -> 10, 8 -> 300 } + // + // Here, `X -> Y` means that the instruction with SPIR-V id `X` is a member of + // the group, and `Y` is the id of its type. If we use + // `Differ::GroupIdsHelperGetTypeId` for `get_group`, then + // `get_group(X) == Y`. + // + // These instructions are bucketed by type as follows: + // + // - source: [1, 3] -> 100 + // [4] -> 200 + // [2] -> 300 + // + // - destination: [5, 7] -> 10 + // [6] -> 20 + // [8] -> 300 + // + // Now suppose that we have previously matched up src type 100 with dst type + // 10, and src type 200 with dst type 20, but no other types are matched. + // + // Then `match_group` is called twice: + // - Once with ([1,3], [5, 7]), corresponding to 100/10 + // - Once with ([4],[6]), corresponding to 200/20 + // + // The source type 300 isn't matched with anything, so the fact that there's a + // destination type 300 is irrelevant, and thus 2 and 8 are never passed to + // `match_group`. + // + // This function isn't specific to types; it simply buckets by the ids + // returned from `get_group`, and consults existing matches to pair up the + // resulting buckets. + void GroupIdsAndMatchByMappedId( + const IdGroup& src_ids, const IdGroup& dst_ids, + uint32_t (Differ::*get_group)(const IdInstructions&, uint32_t), + std::function + match_group); + // Helper functions that determine if two instructions match bool DoIdsMatch(uint32_t src_id, uint32_t dst_id); bool DoesOperandMatch(const opt::Operand& src_operand, @@ -899,6 +952,37 @@ void Differ::GroupIdsAndMatch( } } +void Differ::GroupIdsAndMatchByMappedId( + const IdGroup& src_ids, const IdGroup& dst_ids, + uint32_t (Differ::*get_group)(const IdInstructions&, uint32_t), + std::function + match_group) { + // Group the ids based on a key (get_group) + std::map src_groups; + std::map dst_groups; + + GroupIds(src_ids, true, &src_groups, get_group); + GroupIds(dst_ids, false, &dst_groups, get_group); + + // Iterate over pairs of groups whose keys map to each other. + for (const auto& iter : src_groups) { + const uint32_t& src_key = iter.first; + const IdGroup& src_group = iter.second; + + if (src_key == 0) { + continue; + } + + if (id_map_.IsSrcMapped(src_key)) { + const uint32_t& dst_key = id_map_.MappedDstId(src_key); + const IdGroup& dst_group = dst_groups[dst_key]; + + // Let the caller match the groups as appropriate. + match_group(src_group, dst_group); + } + } +} + bool Differ::DoIdsMatch(uint32_t src_id, uint32_t dst_id) { assert(dst_id != 0); return id_map_.MappedDstId(src_id) == dst_id; @@ -1583,6 +1667,8 @@ void Differ::BestEffortMatchFunctions(const IdGroup& src_func_ids, id_map_.MapIds(match_result.src_id, match_result.dst_id); + MatchFunctionParamIds(src_funcs_[match_result.src_id], + dst_funcs_[match_result.dst_id]); MatchIdsInFunctionBodies(src_func_insts.at(match_result.src_id), dst_func_insts.at(match_result.dst_id), match_result.src_match, match_result.dst_match, 0); @@ -1617,8 +1703,8 @@ void Differ::MatchFunctionParamIds(const opt::Function* src_func, // Then match the parameters by their type. If there are multiple of them, // match them by their order. - GroupIdsAndMatch( - src_params, dst_params, 0, &Differ::GroupIdsHelperGetTypeId, + GroupIdsAndMatchByMappedId( + src_params, dst_params, &Differ::GroupIdsHelperGetTypeId, [this](const IdGroup& src_group_by_type_id, const IdGroup& dst_group_by_type_id) { const size_t shared_param_count = @@ -1626,7 +1712,8 @@ void Differ::MatchFunctionParamIds(const opt::Function* src_func, for (size_t param_index = 0; param_index < shared_param_count; ++param_index) { - id_map_.MapIds(src_group_by_type_id[0], dst_group_by_type_id[0]); + id_map_.MapIds(src_group_by_type_id[param_index], + dst_group_by_type_id[param_index]); } }); } diff --git a/test/diff/diff_files/different_decorations_fragment_autogen.cpp b/test/diff/diff_files/different_decorations_fragment_autogen.cpp index 0d34654f84..ec9074c640 100644 --- a/test/diff/diff_files/different_decorations_fragment_autogen.cpp +++ b/test/diff/diff_files/different_decorations_fragment_autogen.cpp @@ -977,7 +977,7 @@ OpFunctionEnd ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 -; Bound: 82 -+; Bound: 92 ++; Bound: 89 ; Schema: 0 OpCapability Shader OpMemoryModel Logical GLSL450 @@ -1030,8 +1030,7 @@ OpFunctionEnd +OpDecorate %83 DescriptorSet 0 +OpDecorate %83 Binding 0 OpDecorate %32 RelaxedPrecision --OpDecorate %33 RelaxedPrecision -+OpDecorate %84 RelaxedPrecision + OpDecorate %33 RelaxedPrecision OpDecorate %36 RelaxedPrecision OpDecorate %37 RelaxedPrecision OpDecorate %38 RelaxedPrecision @@ -1040,10 +1039,8 @@ OpFunctionEnd OpDecorate %42 RelaxedPrecision OpDecorate %43 RelaxedPrecision OpDecorate %48 RelaxedPrecision --OpDecorate %49 RelaxedPrecision --OpDecorate %50 RelaxedPrecision -+OpDecorate %85 RelaxedPrecision -+OpDecorate %86 RelaxedPrecision + OpDecorate %49 RelaxedPrecision + OpDecorate %50 RelaxedPrecision OpDecorate %52 RelaxedPrecision OpDecorate %53 RelaxedPrecision OpDecorate %54 RelaxedPrecision @@ -1082,13 +1079,13 @@ OpFunctionEnd %61 = OpTypeVoid %69 = OpConstant %16 0 %78 = OpConstant %16 1 -+%88 = OpTypePointer Private %2 ++%85 = OpTypePointer Private %2 %3 = OpTypePointer Input %2 %7 = OpTypePointer UniformConstant %6 %10 = OpTypePointer UniformConstant %9 %13 = OpTypePointer Uniform %12 %19 = OpTypePointer Uniform %18 -+%89 = OpTypePointer Private %2 ++%86 = OpTypePointer Private %2 %21 = OpTypePointer Output %2 %28 = OpTypePointer Uniform %27 %30 = OpTypePointer Function %2 @@ -1106,19 +1103,16 @@ OpFunctionEnd %22 = OpVariable %21 Output -%29 = OpVariable %28 Uniform +%83 = OpVariable %28 Uniform -+%90 = OpConstant %23 0 -+%91 = OpConstant %1 0.5 ++%87 = OpConstant %23 0 ++%88 = OpConstant %1 0.5 %32 = OpFunction %2 None %31 --%33 = OpFunctionParameter %30 -+%84 = OpFunctionParameter %30 + %33 = OpFunctionParameter %30 %34 = OpLabel %36 = OpLoad %6 %8 --%37 = OpLoad %2 %33 -+%37 = OpLoad %2 %84 + %37 = OpLoad %2 %33 %38 = OpVectorShuffle %35 %37 %37 0 1 %39 = OpImageSampleImplicitLod %2 %36 %38 --%41 = OpLoad %2 %33 -+%41 = OpLoad %2 %84 + %41 = OpLoad %2 %33 %42 = OpVectorShuffle %35 %41 %41 2 3 %43 = OpConvertFToS %40 %42 %44 = OpLoad %9 %11 @@ -1127,16 +1121,12 @@ OpFunctionEnd OpReturnValue %46 OpFunctionEnd %48 = OpFunction %2 None %47 --%49 = OpFunctionParameter %30 --%50 = OpFunctionParameter %30 -+%85 = OpFunctionParameter %30 -+%86 = OpFunctionParameter %30 + %49 = OpFunctionParameter %30 + %50 = OpFunctionParameter %30 %51 = OpLabel --%52 = OpLoad %2 %49 -+%52 = OpLoad %2 %85 + %52 = OpLoad %2 %49 %53 = OpVectorShuffle %35 %52 %52 0 1 --%54 = OpLoad %2 %50 -+%54 = OpLoad %2 %86 + %54 = OpLoad %2 %50 %55 = OpVectorShuffle %35 %54 %54 2 3 %56 = OpCompositeExtract %1 %53 0 %57 = OpCompositeExtract %1 %53 1 @@ -1154,9 +1144,9 @@ OpFunctionEnd OpStore %65 %66 %67 = OpFunctionCall %2 %32 %65 -%71 = OpAccessChain %70 %14 %69 -+%87 = OpAccessChain %70 %82 %69 ++%84 = OpAccessChain %70 %82 %69 -%72 = OpLoad %2 %71 -+%72 = OpLoad %2 %87 ++%72 = OpLoad %2 %84 OpStore %68 %72 -%74 = OpAccessChain %70 %20 %69 %69 +%74 = OpAccessChain %70 %14 %69 %69 diff --git a/test/diff/diff_files/different_decorations_vertex_autogen.cpp b/test/diff/diff_files/different_decorations_vertex_autogen.cpp index f65ee5a198..134ebb4a54 100644 --- a/test/diff/diff_files/different_decorations_vertex_autogen.cpp +++ b/test/diff/diff_files/different_decorations_vertex_autogen.cpp @@ -777,7 +777,7 @@ OpFunctionEnd ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 -; Bound: 58 -+; Bound: 79 ++; Bound: 77 ; Schema: 0 OpCapability Shader OpMemoryModel Logical GLSL450 @@ -817,12 +817,10 @@ OpFunctionEnd -OpMemberDecorate %23 3 BuiltIn CullDistance OpDecorate %23 Block OpDecorate %28 RelaxedPrecision --OpDecorate %29 RelaxedPrecision -+OpDecorate %59 RelaxedPrecision + OpDecorate %29 RelaxedPrecision OpDecorate %31 RelaxedPrecision OpDecorate %32 RelaxedPrecision --OpDecorate %33 RelaxedPrecision -+OpDecorate %60 RelaxedPrecision + OpDecorate %33 RelaxedPrecision OpDecorate %35 RelaxedPrecision OpDecorate %36 RelaxedPrecision OpDecorate %37 RelaxedPrecision @@ -845,9 +843,9 @@ OpFunctionEnd +%23 = OpTypeStruct %2 %38 = OpTypeVoid %45 = OpConstant %12 0 -+%65 = OpTypePointer Private %2 ++%63 = OpTypePointer Private %2 %3 = OpTypePointer Input %2 -+%66 = OpTypePointer Private %2 ++%64 = OpTypePointer Private %2 %7 = OpTypePointer Output %2 %10 = OpTypePointer Uniform %9 %18 = OpTypePointer Uniform %17 @@ -865,26 +863,21 @@ OpFunctionEnd -%19 = OpVariable %18 Uniform +%19 = OpVariable %10 Uniform %20 = OpVariable %7 Output -+%58 = OpVariable %66 Private ++%58 = OpVariable %64 Private %25 = OpVariable %24 Output -+%67 = OpConstant %13 0 -+%68 = OpConstant %1 0.5 ++%65 = OpConstant %13 0 ++%66 = OpConstant %1 0.5 %28 = OpFunction %2 None %27 --%29 = OpFunctionParameter %26 -+%59 = OpFunctionParameter %26 + %29 = OpFunctionParameter %26 %30 = OpLabel --%31 = OpLoad %2 %29 -+%31 = OpLoad %2 %59 + %31 = OpLoad %2 %29 OpReturnValue %31 OpFunctionEnd %32 = OpFunction %2 None %27 --%33 = OpFunctionParameter %26 -+%60 = OpFunctionParameter %26 + %33 = OpFunctionParameter %26 %34 = OpLabel --%35 = OpLoad %2 %33 -+%35 = OpLoad %2 %60 --%36 = OpLoad %2 %33 -+%36 = OpLoad %2 %60 + %35 = OpLoad %2 %33 + %36 = OpLoad %2 %33 %37 = OpFAdd %2 %35 %36 OpReturnValue %37 OpFunctionEnd @@ -894,41 +887,41 @@ OpFunctionEnd %50 = OpVariable %26 Function %53 = OpVariable %26 Function -%43 = OpLoad %2 %4 -+%61 = OpLoad %2 %5 ++%59 = OpLoad %2 %5 -OpStore %42 %43 -+OpStore %42 %61 ++OpStore %42 %59 %44 = OpFunctionCall %2 %28 %42 -%47 = OpAccessChain %46 %11 %45 -+%62 = OpAccessChain %46 %19 %45 ++%60 = OpAccessChain %46 %19 %45 -%48 = OpLoad %2 %47 -+%48 = OpLoad %2 %62 ++%48 = OpLoad %2 %60 %49 = OpFAdd %2 %44 %48 -OpStore %8 %49 +OpStore %20 %49 -%51 = OpLoad %2 %5 -+%63 = OpLoad %2 %6 ++%61 = OpLoad %2 %6 -OpStore %50 %51 -+OpStore %50 %63 ++OpStore %50 %61 %52 = OpFunctionCall %2 %32 %50 -%54 = OpLoad %2 %6 -+%64 = OpLoad %2 %4 ++%62 = OpLoad %2 %4 -OpStore %53 %54 -+OpStore %53 %64 ++OpStore %53 %62 %55 = OpFunctionCall %2 %28 %53 %56 = OpFAdd %2 %52 %55 %57 = OpAccessChain %7 %25 %45 OpStore %57 %56 -+%69 = OpAccessChain %7 %25 %67 -+%70 = OpLoad %2 %69 -+%71 = OpCompositeExtract %1 %70 0 -+%72 = OpCompositeExtract %1 %70 1 -+%73 = OpCompositeExtract %1 %70 2 -+%74 = OpCompositeExtract %1 %70 3 -+%76 = OpFNegate %1 %71 -+%77 = OpFAdd %1 %73 %74 -+%78 = OpFMul %1 %77 %68 -+%75 = OpCompositeConstruct %2 %72 %76 %78 %74 -+OpStore %69 %75 ++%67 = OpAccessChain %7 %25 %65 ++%68 = OpLoad %2 %67 ++%69 = OpCompositeExtract %1 %68 0 ++%70 = OpCompositeExtract %1 %68 1 ++%71 = OpCompositeExtract %1 %68 2 ++%72 = OpCompositeExtract %1 %68 3 ++%74 = OpFNegate %1 %69 ++%75 = OpFAdd %1 %71 %72 ++%76 = OpFMul %1 %75 %66 ++%73 = OpCompositeConstruct %2 %70 %74 %76 %72 ++OpStore %67 %73 OpReturn OpFunctionEnd )"; diff --git a/test/diff/diff_files/different_function_parameter_count_autogen.cpp b/test/diff/diff_files/different_function_parameter_count_autogen.cpp index 3a077fb0eb..0eaca958a0 100644 --- a/test/diff/diff_files/different_function_parameter_count_autogen.cpp +++ b/test/diff/diff_files/different_function_parameter_count_autogen.cpp @@ -280,7 +280,7 @@ TEST(DiffTest, DifferentFunctionParameterCountNoDebug) { ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 -; Bound: 25 -+; Bound: 34 ++; Bound: 33 ; Schema: 0 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -306,28 +306,26 @@ TEST(DiffTest, DifferentFunctionParameterCountNoDebug) { %4 = OpFunction %2 None %3 %5 = OpLabel %23 = OpVariable %8 Function -+%32 = OpVariable %8 Function ++%31 = OpVariable %8 Function OpStore %23 %22 -%24 = OpFunctionCall %7 %11 %23 -+OpStore %32 %15 -+%33 = OpFunctionCall %7 %11 %23 %32 ++OpStore %31 %15 ++%32 = OpFunctionCall %7 %11 %23 %31 -OpStore %20 %24 -+OpStore %20 %33 ++OpStore %20 %32 OpReturn OpFunctionEnd -%11 = OpFunction %7 None %9 +%11 = OpFunction %7 None %25 --%10 = OpFunctionParameter %8 + %10 = OpFunctionParameter %8 +%26 = OpFunctionParameter %8 -+%27 = OpFunctionParameter %8 %12 = OpLabel --%13 = OpLoad %7 %10 -+%13 = OpLoad %7 %26 + %13 = OpLoad %7 %10 -%16 = OpFAdd %7 %13 %15 -+%28 = OpLoad %7 %27 -+%29 = OpFAdd %7 %13 %28 ++%27 = OpLoad %7 %26 ++%28 = OpFAdd %7 %13 %27 -OpReturnValue %16 -+OpReturnValue %29 ++OpReturnValue %28 OpFunctionEnd )"; Options options; From 226c3bbe6297f93966da4e23021d655cc27ea9c9 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Tue, 30 May 2023 09:42:46 -0400 Subject: [PATCH 165/523] Fix broken link in README (#5250) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 67793bd55b..7cec2af2fa 100644 --- a/README.md +++ b/README.md @@ -796,6 +796,7 @@ limitations under the License. [googletest-issue-610]: https://github.com/google/googletest/issues/610 [effcee]: https://github.com/google/effcee [re2]: https://github.com/google/re2 +[abseil-cpp]: https://github.com/abseil/abseil-cpp [CMake]: https://cmake.org/ [cpp-style-guide]: https://google.github.io/styleguide/cppguide.html [clang-sanitizers]: http://clang.llvm.org/docs/UsersManual.html#controlling-code-generation From 182fd9ebce072b3aa3dc2ebec179489bbbe7ceeb Mon Sep 17 00:00:00 2001 From: alan-baker Date: Tue, 30 May 2023 20:07:58 -0400 Subject: [PATCH 166/523] Allow physical storage buffer pointer in IO (#5251) Follow up to #5249 * glslang tests that physical storage buffer pointers can be used as varyings in shaders * Allow physical storage buffer pointers in IO interfaces as a 64-bit type --- source/val/validate_interfaces.cpp | 18 ++++++++++++++++++ test/val/val_interfaces_test.cpp | 23 +++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/source/val/validate_interfaces.cpp b/source/val/validate_interfaces.cpp index 7699b01428..291b4b82b2 100644 --- a/source/val/validate_interfaces.cpp +++ b/source/val/validate_interfaces.cpp @@ -173,6 +173,16 @@ spv_result_t NumConsumedLocations(ValidationState_t& _, const Instruction* type, } break; } + case spv::Op::OpTypePointer: { + if (_.addressing_model() == + spv::AddressingModel::PhysicalStorageBuffer64 && + type->GetOperandAs(1) == + spv::StorageClass::PhysicalStorageBuffer) { + *num_locations = 1; + break; + } + [[fallthrough]]; + } default: return _.diag(SPV_ERROR_INVALID_DATA, type) << "Invalid type to assign a location"; @@ -207,6 +217,14 @@ uint32_t NumConsumedComponents(ValidationState_t& _, const Instruction* type) { // Skip the array. return NumConsumedComponents(_, _.FindDef(type->GetOperandAs(1))); + case spv::Op::OpTypePointer: + if (_.addressing_model() == + spv::AddressingModel::PhysicalStorageBuffer64 && + type->GetOperandAs(1) == + spv::StorageClass::PhysicalStorageBuffer) { + return 2; + } + break; default: // This is an error that is validated elsewhere. break; diff --git a/test/val/val_interfaces_test.cpp b/test/val/val_interfaces_test.cpp index 09203b35ce..d75c20cf29 100644 --- a/test/val/val_interfaces_test.cpp +++ b/test/val/val_interfaces_test.cpp @@ -1599,6 +1599,29 @@ TEST_F(ValidateInterfacesTest, InvalidLocationTypePointer) { HasSubstr("Invalid type to assign a location")); } +TEST_F(ValidateInterfacesTest, ValidLocationTypePhysicalStorageBufferPointer) { + const std::string text = R"( +OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint Vertex %main "main" %var +OpDecorate %var Location 0 +OpDecorate %var RestrictPointer +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr = OpTypePointer PhysicalStorageBuffer %int +%ptr2 = OpTypePointer Input %ptr +%var = OpVariable %ptr2 Input +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_VULKAN_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3)); +} + } // namespace } // namespace val } // namespace spvtools From c7e436921a148ebf1ad38720e4f8677366b54792 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 31 May 2023 13:03:53 -0400 Subject: [PATCH 167/523] roll deps (#5243) * Roll external/effcee/ 66edefd2b..77a53ba53 (1 commit) https://github.com/google/effcee/compare/66edefd2bb64...77a53ba53bac $ git log 66edefd2b..77a53ba53 --date=short --no-merges --format='%ad %ae %s' 2023-05-26 dneto Add Abseil dependency, via RE2 Created with: roll-dep external/effcee * Roll external/re2/ c9cba7606..03da4fc08 (18 commits) https://github.com/google/re2/compare/c9cba76063cf...03da4fc0857c $ git log c9cba7606..03da4fc08 --date=short --no-merges --format='%ad %ae %s' 2023-05-26 junyer Use `--enable_platform_specific_config` in `.bazelrc`. 2023-05-24 junyer Call `find_package()` conditionally. 2023-05-19 junyer Install CMake in the `gcc:13` container. 2023-05-19 junyer Sigh. I forgot to omit `sudo` because running under Docker. 2023-05-19 junyer Fix the CMake build on Ubuntu. 2023-05-19 junyer Try building the testing for RE2 with CMake again. 2023-05-18 junyer Uhh. Fix `LDABSL` for sure this time. 2023-05-18 junyer Try one more time to fix the GNU make build with GCC on Ubuntu. 2023-05-18 junyer For now, stop building the testing for RE2 with CMake. 2023-05-18 junyer Revert "Try `x64-windows-static` for CMake on Windows." 2023-05-18 junyer Try `x64-windows-static` for CMake on Windows. 2023-05-18 junyer Try again to fix the CI workflows. 2023-05-17 junyer Try to fix the CMake CI workflow. 2023-05-17 junyer Try to fix the GNU make CI workflow. 2023-05-17 junyer Fix the GNU make and CMake configurations and CI workflows. 2023-05-17 junyer Copy over the `re2/` and `util/` subdirectories. 2023-05-15 junyer Copy over the Bazel configuration and the workflow for Python releases. 2023-05-15 junyer Copy over the `app/` and `python/` subdirectories. Created with: roll-dep external/re2 * Update WORKSPACE to work with the new RE2. * Do not build tests with VS2017 RE2 no longer supports VS2017, so we cannot build the tests anymore. We will continue to make sure the everything else still builds with vs2017. --------- Co-authored-by: GitHub Actions[bot] <> Co-authored-by: Steven Perron --- DEPS | 4 ++-- WORKSPACE | 13 +++++++++++++ kokoro/scripts/windows/build.bat | 17 +++++++++++++---- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/DEPS b/DEPS index 788017ac88..606eb60e58 100644 --- a/DEPS +++ b/DEPS @@ -5,14 +5,14 @@ vars = { 'abseil_revision': '79ca5d7aad63973c83a4962a66ab07cd623131ea', - 'effcee_revision': '66edefd2bb641de8a2f46b476de21f227fc03a28', + 'effcee_revision': 'ef0a5c1528fe9850b65c6b8e6a3ab9039b92b685', 'googletest_revision': '45804691223635953f311cf31a10c632553bbfc3', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': 'c9cba76063cf4235c1a15dd14a24a4ef8d623761', + 're2_revision': '03da4fc0857c285e3a26782f6bc8931c4c950df4', 'spirv_headers_revision': '69155b22b3b1f2d0cfed48f59167d9792de1fd79', } diff --git a/WORKSPACE b/WORKSPACE index 5abfc98bcc..589dc12202 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,3 +1,11 @@ +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "bazel_skylib", + strip_prefix = "bazel-skylib-main", + urls = ["https://github.com/bazelbuild/bazel-skylib/archive/main.zip"], +) + local_repository( name = "spirv_headers", path = "external/spirv-headers", @@ -17,3 +25,8 @@ local_repository( name = "com_google_effcee", path = "external/effcee", ) + +local_repository( + name = "com_google_absl", + path = "external/abseil_cpp", +) diff --git a/kokoro/scripts/windows/build.bat b/kokoro/scripts/windows/build.bat index bb14da3dc9..fe15f2d791 100644 --- a/kokoro/scripts/windows/build.bat +++ b/kokoro/scripts/windows/build.bat @@ -30,6 +30,9 @@ set PATH=C:\python36;"C:\Program Files\cmake-3.23.1-windows-x86_64\bin";%PATH% if %VS_VERSION% == 2017 ( call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 echo "Using VS 2017..." + + :: RE2 does not support VS2017, we we must disable tests. + set BUILD_TESTS=NO ) else if %VS_VERSION% == 2019 ( call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 echo "Using VS 2019..." @@ -56,6 +59,10 @@ set CMAKE_FLAGS=-DCMAKE_INSTALL_PREFIX=%KOKORO_ARTIFACTS_DIR%\install -GNinja -D :: Build spirv-fuzz set CMAKE_FLAGS=%CMAKE_FLAGS% -DSPIRV_BUILD_FUZZER=ON +if "%BUILD_TESTS%" == "NO" ( + set CMAKE_FLAGS=-DSPIRV_SKIP_TESTS=ON %CMAKE_FLAGS% +) + cmake %CMAKE_FLAGS% .. if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% @@ -71,10 +78,12 @@ setlocal ENABLEDELAYEDEXPANSION :: ################################################ :: Run the tests :: ################################################ -echo "Running Tests... %DATE% %TIME%" -ctest -C %BUILD_TYPE% --output-on-failure --timeout 300 -if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL! -echo "Tests Completed %DATE% %TIME%" +if "%BUILD_TESTS%" NEQ "NO" ( + echo "Running Tests... %DATE% %TIME%" + ctest -C %BUILD_TYPE% --output-on-failure --timeout 300 + if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL! + echo "Tests Completed %DATE% %TIME%" +) :: ################################################ :: Install and package. From ec244c85987094b4b89fbd322992a6c1a84053b6 Mon Sep 17 00:00:00 2001 From: David Neto Date: Wed, 31 May 2023 16:55:43 -0400 Subject: [PATCH 168/523] Increase tested Android API level (#5253) Vulkan was introduced in Android API 24. Test that. The Android NDK drops support for very old APIs. --- android_test/jni/Application.mk | 2 +- kokoro/scripts/linux/build-docker.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/android_test/jni/Application.mk b/android_test/jni/Application.mk index 4e66465931..47c0acfbce 100644 --- a/android_test/jni/Application.mk +++ b/android_test/jni/Application.mk @@ -1,5 +1,5 @@ APP_ABI := all APP_BUILD_SCRIPT := Android.mk APP_STL := c++_static -APP_PLATFORM := android-9 +APP_PLATFORM := android-24 NDK_TOOLCHAIN_VERSION := 4.9 diff --git a/kokoro/scripts/linux/build-docker.sh b/kokoro/scripts/linux/build-docker.sh index 77430398de..4f24c2d192 100755 --- a/kokoro/scripts/linux/build-docker.sh +++ b/kokoro/scripts/linux/build-docker.sh @@ -164,7 +164,7 @@ elif [ $TOOL = "cmake-android-ndk" ]; then echo $(date): Starting build... cmake -DCMAKE_BUILD_TYPE=Release \ - -DANDROID_NATIVE_API_LEVEL=android-16 \ + -DANDROID_NATIVE_API_LEVEL=android-24 \ -DANDROID_ABI="armeabi-v7a with NEON" \ -DSPIRV_SKIP_TESTS=ON \ -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake" \ From 5ed21eb1e2f4b11dea5c840fc6c2fe805ed751f1 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 1 Jun 2023 09:09:08 -0700 Subject: [PATCH 169/523] Add folding rule for OpTranspose (#5241) --- source/opt/const_folding_rules.cpp | 64 +++++++++++++++++++++++ test/opt/fold_test.cpp | 81 ++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) diff --git a/source/opt/const_folding_rules.cpp b/source/opt/const_folding_rules.cpp index e3414de3b6..b1a87a5570 100644 --- a/source/opt/const_folding_rules.cpp +++ b/source/opt/const_folding_rules.cpp @@ -341,6 +341,69 @@ ConstantFoldingRule FoldVectorTimesScalar() { }; } +// Returns to the constant that results from tranposing |matrix|. The result +// will have type |result_type|, and |matrix| must exist in |context|. The +// result constant will also exist in |context|. +const analysis::Constant* TransposeMatrix(const analysis::Constant* matrix, + analysis::Matrix* result_type, + IRContext* context) { + analysis::ConstantManager* const_mgr = context->get_constant_mgr(); + if (matrix->AsNullConstant() != nullptr) { + return const_mgr->GetNullCompositeConstant(result_type); + } + + const auto& columns = matrix->AsMatrixConstant()->GetComponents(); + uint32_t number_of_rows = columns[0]->type()->AsVector()->element_count(); + + // Collect the ids of the elements in their new positions. + std::vector> result_elements(number_of_rows); + for (const analysis::Constant* column : columns) { + if (column->AsNullConstant()) { + column = const_mgr->GetNullCompositeConstant(column->type()); + } + const auto& column_components = column->AsVectorConstant()->GetComponents(); + + for (uint32_t row = 0; row < number_of_rows; ++row) { + result_elements[row].push_back( + const_mgr->GetDefiningInstruction(column_components[row]) + ->result_id()); + } + } + + // Create the constant for each row in the result, and collect the ids. + std::vector result_columns(number_of_rows); + for (uint32_t col = 0; col < number_of_rows; ++col) { + auto* element = const_mgr->GetConstant(result_type->element_type(), + result_elements[col]); + result_columns[col] = + const_mgr->GetDefiningInstruction(element)->result_id(); + } + + // Create the matrix constant from the row ids, and return it. + return const_mgr->GetConstant(result_type, result_columns); +} + +const analysis::Constant* FoldTranspose( + IRContext* context, Instruction* inst, + const std::vector& constants) { + assert(inst->opcode() == spv::Op::OpTranspose); + + analysis::TypeManager* type_mgr = context->get_type_mgr(); + if (!inst->IsFloatingPointFoldingAllowed()) { + if (HasFloatingPoint(type_mgr->GetType(inst->type_id()))) { + return nullptr; + } + } + + const analysis::Constant* matrix = constants[0]; + if (matrix == nullptr) { + return nullptr; + } + + auto* result_type = type_mgr->GetType(inst->type_id()); + return TransposeMatrix(matrix, result_type->AsMatrix(), context); +} + ConstantFoldingRule FoldVectorTimesMatrix() { return [](IRContext* context, Instruction* inst, const std::vector& constants) @@ -1566,6 +1629,7 @@ void ConstantFoldingRules::AddFoldingRules() { rules_[spv::Op::OpVectorTimesScalar].push_back(FoldVectorTimesScalar()); rules_[spv::Op::OpVectorTimesMatrix].push_back(FoldVectorTimesMatrix()); rules_[spv::Op::OpMatrixTimesVector].push_back(FoldMatrixTimesVector()); + rules_[spv::Op::OpTranspose].push_back(FoldTranspose); rules_[spv::Op::OpFNegate].push_back(FoldFNegate()); rules_[spv::Op::OpQuantizeToF16].push_back(FoldQuantizeToF16()); diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index d6e7ce26e0..079c45c131 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -156,6 +156,8 @@ OpName %main "main" %v2half = OpTypeVector %half 2 %v2bool = OpTypeVector %bool 2 %m2x2int = OpTypeMatrix %v2int 2 +%mat4v2float = OpTypeMatrix %v2float 4 +%mat2v4float = OpTypeMatrix %v4float 2 %mat4v4float = OpTypeMatrix %v4float 4 %mat4v4double = OpTypeMatrix %v4double 4 %struct_v2int_int_int = OpTypeStruct %v2int %int %int @@ -290,6 +292,7 @@ OpName %main "main" %v4float_1_1_1_1 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 %v4float_1_2_3_4 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4 %v4float_null = OpConstantNull %v4float +%mat2v4float_null = OpConstantNull %mat2v4float %mat4v4float_null = OpConstantNull %mat4v4float %mat4v4float_1_2_3_4 = OpConstantComposite %mat4v4float %v4float_1_2_3_4 %v4float_1_2_3_4 %v4float_1_2_3_4 %v4float_1_2_3_4 %mat4v4float_1_2_3_4_null = OpConstantComposite %mat4v4float %v4float_1_2_3_4 %v4float_null %v4float_1_2_3_4 %v4float_null @@ -1239,6 +1242,84 @@ ::testing::Values( 2, {4.0,8.0,12.0,16.0}) )); // clang-format on + +using FloatMatrixInstructionFoldingTest = ::testing::TestWithParam< + InstructionFoldingCase>>>; + +TEST_P(FloatMatrixInstructionFoldingTest, Case) { + const auto& tc = GetParam(); + + // Build module. + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(nullptr, context); + + // Fold the instruction to test. + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); + bool succeeded = context->get_instruction_folder().FoldInstruction(inst); + + // Make sure the instruction folded as expected. + EXPECT_TRUE(succeeded); + EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); + + if (inst->opcode() == spv::Op::OpCopyObject) { + inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); + analysis::ConstantManager* const_mgr = context->get_constant_mgr(); + const analysis::Constant* result = const_mgr->GetConstantFromInst(inst); + EXPECT_NE(result, nullptr); + if (result != nullptr) { + std::vector matrix = + result->AsMatrixConstant()->GetComponents(); + EXPECT_EQ(matrix.size(), tc.expected_result.size()); + for (size_t c = 0; c < matrix.size(); c++) { + if (matrix[c]->AsNullConstant() != nullptr) { + matrix[c] = const_mgr->GetNullCompositeConstant(matrix[c]->type()); + } + const analysis::VectorConstant* column_const = + matrix[c]->AsVectorConstant(); + ASSERT_NE(column_const, nullptr); + const std::vector& column = + column_const->GetComponents(); + EXPECT_EQ(column.size(), tc.expected_result[c].size()); + for (size_t r = 0; r < column.size(); r++) { + EXPECT_EQ(tc.expected_result[c][r], column[r]->GetFloat()); + } + } + } + } +} + +// clang-format off +INSTANTIATE_TEST_SUITE_P(TestCase, FloatMatrixInstructionFoldingTest, +::testing::Values( + // Test case 0: OpTranspose square null matrix + InstructionFoldingCase>>( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpTranspose %mat4v4float %mat4v4float_null\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {{0.0f, 0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f, 0.0f},{0.0f, 0.0f, 0.0f, 0.0f}}), + // Test case 1: OpTranspose rectangular null matrix + InstructionFoldingCase>>( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpTranspose %mat4v2float %mat2v4float_null\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {{0.0f, 0.0f},{0.0f, 0.0f},{0.0f, 0.0f},{0.0f, 0.0f}}), + InstructionFoldingCase>>( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpTranspose %mat4v4float %mat4v4float_1_2_3_4\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {{1.0f, 1.0f, 1.0f, 1.0f},{2.0f, 2.0f, 2.0f, 2.0f},{3.0f, 3.0f, 3.0f, 3.0f},{4.0f, 4.0f, 4.0f, 4.0f}}) +)); +// clang-format on + using BooleanInstructionFoldingTest = ::testing::TestWithParam>; From 59b4febd819977b440692674f6a862d6d17731b5 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Tue, 6 Jun 2023 18:05:04 -0400 Subject: [PATCH 170/523] Allow OpTypeBool in UniformConstant (#5237) See https://github.com/KhronosGroup/SPIRV-Registry/issues/72 * OpenGL allowed uniforms to be declared with boolean types, but the validator was overly strict in disallowing it --- source/val/validate_memory.cpp | 5 +++-- test/val/val_id_test.cpp | 21 ++++++++++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index 5f7358c686..975a55cc1b 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -442,6 +442,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { storage_class != spv::StorageClass::CrossWorkgroup && storage_class != spv::StorageClass::Private && storage_class != spv::StorageClass::Function && + storage_class != spv::StorageClass::UniformConstant && storage_class != spv::StorageClass::RayPayloadKHR && storage_class != spv::StorageClass::IncomingRayPayloadKHR && storage_class != spv::StorageClass::HitAttributeKHR && @@ -475,8 +476,8 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { "can only be used with non-externally visible shader Storage " "Classes: Workgroup, CrossWorkgroup, Private, Function, " "Input, Output, RayPayloadKHR, IncomingRayPayloadKHR, " - "HitAttributeKHR, CallableDataKHR, or " - "IncomingCallableDataKHR"; + "HitAttributeKHR, CallableDataKHR, " + "IncomingCallableDataKHR, or UniformConstant"; } } } diff --git a/test/val/val_id_test.cpp b/test/val/val_id_test.cpp index 3666f38b0d..7acac563ed 100644 --- a/test/val/val_id_test.cpp +++ b/test/val/val_id_test.cpp @@ -2317,7 +2317,7 @@ OpFunctionEnd "be used with non-externally visible shader Storage Classes: " "Workgroup, CrossWorkgroup, Private, Function, Input, Output, " "RayPayloadKHR, IncomingRayPayloadKHR, HitAttributeKHR, " - "CallableDataKHR, or IncomingCallableDataKHR"))); + "CallableDataKHR, IncomingCallableDataKHR, or UniformConstant"))); } TEST_P(ValidateIdWithMessage, OpVariableContainsBoolPrivateGood) { @@ -2339,6 +2339,25 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_P(ValidateIdWithMessage, OpVariableContainsBoolUniformConstantGood) { + std::string spirv = kGLSL450MemoryModel + R"( +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%block = OpTypeStruct %bool %int +%_ptr_UniformConstant_block = OpTypePointer UniformConstant %block +%var = OpVariable %_ptr_UniformConstant_block UniformConstant +%void = OpTypeVoid +%fnty = OpTypeFunction %void +%main = OpFunction %void None %fnty +%entry = OpLabel +%load = OpLoad %block %var +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + TEST_P(ValidateIdWithMessage, OpVariableContainsBoolPointerGood) { std::string spirv = kGLSL450MemoryModel + R"( %bool = OpTypeBool From 1d7dec3c51dfcecaf10036448e9709ae02f877e5 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 8 Jun 2023 05:50:29 -0700 Subject: [PATCH 171/523] Use windows 2019 to workaround bazel issue (#5261) In the latest windows images, MSVC is not installed in the default directory, and bazel is not able to find it. See https://github.com/actions/runner-images/issues/7675. Because of that, I will change the github action so that is uses windows-2019 instead of latest. At the same time, I merged the build and test commands for the different platforms because they are now the same. --- .github/workflows/bazel.yml | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 752b662bec..5c353718e7 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -13,7 +13,7 @@ jobs: timeout-minutes: 120 strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-latest, macos-latest, windows-2019] runs-on: ${{matrix.os}} @@ -28,15 +28,7 @@ jobs: with: path: ~/.bazel/cache key: bazel-cache-${{ runner.os }} - - name: Build All (Windows) - if: ${{matrix.os == 'windows-latest' }} + - name: Build All run: bazel --output_user_root=~/.bazel/cache build //... - - name: Test All (Windows) - if: ${{matrix.os == 'windows-latest' }} - run: bazel --output_user_root=~/.bazel/cache test //... - - name: Build All (Linux, MacOS) - if: ${{ matrix.os != 'windows-latest' }} - run: bazel --output_user_root=~/.bazel/cache build //... - - name: Test All (Linux, MacOS) - if: ${{ matrix.os != 'windows-latest' }} + - name: Test All run: bazel --output_user_root=~/.bazel/cache test //... From 9da026922578b6113522832a02fab65cb70f2c56 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 8 Jun 2023 09:33:45 -0400 Subject: [PATCH 172/523] roll deps (#5263) * Roll external/effcee/ ef0a5c152..6d3b974a7 (6 commits) https://github.com/google/effcee/compare/ef0a5c1528fe...6d3b974a7779 $ git log ef0a5c152..6d3b974a7 --date=short --no-merges --format='%ad %ae %s' 2023-06-05 dneto On Windows, export all symbols 2023-06-05 dneto Fix cursor_test.cc compilation on MSVC 2023-06-02 dneto Update CHANGES 2023-06-02 dneto Add Kokoro build scripts 2023-05-31 dneto Add DEPS and a script to get them out 2023-05-31 dneto gitignore: ignore abseil and bazel intermediate files Created with: roll-dep external/effcee * Roll external/googletest/ 458046912..334704df2 (8 commits) https://github.com/google/googletest/compare/458046912236...334704df263b $ git log 458046912..334704df2 --date=short --no-merges --format='%ad %ae %s' 2023-06-02 joakim.plate Check for file system for current directory 2023-06-02 pratyush3757 change table to unordered list 2023-06-01 dinor Copy supported platforms from README onto https://google.github.io/googletest/platforms.html 2023-05-31 dinor Provide example for setting C++ language standard in GoogleTest's Bazel quickstart and readme. An equivalent for CMake was merged in https://github.com/google/googletest/commit/aa99ce5a0db4215bb8e2cda3ee68b6b8d4896815 2023-05-31 junyer Update GoogleTest to RE2 release `2023-06-01`. 2023-05-30 pratyush3757 fix README table 2023-05-24 niranjan.nilakantan Disable some warnings for IntelLLVM on Windows. 2023-05-24 niranjan.nilakantan Build googletest with IntelLLVM compilers. Created with: roll-dep external/googletest * Roll external/re2/ 03da4fc08..7c5e396af (4 commits) https://github.com/google/re2/compare/03da4fc0857c...7c5e396af825 $ git log 03da4fc08..7c5e396af --date=short --no-merges --format='%ad %ae %s' 2023-06-01 junyer `target_compile_definitions()` needs a scope keyword. 2023-06-01 junyer Export `PCRE::no_more_args` and the functors. 2023-06-01 junyer Fix a typographical error. 2023-06-01 junyer Set `CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS` again. Created with: roll-dep external/re2 * Roll external/spirv-headers/ 69155b22b..8e2ad2748 (3 commits) https://github.com/KhronosGroup/SPIRV-Headers/compare/69155b22b3b1...8e2ad27488ed $ git log 69155b22b..8e2ad2748 --date=short --no-merges --format='%ad %ae %s' 2023-05-31 heroseh regenerate headers & correct order of TileImage*ReadAccessEXT Capability enum 2023-05-31 heroseh add HERO_C to the source language enumeration 2023-04-13 heroseh Add Hero C Compiler to the vendor list & add C source language to the Source Language enum Created with: roll-dep external/spirv-headers --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/DEPS b/DEPS index 606eb60e58..4252f91749 100644 --- a/DEPS +++ b/DEPS @@ -5,15 +5,15 @@ vars = { 'abseil_revision': '79ca5d7aad63973c83a4962a66ab07cd623131ea', - 'effcee_revision': 'ef0a5c1528fe9850b65c6b8e6a3ab9039b92b685', + 'effcee_revision': '6d3b974a7779506b59d70cc7ecea1e47931c7183', - 'googletest_revision': '45804691223635953f311cf31a10c632553bbfc3', + 'googletest_revision': '334704df263b480a3e9e7441ed3292a5e30a37ec', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '03da4fc0857c285e3a26782f6bc8931c4c950df4', - 'spirv_headers_revision': '69155b22b3b1f2d0cfed48f59167d9792de1fd79', + 're2_revision': '7c5e396af825562ec8321fdbf2f1cf276b26e3ae', + 'spirv_headers_revision': '8e2ad27488ed2f87c068c01a8f5e8979f7086405', } deps = { From 93c13345e176f3f8bdb4b07e59c5e3365b3dbf44 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Thu, 8 Jun 2023 07:42:45 -0700 Subject: [PATCH 173/523] spirv-diff: Properly match SPV_KHR_ray_query types. (#5259) Fixes #5258. --- source/diff/diff.cpp | 4 +- .../diff_files/diff_test_files_autogen.cmake | 1 + .../diff_files/ray_query_types_autogen.cpp | 150 ++++++++++++++++++ .../diff_files/ray_query_types_dst.spvasm | 18 +++ .../diff_files/ray_query_types_src.spvasm | 16 ++ 5 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 test/diff/diff_files/ray_query_types_autogen.cpp create mode 100644 test/diff/diff_files/ray_query_types_dst.spvasm create mode 100644 test/diff/diff_files/ray_query_types_src.spvasm diff --git a/source/diff/diff.cpp b/source/diff/diff.cpp index 1cfffa96e4..9c30900a3c 100644 --- a/source/diff/diff.cpp +++ b/source/diff/diff.cpp @@ -2288,7 +2288,9 @@ void Differ::MatchTypeIds() { case spv::Op::OpTypeVoid: case spv::Op::OpTypeBool: case spv::Op::OpTypeSampler: - // void, bool and sampler are unique, match them. + case spv::Op::OpTypeAccelerationStructureNV: + case spv::Op::OpTypeRayQueryKHR: + // the above types have no operands and are unique, match them. return true; case spv::Op::OpTypeInt: case spv::Op::OpTypeFloat: diff --git a/test/diff/diff_files/diff_test_files_autogen.cmake b/test/diff/diff_files/diff_test_files_autogen.cmake index 6440d0b9ca..51cb62fab0 100644 --- a/test/diff/diff_files/diff_test_files_autogen.cmake +++ b/test/diff/diff_files/diff_test_files_autogen.cmake @@ -36,6 +36,7 @@ list(APPEND DIFF_TEST_FILES "diff_files/large_functions_small_diffs_autogen.cpp" "diff_files/multiple_different_entry_points_autogen.cpp" "diff_files/multiple_same_entry_points_autogen.cpp" +"diff_files/ray_query_types_autogen.cpp" "diff_files/reordered_if_blocks_autogen.cpp" "diff_files/reordered_switch_blocks_autogen.cpp" "diff_files/small_functions_small_diffs_autogen.cpp" diff --git a/test/diff/diff_files/ray_query_types_autogen.cpp b/test/diff/diff_files/ray_query_types_autogen.cpp new file mode 100644 index 0000000000..76546d19ba --- /dev/null +++ b/test/diff/diff_files/ray_query_types_autogen.cpp @@ -0,0 +1,150 @@ +// GENERATED FILE - DO NOT EDIT. +// Generated by generate_tests.py +// +// Copyright (c) 2022 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "../diff_test_utils.h" + +#include "gtest/gtest.h" + +namespace spvtools { +namespace diff { +namespace { + +// Test that OpTypeAccelerationStructureNV and OpTypeRayQueryKHR are +// matched. +constexpr char kSrc[] = R"(OpCapability RayQueryKHR +OpCapability Shader +OpExtension "SPV_KHR_ray_query" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %43 "main" +OpExecutionMode %43 LocalSize 1 1 1 +%2 = OpTypeVoid +%3 = OpTypeAccelerationStructureNV +%13 = OpTypeRayQueryKHR +%44 = OpTypeFunction %2 +%43 = OpFunction %2 None %44 +%42 = OpLabel +OpReturn +OpFunctionEnd)"; +constexpr char kDst[] = R"(; SPIR-V +; Version: 1.4 +; Generator: rspirv +; Bound: 95 +OpCapability RayQueryKHR +OpCapability Shader +OpExtension "SPV_KHR_ray_query" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %43 "main" +OpExecutionMode %43 LocalSize 1 1 1 +%2 = OpTypeVoid +%3 = OpTypeAccelerationStructureNV +%13 = OpTypeRayQueryKHR +%44 = OpTypeFunction %2 +%43 = OpFunction %2 None %44 +%42 = OpLabel +OpReturn +OpFunctionEnd +)"; + +TEST(DiffTest, RayQueryTypes) { + constexpr char kDiff[] = R"( ; SPIR-V + ; Version: 1.6 + ; Generator: Khronos SPIR-V Tools Assembler; 0 +-; Bound: 45 ++; Bound: 83 + ; Schema: 0 + OpCapability RayQueryKHR + OpCapability Shader + OpExtension "SPV_KHR_ray_query" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %43 "main" + OpExecutionMode %43 LocalSize 1 1 1 + %2 = OpTypeVoid + %3 = OpTypeAccelerationStructureKHR + %13 = OpTypeRayQueryKHR + %44 = OpTypeFunction %2 + %43 = OpFunction %2 None %44 + %42 = OpLabel + OpReturn + OpFunctionEnd +)"; + Options options; + DoStringDiffTest(kSrc, kDst, kDiff, options); +} + +TEST(DiffTest, RayQueryTypesNoDebug) { + constexpr char kSrcNoDebug[] = R"(OpCapability RayQueryKHR +OpCapability Shader +OpExtension "SPV_KHR_ray_query" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %43 "main" +OpExecutionMode %43 LocalSize 1 1 1 +%2 = OpTypeVoid +%3 = OpTypeAccelerationStructureNV +%13 = OpTypeRayQueryKHR +%44 = OpTypeFunction %2 +%43 = OpFunction %2 None %44 +%42 = OpLabel +OpReturn +OpFunctionEnd +)"; + constexpr char kDstNoDebug[] = R"(; SPIR-V +; Version: 1.4 +; Generator: rspirv +; Bound: 95 +OpCapability RayQueryKHR +OpCapability Shader +OpExtension "SPV_KHR_ray_query" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %43 "main" +OpExecutionMode %43 LocalSize 1 1 1 +%2 = OpTypeVoid +%3 = OpTypeAccelerationStructureNV +%13 = OpTypeRayQueryKHR +%44 = OpTypeFunction %2 +%43 = OpFunction %2 None %44 +%42 = OpLabel +OpReturn +OpFunctionEnd +)"; + constexpr char kDiff[] = R"( ; SPIR-V + ; Version: 1.6 + ; Generator: Khronos SPIR-V Tools Assembler; 0 +-; Bound: 45 ++; Bound: 83 + ; Schema: 0 + OpCapability RayQueryKHR + OpCapability Shader + OpExtension "SPV_KHR_ray_query" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %43 "main" + OpExecutionMode %43 LocalSize 1 1 1 + %2 = OpTypeVoid + %3 = OpTypeAccelerationStructureKHR + %13 = OpTypeRayQueryKHR + %44 = OpTypeFunction %2 + %43 = OpFunction %2 None %44 + %42 = OpLabel + OpReturn + OpFunctionEnd +)"; + Options options; + DoStringDiffTest(kSrcNoDebug, kDstNoDebug, kDiff, options); +} + +} // namespace +} // namespace diff +} // namespace spvtools diff --git a/test/diff/diff_files/ray_query_types_dst.spvasm b/test/diff/diff_files/ray_query_types_dst.spvasm new file mode 100644 index 0000000000..5f8be53d44 --- /dev/null +++ b/test/diff/diff_files/ray_query_types_dst.spvasm @@ -0,0 +1,18 @@ +; SPIR-V +; Version: 1.4 +; Generator: rspirv +; Bound: 95 +OpCapability RayQueryKHR +OpCapability Shader +OpExtension "SPV_KHR_ray_query" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %43 "main" +OpExecutionMode %43 LocalSize 1 1 1 +%2 = OpTypeVoid +%3 = OpTypeAccelerationStructureNV +%13 = OpTypeRayQueryKHR +%44 = OpTypeFunction %2 +%43 = OpFunction %2 None %44 +%42 = OpLabel +OpReturn +OpFunctionEnd diff --git a/test/diff/diff_files/ray_query_types_src.spvasm b/test/diff/diff_files/ray_query_types_src.spvasm new file mode 100644 index 0000000000..0b64015b56 --- /dev/null +++ b/test/diff/diff_files/ray_query_types_src.spvasm @@ -0,0 +1,16 @@ +;; Test that OpTypeAccelerationStructureNV and OpTypeRayQueryKHR are +;; matched. +OpCapability RayQueryKHR +OpCapability Shader +OpExtension "SPV_KHR_ray_query" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %43 "main" +OpExecutionMode %43 LocalSize 1 1 1 +%2 = OpTypeVoid +%3 = OpTypeAccelerationStructureNV +%13 = OpTypeRayQueryKHR +%44 = OpTypeFunction %2 +%43 = OpFunction %2 None %44 +%42 = OpLabel +OpReturn +OpFunctionEnd From ae1843b67c54d5f813779e17613cb8750da953f5 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Fri, 9 Jun 2023 12:00:46 -0700 Subject: [PATCH 174/523] spirv-diff: Leave undefined ids unpaired. (#5262) If an id in one module is not defined by any instruction, don't bother matching it with an id in the other module, as this disturbs the reported id bound, resulting in spurious differences. Fixes #5260. --- source/diff/diff.cpp | 57 ++++++++-------- .../OpExtInst_in_src_only_autogen.cpp | 6 +- test/diff/diff_files/basic_autogen.cpp | 10 +-- .../constant_array_size_autogen.cpp | 4 +- ...erent_function_parameter_count_autogen.cpp | 22 +++--- .../diff_files/extra_if_block_autogen.cpp | 68 +++++++++---------- .../int_vs_uint_constants_autogen.cpp | 6 +- .../reordered_if_blocks_autogen.cpp | 6 +- .../reordered_switch_blocks_autogen.cpp | 6 +- .../spec_constant_array_size_autogen.cpp | 20 +++--- 10 files changed, 101 insertions(+), 104 deletions(-) diff --git a/source/diff/diff.cpp b/source/diff/diff.cpp index 9c30900a3c..d5cda462cb 100644 --- a/source/diff/diff.cpp +++ b/source/diff/diff.cpp @@ -108,10 +108,6 @@ class IdMap { return inst_map_.find(from_inst) != inst_map_.end(); } - // Map any ids in src and dst that have not been mapped to new ids in dst and - // src respectively. - void MapUnmatchedIds(IdMap& other_way); - // Some instructions don't have result ids. Those are mapped by pointer. void MapInsts(const opt::Instruction* from_inst, const opt::Instruction* to_inst) { @@ -124,6 +120,12 @@ class IdMap { uint32_t IdBound() const { return static_cast(id_map_.size()); } + // Generate a fresh id in this mapping's domain. + uint32_t MakeFreshId() { + id_map_.push_back(0); + return static_cast(id_map_.size()) - 1; + } + private: // Given an id, returns the corresponding id in the other module, or 0 if not // matched yet. @@ -162,8 +164,11 @@ class SrcDstIdMap { } // Map any ids in src and dst that have not been mapped to new ids in dst and - // src respectively. - void MapUnmatchedIds(); + // src respectively. Use src_insn_defined and dst_insn_defined to ignore ids + // that are simply never defined. (Since we assume the inputs are valid + // SPIR-V, this implies they are also never used.) + void MapUnmatchedIds(std::function src_insn_defined, + std::function dst_insn_defined); // Some instructions don't have result ids. Those are mapped by pointer. void MapInsts(const opt::Instruction* src_inst, @@ -213,6 +218,11 @@ struct IdInstructions { void MapIdToInstruction(uint32_t id, const opt::Instruction* inst); + // Return true if id is mapped to any instruction, false otherwise. + bool IsDefined(uint32_t id) { + return id < inst_map_.size() && inst_map_[id] != nullptr; + } + void MapIdsToInstruction( opt::IteratorRange section); void MapIdsToInfos( @@ -567,36 +577,27 @@ class Differ { FunctionMap dst_funcs_; }; -void IdMap::MapUnmatchedIds(IdMap& other_way) { - const uint32_t src_id_bound = static_cast(id_map_.size()); - const uint32_t dst_id_bound = static_cast(other_way.id_map_.size()); - - uint32_t next_src_id = src_id_bound; - uint32_t next_dst_id = dst_id_bound; +void SrcDstIdMap::MapUnmatchedIds( + std::function src_insn_defined, + std::function dst_insn_defined) { + const uint32_t src_id_bound = static_cast(src_to_dst_.IdBound()); + const uint32_t dst_id_bound = static_cast(dst_to_src_.IdBound()); for (uint32_t src_id = 1; src_id < src_id_bound; ++src_id) { - if (!IsMapped(src_id)) { - MapIds(src_id, next_dst_id); - - other_way.id_map_.push_back(0); - other_way.MapIds(next_dst_id++, src_id); + if (!src_to_dst_.IsMapped(src_id) && src_insn_defined(src_id)) { + uint32_t fresh_dst_id = dst_to_src_.MakeFreshId(); + MapIds(src_id, fresh_dst_id); } } for (uint32_t dst_id = 1; dst_id < dst_id_bound; ++dst_id) { - if (!other_way.IsMapped(dst_id)) { - id_map_.push_back(0); - MapIds(next_src_id, dst_id); - - other_way.MapIds(dst_id, next_src_id++); + if (!dst_to_src_.IsMapped(dst_id) && dst_insn_defined(dst_id)) { + uint32_t fresh_src_id = src_to_dst_.MakeFreshId(); + MapIds(fresh_src_id, dst_id); } } } -void SrcDstIdMap::MapUnmatchedIds() { - src_to_dst_.MapUnmatchedIds(dst_to_src_); -} - void IdInstructions::MapIdToInstruction(uint32_t id, const opt::Instruction* inst) { assert(id != 0); @@ -2735,7 +2736,9 @@ opt::Instruction Differ::ToMappedSrcIds(const opt::Instruction& dst_inst) { } spv_result_t Differ::Output() { - id_map_.MapUnmatchedIds(); + id_map_.MapUnmatchedIds( + [this](uint32_t src_id) { return src_id_to_.IsDefined(src_id); }, + [this](uint32_t dst_id) { return dst_id_to_.IsDefined(dst_id); }); src_id_to_.inst_map_.resize(id_map_.SrcToDstMap().IdBound(), nullptr); dst_id_to_.inst_map_.resize(id_map_.DstToSrcMap().IdBound(), nullptr); diff --git a/test/diff/diff_files/OpExtInst_in_src_only_autogen.cpp b/test/diff/diff_files/OpExtInst_in_src_only_autogen.cpp index 9944c2cf1f..bd5a7d5873 100644 --- a/test/diff/diff_files/OpExtInst_in_src_only_autogen.cpp +++ b/test/diff/diff_files/OpExtInst_in_src_only_autogen.cpp @@ -95,8 +95,7 @@ TEST(DiffTest, OpextinstInSrcOnly) { constexpr char kDiff[] = R"( ; SPIR-V ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 --; Bound: 15 -+; Bound: 16 + ; Bound: 15 ; Schema: 0 OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" @@ -199,8 +198,7 @@ TEST(DiffTest, OpextinstInSrcOnlyNoDebug) { constexpr char kDiff[] = R"( ; SPIR-V ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 --; Bound: 15 -+; Bound: 16 + ; Bound: 15 ; Schema: 0 OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" diff --git a/test/diff/diff_files/basic_autogen.cpp b/test/diff/diff_files/basic_autogen.cpp index f3afc701b3..d4b6846bfe 100644 --- a/test/diff/diff_files/basic_autogen.cpp +++ b/test/diff/diff_files/basic_autogen.cpp @@ -129,7 +129,7 @@ TEST(DiffTest, Basic) { ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 -; Bound: 27 -+; Bound: 36 ++; Bound: 30 ; Schema: 0 OpCapability Shader +%27 = OpExtInstImport "GLSL.std.450" @@ -272,7 +272,7 @@ OpFunctionEnd ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 -; Bound: 27 -+; Bound: 36 ++; Bound: 30 ; Schema: 0 OpCapability Shader +%27 = OpExtInstImport "GLSL.std.450" @@ -324,7 +324,7 @@ TEST(DiffTest, BasicDumpIds) { ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 -; Bound: 27 -+; Bound: 36 ++; Bound: 30 ; Schema: 0 OpCapability Shader +%27 = OpExtInstImport "GLSL.std.450" @@ -384,8 +384,8 @@ TEST(DiffTest, BasicDumpIds) { 6 -> 14 [TypeInt] 13 -> 19 [TypePointer] 14 -> 27 [Variable] - 15 -> 34 [Constant] - 16 -> 35 [TypeArray] + 15 -> 28 [Constant] + 16 -> 29 [TypeArray] 17 -> 11 [TypeStruct] 18 -> 12 [TypePointer] 19 -> 13 [Variable] diff --git a/test/diff/diff_files/constant_array_size_autogen.cpp b/test/diff/diff_files/constant_array_size_autogen.cpp index 16975ff47e..2b6d7d8099 100644 --- a/test/diff/diff_files/constant_array_size_autogen.cpp +++ b/test/diff/diff_files/constant_array_size_autogen.cpp @@ -125,7 +125,7 @@ TEST(DiffTest, ConstantArraySize) { ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 -; Bound: 27 -+; Bound: 34 ++; Bound: 28 ; Schema: 0 OpCapability Shader OpMemoryModel Logical GLSL450 @@ -259,7 +259,7 @@ OpFunctionEnd ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 -; Bound: 27 -+; Bound: 34 ++; Bound: 28 ; Schema: 0 OpCapability Shader OpMemoryModel Logical GLSL450 diff --git a/test/diff/diff_files/different_function_parameter_count_autogen.cpp b/test/diff/diff_files/different_function_parameter_count_autogen.cpp index 0eaca958a0..e31a4a89ec 100644 --- a/test/diff/diff_files/different_function_parameter_count_autogen.cpp +++ b/test/diff/diff_files/different_function_parameter_count_autogen.cpp @@ -128,7 +128,7 @@ TEST(DiffTest, DifferentFunctionParameterCount) { ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 -; Bound: 25 -+; Bound: 33 ++; Bound: 31 ; Schema: 0 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -143,7 +143,7 @@ TEST(DiffTest, DifferentFunctionParameterCount) { +OpName %26 "v2" OpName %20 "o" OpName %23 "param" -+OpName %31 "param" ++OpName %29 "param" OpDecorate %20 RelaxedPrecision OpDecorate %20 Location 0 %2 = OpTypeVoid @@ -162,13 +162,13 @@ TEST(DiffTest, DifferentFunctionParameterCount) { %4 = OpFunction %2 None %3 %5 = OpLabel %23 = OpVariable %8 Function -+%31 = OpVariable %8 Function ++%29 = OpVariable %8 Function OpStore %23 %22 -%24 = OpFunctionCall %7 %11 %23 -+OpStore %31 %15 -+%32 = OpFunctionCall %7 %11 %23 %31 ++OpStore %29 %15 ++%30 = OpFunctionCall %7 %11 %23 %29 -OpStore %20 %24 -+OpStore %20 %32 ++OpStore %20 %30 OpReturn OpFunctionEnd -%11 = OpFunction %7 None %9 @@ -280,7 +280,7 @@ TEST(DiffTest, DifferentFunctionParameterCountNoDebug) { ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 -; Bound: 25 -+; Bound: 33 ++; Bound: 31 ; Schema: 0 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -306,13 +306,13 @@ TEST(DiffTest, DifferentFunctionParameterCountNoDebug) { %4 = OpFunction %2 None %3 %5 = OpLabel %23 = OpVariable %8 Function -+%31 = OpVariable %8 Function ++%29 = OpVariable %8 Function OpStore %23 %22 -%24 = OpFunctionCall %7 %11 %23 -+OpStore %31 %15 -+%32 = OpFunctionCall %7 %11 %23 %31 ++OpStore %29 %15 ++%30 = OpFunctionCall %7 %11 %23 %29 -OpStore %20 %24 -+OpStore %20 %32 ++OpStore %20 %30 OpReturn OpFunctionEnd -%11 = OpFunction %7 None %9 diff --git a/test/diff/diff_files/extra_if_block_autogen.cpp b/test/diff/diff_files/extra_if_block_autogen.cpp index 4f91319871..fee34aea57 100644 --- a/test/diff/diff_files/extra_if_block_autogen.cpp +++ b/test/diff/diff_files/extra_if_block_autogen.cpp @@ -303,7 +303,7 @@ TEST(DiffTest, ExtraIfBlock) { ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 -; Bound: 69 -+; Bound: 81 ++; Bound: 77 ; Schema: 0 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -352,10 +352,10 @@ TEST(DiffTest, ExtraIfBlock) { OpDecorate %54 RelaxedPrecision OpDecorate %55 RelaxedPrecision OpDecorate %56 RelaxedPrecision -+OpDecorate %72 RelaxedPrecision ++OpDecorate %70 RelaxedPrecision OpDecorate %57 RelaxedPrecision -+OpDecorate %77 RelaxedPrecision -+OpDecorate %78 RelaxedPrecision ++OpDecorate %75 RelaxedPrecision ++OpDecorate %76 RelaxedPrecision OpDecorate %58 RelaxedPrecision OpDecorate %63 RelaxedPrecision OpDecorate %63 Location 0 @@ -383,7 +383,7 @@ TEST(DiffTest, ExtraIfBlock) { %32 = OpConstant %19 1 %49 = OpConstant %6 10 %52 = OpConstant %6 0.5 -+%76 = OpConstant %6 0.100000001 ++%74 = OpConstant %6 0.100000001 %53 = OpConstant %6 0.699999988 %61 = OpTypeVector %6 4 %62 = OpTypePointer Output %61 @@ -439,20 +439,20 @@ TEST(DiffTest, ExtraIfBlock) { %55 = OpLoad %6 %45 %56 = OpFMul %6 %55 %54 OpStore %45 %56 -+%71 = OpAccessChain %21 %18 %32 -+%72 = OpLoad %15 %71 -+%73 = OpINotEqual %25 %72 %24 -+OpSelectionMerge %75 None -+OpBranchConditional %73 %74 %75 -+%74 = OpLabel ++%69 = OpAccessChain %21 %18 %32 ++%70 = OpLoad %15 %69 ++%71 = OpINotEqual %25 %70 %24 ++OpSelectionMerge %73 None ++OpBranchConditional %71 %72 %73 ++%72 = OpLabel %57 = OpLoad %6 %45 -+%77 = OpFSub %6 %57 %76 -+OpStore %45 %77 -+OpBranch %75 -+%75 = OpLabel -+%78 = OpLoad %6 %45 ++%75 = OpFSub %6 %57 %74 ++OpStore %45 %75 ++OpBranch %73 ++%73 = OpLabel ++%76 = OpLoad %6 %45 -%58 = OpExtInst %6 %1 Exp %57 -+%58 = OpExtInst %6 %1 Exp %78 ++%58 = OpExtInst %6 %1 Exp %76 OpReturnValue %58 OpFunctionEnd )"; @@ -716,7 +716,7 @@ TEST(DiffTest, ExtraIfBlockNoDebug) { ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 -; Bound: 69 -+; Bound: 81 ++; Bound: 77 ; Schema: 0 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -754,10 +754,10 @@ TEST(DiffTest, ExtraIfBlockNoDebug) { OpDecorate %54 RelaxedPrecision OpDecorate %55 RelaxedPrecision OpDecorate %56 RelaxedPrecision -+OpDecorate %72 RelaxedPrecision ++OpDecorate %70 RelaxedPrecision OpDecorate %57 RelaxedPrecision -+OpDecorate %77 RelaxedPrecision -+OpDecorate %78 RelaxedPrecision ++OpDecorate %75 RelaxedPrecision ++OpDecorate %76 RelaxedPrecision OpDecorate %58 RelaxedPrecision OpDecorate %63 RelaxedPrecision OpDecorate %63 Location 0 @@ -785,7 +785,7 @@ TEST(DiffTest, ExtraIfBlockNoDebug) { %32 = OpConstant %19 1 %49 = OpConstant %6 10 %52 = OpConstant %6 0.5 -+%76 = OpConstant %6 0.100000001 ++%74 = OpConstant %6 0.100000001 %53 = OpConstant %6 0.699999988 %61 = OpTypeVector %6 4 %62 = OpTypePointer Output %61 @@ -841,20 +841,20 @@ TEST(DiffTest, ExtraIfBlockNoDebug) { %55 = OpLoad %6 %45 %56 = OpFMul %6 %55 %54 OpStore %45 %56 -+%71 = OpAccessChain %21 %18 %32 -+%72 = OpLoad %15 %71 -+%73 = OpINotEqual %25 %72 %24 -+OpSelectionMerge %75 None -+OpBranchConditional %73 %74 %75 -+%74 = OpLabel ++%69 = OpAccessChain %21 %18 %32 ++%70 = OpLoad %15 %69 ++%71 = OpINotEqual %25 %70 %24 ++OpSelectionMerge %73 None ++OpBranchConditional %71 %72 %73 ++%72 = OpLabel %57 = OpLoad %6 %45 -+%77 = OpFSub %6 %57 %76 -+OpStore %45 %77 -+OpBranch %75 -+%75 = OpLabel -+%78 = OpLoad %6 %45 ++%75 = OpFSub %6 %57 %74 ++OpStore %45 %75 ++OpBranch %73 ++%73 = OpLabel ++%76 = OpLoad %6 %45 -%58 = OpExtInst %6 %1 Exp %57 -+%58 = OpExtInst %6 %1 Exp %78 ++%58 = OpExtInst %6 %1 Exp %76 OpReturnValue %58 OpFunctionEnd )"; diff --git a/test/diff/diff_files/int_vs_uint_constants_autogen.cpp b/test/diff/diff_files/int_vs_uint_constants_autogen.cpp index 187722e891..11bb811799 100644 --- a/test/diff/diff_files/int_vs_uint_constants_autogen.cpp +++ b/test/diff/diff_files/int_vs_uint_constants_autogen.cpp @@ -371,10 +371,10 @@ TEST(DiffTest, IntVsUintConstantsDumpIds) { 3 -> 16 [TypePointer] 4 -> 17 [Variable] 5 -> 8 [TypeInt] - 8 -> 23 [TypeVector] + 8 -> 21 [TypeVector] 13 -> 19 [TypePointer] - 15 -> 29 [Constant] - 16 -> 30 [TypeArray] + 15 -> 22 [Constant] + 16 -> 23 [TypeArray] 17 -> 11 [TypeStruct] 18 -> 12 [TypePointer] 19 -> 13 [Variable] diff --git a/test/diff/diff_files/reordered_if_blocks_autogen.cpp b/test/diff/diff_files/reordered_if_blocks_autogen.cpp index 0788199f9f..3abaf40de3 100644 --- a/test/diff/diff_files/reordered_if_blocks_autogen.cpp +++ b/test/diff/diff_files/reordered_if_blocks_autogen.cpp @@ -203,8 +203,7 @@ TEST(DiffTest, ReorderedIfBlocks) { constexpr char kDiff[] = R"( ; SPIR-V ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 --; Bound: 46 -+; Bound: 47 + ; Bound: 46 ; Schema: 0 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -471,8 +470,7 @@ TEST(DiffTest, ReorderedIfBlocksNoDebug) { constexpr char kDiff[] = R"( ; SPIR-V ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 --; Bound: 46 -+; Bound: 47 + ; Bound: 46 ; Schema: 0 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" diff --git a/test/diff/diff_files/reordered_switch_blocks_autogen.cpp b/test/diff/diff_files/reordered_switch_blocks_autogen.cpp index c0ba48d1e9..ade5350e79 100644 --- a/test/diff/diff_files/reordered_switch_blocks_autogen.cpp +++ b/test/diff/diff_files/reordered_switch_blocks_autogen.cpp @@ -212,8 +212,7 @@ TEST(DiffTest, ReorderedSwitchBlocks) { constexpr char kDiff[] = R"( ; SPIR-V ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 --; Bound: 58 -+; Bound: 62 + ; Bound: 58 ; Schema: 0 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" @@ -485,8 +484,7 @@ TEST(DiffTest, ReorderedSwitchBlocksNoDebug) { constexpr char kDiff[] = R"( ; SPIR-V ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 --; Bound: 58 -+; Bound: 62 + ; Bound: 58 ; Schema: 0 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" diff --git a/test/diff/diff_files/spec_constant_array_size_autogen.cpp b/test/diff/diff_files/spec_constant_array_size_autogen.cpp index 1962d27e70..98ad072748 100644 --- a/test/diff/diff_files/spec_constant_array_size_autogen.cpp +++ b/test/diff/diff_files/spec_constant_array_size_autogen.cpp @@ -125,7 +125,7 @@ TEST(DiffTest, SpecConstantArraySize) { ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 -; Bound: 27 -+; Bound: 36 ++; Bound: 29 ; Schema: 0 OpCapability Shader OpMemoryModel Logical GLSL450 @@ -140,7 +140,7 @@ TEST(DiffTest, SpecConstantArraySize) { OpName %19 "" OpName %22 "main" OpDecorate %4 Location 0 -+OpDecorate %34 SpecId 4 ++OpDecorate %27 SpecId 4 OpMemberDecorate %17 1 RelaxedPrecision OpMemberDecorate %17 0 BuiltIn Position OpMemberDecorate %17 1 BuiltIn PointSize @@ -153,10 +153,10 @@ TEST(DiffTest, SpecConstantArraySize) { %8 = OpTypeVector %5 4 -%15 = OpConstant %5 8 -%16 = OpTypeArray %1 %15 -+%34 = OpSpecConstant %5 8 -+%35 = OpTypeArray %1 %34 ++%27 = OpSpecConstant %5 8 ++%28 = OpTypeArray %1 %27 -%17 = OpTypeStruct %2 %1 %16 %16 -+%17 = OpTypeStruct %2 %1 %35 %35 ++%17 = OpTypeStruct %2 %1 %28 %28 %20 = OpTypeVoid %25 = OpConstant %5 0 %3 = OpTypePointer Input %2 @@ -261,14 +261,14 @@ OpFunctionEnd ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 -; Bound: 27 -+; Bound: 36 ++; Bound: 29 ; Schema: 0 OpCapability Shader OpMemoryModel Logical GLSL450 OpEntryPoint Vertex %22 "main" %4 %19 OpSource GLSL 450 OpDecorate %4 Location 0 -+OpDecorate %34 SpecId 4 ++OpDecorate %27 SpecId 4 OpMemberDecorate %17 1 RelaxedPrecision OpMemberDecorate %17 0 BuiltIn Position OpMemberDecorate %17 1 BuiltIn PointSize @@ -281,10 +281,10 @@ OpFunctionEnd %8 = OpTypeVector %5 4 -%15 = OpConstant %5 8 -%16 = OpTypeArray %1 %15 -+%34 = OpSpecConstant %5 8 -+%35 = OpTypeArray %1 %34 ++%27 = OpSpecConstant %5 8 ++%28 = OpTypeArray %1 %27 -%17 = OpTypeStruct %2 %1 %16 %16 -+%17 = OpTypeStruct %2 %1 %35 %35 ++%17 = OpTypeStruct %2 %1 %28 %28 %20 = OpTypeVoid %25 = OpConstant %5 0 %3 = OpTypePointer Input %2 From 9c66587d14e29e2863f1694d7abbd78e9a60e2eb Mon Sep 17 00:00:00 2001 From: Shahbaz Youssefi Date: Fri, 9 Jun 2023 16:28:30 -0400 Subject: [PATCH 175/523] spirv-diff: Update test expectations (#5264) Seems to have been left out due to submission race condition --- test/diff/diff_files/ray_query_types_autogen.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/diff/diff_files/ray_query_types_autogen.cpp b/test/diff/diff_files/ray_query_types_autogen.cpp index 76546d19ba..5507def64e 100644 --- a/test/diff/diff_files/ray_query_types_autogen.cpp +++ b/test/diff/diff_files/ray_query_types_autogen.cpp @@ -63,8 +63,7 @@ TEST(DiffTest, RayQueryTypes) { constexpr char kDiff[] = R"( ; SPIR-V ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 --; Bound: 45 -+; Bound: 83 + ; Bound: 45 ; Schema: 0 OpCapability RayQueryKHR OpCapability Shader @@ -123,8 +122,7 @@ OpFunctionEnd constexpr char kDiff[] = R"( ; SPIR-V ; Version: 1.6 ; Generator: Khronos SPIR-V Tools Assembler; 0 --; Bound: 45 -+; Bound: 83 + ; Bound: 45 ; Schema: 0 OpCapability RayQueryKHR OpCapability Shader From 6d0e3cf6afb8a5e9e246ad9eaeeeb1ac3b5f3ca8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 12 Jun 2023 10:12:23 -0400 Subject: [PATCH 176/523] Roll external/googletest/ 334704df2..65cfeca1a (1 commit) (#5265) https://github.com/google/googletest/compare/334704df263b...65cfeca1a1ee $ git log 334704df2..65cfeca1a --date=short --no-merges --format='%ad %ae %s' 2023-06-09 absl-team internal g3doc documentation change. 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 4252f91749..0894e36245 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ vars = { 'effcee_revision': '6d3b974a7779506b59d70cc7ecea1e47931c7183', - 'googletest_revision': '334704df263b480a3e9e7441ed3292a5e30a37ec', + 'googletest_revision': '65cfeca1a1eebca291b59395f79a60a4497d0f73', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From 40dde04ca20e006bf4a3ecd1e3006c1278a36816 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 13 Jun 2023 09:48:33 -0400 Subject: [PATCH 177/523] Roll external/googletest/ 65cfeca1a..e9078161e (1 commit) (#5267) https://github.com/google/googletest/compare/65cfeca1a1ee...e9078161e6d3 $ git log 65cfeca1a..e9078161e --date=short --no-merges --format='%ad %ae %s' 2023-03-14 macieksroczynski Add COMPONENT to install 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 0894e36245..38be88eefb 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ vars = { 'effcee_revision': '6d3b974a7779506b59d70cc7ecea1e47931c7183', - 'googletest_revision': '65cfeca1a1eebca291b59395f79a60a4497d0f73', + 'googletest_revision': 'e9078161e6d35e31535b3d76086ffd5714050a1b', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From b4f352e54f63a07b3a1338abd22e6ef69106f4ca Mon Sep 17 00:00:00 2001 From: Eugene Kozlov Date: Wed, 14 Jun 2023 18:00:26 +0400 Subject: [PATCH 178/523] Expose preserve_interface in Optimizer::Register*Passes. (#5268) Fixes #5266 --- include/spirv-tools/optimizer.hpp | 18 ++++++++++++ source/opt/optimizer.cpp | 48 +++++++++++++++++++------------ 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp index 8bdd4e8268..3ac12b9484 100644 --- a/include/spirv-tools/optimizer.hpp +++ b/include/spirv-tools/optimizer.hpp @@ -97,12 +97,24 @@ class Optimizer { // Registers passes that attempt to improve performance of generated code. // This sequence of passes is subject to constant review and will change // from time to time. + // + // If |preserve_interface| is true, all non-io variables in the entry point + // interface are considered live and are not eliminated. + // |preserve_interface| should be true if HLSL is generated + // from the SPIR-V bytecode. Optimizer& RegisterPerformancePasses(); + Optimizer& RegisterPerformancePasses(bool preserve_interface); // Registers passes that attempt to improve the size of generated code. // This sequence of passes is subject to constant review and will change // from time to time. + // + // If |preserve_interface| is true, all non-io variables in the entry point + // interface are considered live and are not eliminated. + // |preserve_interface| should be true if HLSL is generated + // from the SPIR-V bytecode. Optimizer& RegisterSizePasses(); + Optimizer& RegisterSizePasses(bool preserve_interface); // Registers passes that attempt to legalize the generated code. // @@ -112,7 +124,13 @@ class Optimizer { // // This sequence of passes is subject to constant review and will change // from time to time. + // + // If |preserve_interface| is true, all non-io variables in the entry point + // interface are considered live and are not eliminated. + // |preserve_interface| should be true if HLSL is generated + // from the SPIR-V bytecode. Optimizer& RegisterLegalizationPasses(); + Optimizer& RegisterLegalizationPasses(bool preserve_interface); // Register passes specified in the list of |flags|. Each flag must be a // string of a form accepted by Optimizer::FlagHasValidForm(). diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index 46a92dd90e..212e247ed0 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -109,7 +109,7 @@ Optimizer& Optimizer::RegisterPass(PassToken&& p) { // The legalization problem is essentially a very general copy propagation // problem. The optimization we use are all used to either do copy propagation // or enable more copy propagation. -Optimizer& Optimizer::RegisterLegalizationPasses() { +Optimizer& Optimizer::RegisterLegalizationPasses(bool preserve_interface) { return // Wrap OpKill instructions so all other code can be inlined. RegisterPass(CreateWrapOpKillPass()) @@ -129,16 +129,16 @@ Optimizer& Optimizer::RegisterLegalizationPasses() { // Propagate the value stored to the loads in very simple cases. .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) .RegisterPass(CreateLocalSingleStoreElimPass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) // Split up aggregates so they are easier to deal with. .RegisterPass(CreateScalarReplacementPass(0)) // Remove loads and stores so everything is in intermediate values. // Takes care of copy propagation of non-members. .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) .RegisterPass(CreateLocalSingleStoreElimPass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) .RegisterPass(CreateLocalMultiStoreElimPass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) // Propagate constants to get as many constant conditions on branches // as possible. .RegisterPass(CreateCCPPass()) @@ -147,7 +147,7 @@ Optimizer& Optimizer::RegisterLegalizationPasses() { // Copy propagate members. Cleans up code sequences generated by // scalar replacement. Also important for removing OpPhi nodes. .RegisterPass(CreateSimplificationPass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) .RegisterPass(CreateCopyPropagateArraysPass()) // May need loop unrolling here see // https://github.com/Microsoft/DirectXShaderCompiler/pull/930 @@ -156,30 +156,34 @@ Optimizer& Optimizer::RegisterLegalizationPasses() { .RegisterPass(CreateVectorDCEPass()) .RegisterPass(CreateDeadInsertElimPass()) .RegisterPass(CreateReduceLoadSizePass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) .RegisterPass(CreateInterpolateFixupPass()); } -Optimizer& Optimizer::RegisterPerformancePasses() { +Optimizer& Optimizer::RegisterLegalizationPasses() { + return RegisterLegalizationPasses(false); +} + +Optimizer& Optimizer::RegisterPerformancePasses(bool preserve_interface) { return RegisterPass(CreateWrapOpKillPass()) .RegisterPass(CreateDeadBranchElimPass()) .RegisterPass(CreateMergeReturnPass()) .RegisterPass(CreateInlineExhaustivePass()) .RegisterPass(CreateEliminateDeadFunctionsPass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) .RegisterPass(CreatePrivateToLocalPass()) .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) .RegisterPass(CreateLocalSingleStoreElimPass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) .RegisterPass(CreateScalarReplacementPass()) .RegisterPass(CreateLocalAccessChainConvertPass()) .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) .RegisterPass(CreateLocalSingleStoreElimPass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) .RegisterPass(CreateLocalMultiStoreElimPass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) .RegisterPass(CreateCCPPass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) .RegisterPass(CreateLoopUnrollPass(true)) .RegisterPass(CreateDeadBranchElimPass()) .RegisterPass(CreateRedundancyEliminationPass()) @@ -189,9 +193,9 @@ Optimizer& Optimizer::RegisterPerformancePasses() { .RegisterPass(CreateLocalAccessChainConvertPass()) .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) .RegisterPass(CreateLocalSingleStoreElimPass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) .RegisterPass(CreateSSARewritePass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) .RegisterPass(CreateVectorDCEPass()) .RegisterPass(CreateDeadInsertElimPass()) .RegisterPass(CreateDeadBranchElimPass()) @@ -199,7 +203,7 @@ Optimizer& Optimizer::RegisterPerformancePasses() { .RegisterPass(CreateIfConversionPass()) .RegisterPass(CreateCopyPropagateArraysPass()) .RegisterPass(CreateReduceLoadSizePass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) .RegisterPass(CreateBlockMergePass()) .RegisterPass(CreateRedundancyEliminationPass()) .RegisterPass(CreateDeadBranchElimPass()) @@ -207,7 +211,11 @@ Optimizer& Optimizer::RegisterPerformancePasses() { .RegisterPass(CreateSimplificationPass()); } -Optimizer& Optimizer::RegisterSizePasses() { +Optimizer& Optimizer::RegisterPerformancePasses() { + return RegisterPerformancePasses(false); +} + +Optimizer& Optimizer::RegisterSizePasses(bool preserve_interface) { return RegisterPass(CreateWrapOpKillPass()) .RegisterPass(CreateDeadBranchElimPass()) .RegisterPass(CreateMergeReturnPass()) @@ -224,12 +232,12 @@ Optimizer& Optimizer::RegisterSizePasses() { .RegisterPass(CreateLocalSingleStoreElimPass()) .RegisterPass(CreateIfConversionPass()) .RegisterPass(CreateSimplificationPass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) .RegisterPass(CreateDeadBranchElimPass()) .RegisterPass(CreateBlockMergePass()) .RegisterPass(CreateLocalAccessChainConvertPass()) .RegisterPass(CreateLocalSingleBlockLoadStoreElimPass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) .RegisterPass(CreateCopyPropagateArraysPass()) .RegisterPass(CreateVectorDCEPass()) .RegisterPass(CreateDeadInsertElimPass()) @@ -239,10 +247,12 @@ Optimizer& Optimizer::RegisterSizePasses() { .RegisterPass(CreateLocalMultiStoreElimPass()) .RegisterPass(CreateRedundancyEliminationPass()) .RegisterPass(CreateSimplificationPass()) - .RegisterPass(CreateAggressiveDCEPass()) + .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) .RegisterPass(CreateCFGCleanupPass()); } +Optimizer& Optimizer::RegisterSizePasses() { return RegisterSizePasses(false); } + bool Optimizer::RegisterPassesFromFlags(const std::vector& flags) { for (const auto& flag : flags) { if (!RegisterPassFromFlag(flag)) { From d33bea584707c3509065010c45d9b79c54c8376b Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Wed, 14 Jun 2023 16:14:46 -0600 Subject: [PATCH 179/523] instrument: Fix buffer address length calculations (#5257) The length of a uvec3 was assumed to be 16 bytes, but it is 12. Sometimes the stride might be 16 bytes though, which is probably the source of the confusion. Redo structure length to be the offset + length of the last member. Add tests to cover arrays of uvec3s and uvec3 struct members. Fixes https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/5691 --- source/opt/inst_buff_addr_check_pass.cpp | 60 ++--- source/opt/inst_buff_addr_check_pass.h | 4 - test/opt/inst_buff_addr_check_test.cpp | 273 ++++++++++++++++++++++- 3 files changed, 283 insertions(+), 54 deletions(-) diff --git a/source/opt/inst_buff_addr_check_pass.cpp b/source/opt/inst_buff_addr_check_pass.cpp index 495470652f..2333d668a3 100644 --- a/source/opt/inst_buff_addr_check_pass.cpp +++ b/source/opt/inst_buff_addr_check_pass.cpp @@ -150,48 +150,13 @@ void InstBuffAddrCheckPass::GenCheckCode( context()->KillInst(ref_inst); } -uint32_t InstBuffAddrCheckPass::GetTypeAlignment(uint32_t type_id) { - Instruction* type_inst = get_def_use_mgr()->GetDef(type_id); - switch (type_inst->opcode()) { - case spv::Op::OpTypeFloat: - case spv::Op::OpTypeInt: - case spv::Op::OpTypeVector: - return GetTypeLength(type_id); - case spv::Op::OpTypeMatrix: - return GetTypeAlignment(type_inst->GetSingleWordInOperand(0)); - case spv::Op::OpTypeArray: - case spv::Op::OpTypeRuntimeArray: - return GetTypeAlignment(type_inst->GetSingleWordInOperand(0)); - case spv::Op::OpTypeStruct: { - uint32_t max = 0; - type_inst->ForEachInId([&max, this](const uint32_t* iid) { - uint32_t alignment = GetTypeAlignment(*iid); - max = (alignment > max) ? alignment : max; - }); - return max; - } - case spv::Op::OpTypePointer: - assert(spv::StorageClass(type_inst->GetSingleWordInOperand(0)) == - spv::StorageClass::PhysicalStorageBufferEXT && - "unexpected pointer type"); - return 8u; - default: - assert(false && "unexpected type"); - return 0; - } -} - uint32_t InstBuffAddrCheckPass::GetTypeLength(uint32_t type_id) { Instruction* type_inst = get_def_use_mgr()->GetDef(type_id); switch (type_inst->opcode()) { case spv::Op::OpTypeFloat: case spv::Op::OpTypeInt: return type_inst->GetSingleWordInOperand(0) / 8u; - case spv::Op::OpTypeVector: { - uint32_t raw_cnt = type_inst->GetSingleWordInOperand(1); - uint32_t adj_cnt = (raw_cnt == 3u) ? 4u : raw_cnt; - return adj_cnt * GetTypeLength(type_inst->GetSingleWordInOperand(0)); - } + case spv::Op::OpTypeVector: case spv::Op::OpTypeMatrix: return type_inst->GetSingleWordInOperand(1) * GetTypeLength(type_inst->GetSingleWordInOperand(0)); @@ -207,18 +172,19 @@ uint32_t InstBuffAddrCheckPass::GetTypeLength(uint32_t type_id) { return cnt * GetTypeLength(type_inst->GetSingleWordInOperand(0)); } case spv::Op::OpTypeStruct: { - uint32_t len = 0; - type_inst->ForEachInId([&len, this](const uint32_t* iid) { - // Align struct length - uint32_t alignment = GetTypeAlignment(*iid); - uint32_t mod = len % alignment; - uint32_t diff = (mod != 0) ? alignment - mod : 0; - len += diff; - // Increment struct length by component length - uint32_t comp_len = GetTypeLength(*iid); - len += comp_len; + // Figure out the location of the last byte of the last member of the + // structure. + uint32_t last_offset = 0, last_len = 0; + + get_decoration_mgr()->ForEachDecoration( + type_id, uint32_t(spv::Decoration::Offset), + [&last_offset](const Instruction& deco_inst) { + last_offset = deco_inst.GetSingleWordInOperand(3); + }); + type_inst->ForEachInId([&last_len, this](const uint32_t* iid) { + last_len = GetTypeLength(*iid); }); - return len; + return last_offset + last_len; } case spv::Op::OpTypeRuntimeArray: default: diff --git a/source/opt/inst_buff_addr_check_pass.h b/source/opt/inst_buff_addr_check_pass.h index 2ec212bf87..9c4b3ed9a9 100644 --- a/source/opt/inst_buff_addr_check_pass.h +++ b/source/opt/inst_buff_addr_check_pass.h @@ -45,10 +45,6 @@ class InstBuffAddrCheckPass : public InstrumentPass { InstProcessFunction& pfn) override; private: - // Return byte alignment of type |type_id|. Must be int, float, vector, - // matrix, struct, array or physical pointer. Uses std430 alignment. - uint32_t GetTypeAlignment(uint32_t type_id); - // Return byte length of type |type_id|. Must be int, float, vector, matrix, // struct, array or physical pointer. Uses std430 alignment and sizes. uint32_t GetTypeLength(uint32_t type_id); diff --git a/test/opt/inst_buff_addr_check_test.cpp b/test/opt/inst_buff_addr_check_test.cpp index 80e6b7a065..8c8635fdf6 100644 --- a/test/opt/inst_buff_addr_check_test.cpp +++ b/test/opt/inst_buff_addr_check_test.cpp @@ -525,7 +525,7 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffe )" + kInputGlobals + R"( ; CHECK: {{%\w+}} = OpTypeFunction %void %uint %uint %uint %uint )" + kOutputGlobals + R"( -; CHECK: %143 = OpConstantNull %Test_0 +; CHECK: {{%\w+}} = OpConstantNull %Test_0 )"; // clang-format on @@ -567,6 +567,146 @@ OpFunctionEnd defs + decorates + globals + main_func + output_funcs, true); } +TEST_F(InstBuffAddrTest, PaddedStructLoad) { + // #version 450 + // #extension GL_EXT_buffer_reference : enable + // #extension GL_ARB_gpu_shader_int64 : enable + // struct Test { + // uvec3 pad_1; // Offset 0 Size 12 + // double pad_2; // Offset 16 Size 8 (alignment requirement) + // float a; // Offset 24 Size 4 + // }; // Total Size 28 + // + // layout(buffer_reference, std430, buffer_reference_align = 16) buffer + // TestBuffer { Test test; }; + // + // Test GetTest(uint64_t ptr) { + // return TestBuffer(ptr).test; + // } + // + // void main() { + // GetTest(0xe0000000); + // } + + const std::string defs = + R"( +OpCapability Shader +OpCapability Float64 +OpCapability Int64 +OpCapability PhysicalStorageBufferAddresses +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint Vertex %main "main" +OpSource GLSL 450 +OpSourceExtension "GL_ARB_gpu_shader_int64" +OpSourceExtension "GL_EXT_buffer_reference" +OpName %main "main" +OpName %Test "Test" +OpMemberName %Test 0 "pad_1" +OpMemberName %Test 1 "pad_2" +OpMemberName %Test 2 "a" +OpName %GetTest_u641_ "GetTest(u641;" +OpName %ptr "ptr" +OpName %Test_0 "Test" +OpMemberName %Test_0 0 "pad_1" +OpMemberName %Test_0 1 "pad_2" +OpMemberName %Test_0 2 "a" +OpName %TestBuffer "TestBuffer" +OpMemberName %TestBuffer 0 "test" +OpName %param "param" +)"; + + // clang-format off + const std::string decorates = R"( +OpDecorate %TestBuffer Block +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 %_runtimearr_uint ArrayStride 4 +)" + kOutputDecorations + R"( +; CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex +; CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex +)"; + + const std::string globals = R"( +%void = OpTypeVoid +%3 = OpTypeFunction %void +%ulong = OpTypeInt 64 0 +%_ptr_Function_ulong = OpTypePointer Function %ulong +%uint = OpTypeInt 32 0 +%v3uint = OpTypeVector %uint 3 +%double = OpTypeFloat 64 +%float = OpTypeFloat 32 +%Test = OpTypeStruct %v3uint %double %float +%13 = OpTypeFunction %Test %_ptr_Function_ulong +OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffer +%Test_0 = OpTypeStruct %v3uint %double %float +%TestBuffer = OpTypeStruct %Test_0 +%_ptr_PhysicalStorageBuffer_TestBuffer = OpTypePointer PhysicalStorageBuffer %TestBuffer +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%_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 +)"; + // clang-format on + + const std::string main_func = + R"( +%main = OpFunction %void None %3 +%5 = OpLabel +%param = OpVariable %_ptr_Function_ulong Function +OpStore %param %ulong_18446744073172680704 +%35 = OpFunctionCall %Test %GetTest_u641_ %param +OpReturn +OpFunctionEnd +%GetTest_u641_ = OpFunction %Test None %13 +%ptr = OpFunctionParameter %_ptr_Function_ulong +%16 = OpLabel +%28 = OpVariable %_ptr_Function_Test Function +%17 = OpLoad %ulong %ptr +%21 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_TestBuffer %17 +%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+}} = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_62 {{%\w+}} {{%\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]] +OpStore %28 %29 +%30 = OpLoad %Test %28 +OpReturnValue %30 +OpFunctionEnd +)"; + + const std::string output_funcs = kSearchAndTest + kStreamWrite4Vert; + + SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch( + defs + decorates + globals + main_func + output_funcs, true); +} + TEST_F(InstBuffAddrTest, DeviceBufferAddressOOB) { // #version 450 // #extension GL_EXT_buffer_reference : enable @@ -609,7 +749,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"( +OpDecorate %u_info Binding 0 +)" + kInputDecorations + kOutputDecorations + R"( %void = OpTypeVoid %3 = OpTypeFunction %void %int = OpTypeInt 32 1 @@ -629,7 +770,8 @@ 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"( +%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int +)" + kInputGlobals + kOutputGlobals + R"( %main = OpFunction %void None %3 %5 = OpLabel %i = OpVariable %_ptr_Function_int Function @@ -679,6 +821,131 @@ OpFunctionEnd)" + kSearchAndTest + kStreamWrite4Vert; SinglePassRunAndMatch(text, true, 7, 23); } +TEST_F(InstBuffAddrTest, UVec3ScalarAddressOOB) { + // clang-format off + // #version 450 + // #extension GL_EXT_buffer_reference : enable + // #extension GL_EXT_scalar_block_layout : enable + // layout(buffer_reference, std430, scalar) readonly buffer IndexBuffer + // { + // uvec3 indices[]; + // }; + // layout(set = 0, binding = 0) uniform ufoo { + // IndexBuffer data; + // int nReads; + // } u_info; + // void main() { + // uvec3 readvec; + // for (int i=0; i < u_info.nReads; ++i) { + // readvec = u_info.data.indices[i]; + // } + // } + const std::string text = R"( +OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint Vertex %main "main" %u_info +OpSource GLSL 450 +OpSourceExtension "GL_EXT_buffer_reference" +OpSourceExtension "GL_EXT_scalar_block_layout" +OpName %main "main" +OpName %i "i" +OpName %ufoo "ufoo" +OpMemberName %ufoo 0 "data" +OpMemberName %ufoo 1 "nReads" +OpName %IndexBuffer "IndexBuffer" +OpMemberName %IndexBuffer 0 "indices" +OpName %u_info "u_info" +OpName %readvec "readvec" +OpMemberDecorate %ufoo 0 Offset 0 +OpMemberDecorate %ufoo 1 Offset 8 +OpDecorate %ufoo Block +OpDecorate %_runtimearr_v3uint ArrayStride 12 +OpMemberDecorate %IndexBuffer 0 NonWritable +OpMemberDecorate %IndexBuffer 0 Offset 0 +OpDecorate %IndexBuffer Block +OpDecorate %u_info DescriptorSet 0 +OpDecorate %u_info Binding 0 +)" + kInputDecorations + kOutputDecorations + R"( +%void = OpTypeVoid +%3 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%_ptr_Function_int = OpTypePointer Function %int +%int_0 = OpConstant %int 0 +OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_IndexBuffer PhysicalStorageBuffer +%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_IndexBuffer %int +%uint = OpTypeInt 32 0 +%v3uint = OpTypeVector %uint 3 +%_runtimearr_v3uint = OpTypeRuntimeArray %v3uint +%IndexBuffer = OpTypeStruct %_runtimearr_v3uint +%_ptr_PhysicalStorageBuffer_IndexBuffer = OpTypePointer PhysicalStorageBuffer %IndexBuffer +%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo +%u_info = OpVariable %_ptr_Uniform_ufoo Uniform +%int_1 = OpConstant %int 1 +%_ptr_Uniform_int = OpTypePointer Uniform %int +%bool = OpTypeBool +)" + kInputGlobals + kOutputGlobals + R"( +%_ptr_Function_v3uint = OpTypePointer Function %v3uint +%_ptr_Uniform__ptr_PhysicalStorageBuffer_IndexBuffer = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_IndexBuffer +%_ptr_PhysicalStorageBuffer_v3uint = OpTypePointer PhysicalStorageBuffer %v3uint +%main = OpFunction %void None %3 +%5 = OpLabel +%i = OpVariable %_ptr_Function_int Function +%readvec = OpVariable %_ptr_Function_v3uint Function +OpStore %i %int_0 +OpBranch %10 +%10 = OpLabel +OpLoopMerge %12 %13 None +OpBranch %14 +%14 = OpLabel +%15 = OpLoad %int %i +%26 = OpAccessChain %_ptr_Uniform_int %u_info %int_1 +%27 = OpLoad %int %26 +%29 = OpSLessThan %bool %15 %27 +OpBranchConditional %29 %11 %12 +%11 = OpLabel +%33 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_IndexBuffer %u_info %int_0 +%34 = OpLoad %_ptr_PhysicalStorageBuffer_IndexBuffer %33 +%35 = OpLoad %int %i +%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+}} = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_66 %uint_2 {{%\w+}} {{%\w+}} +; 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 +%40 = OpIAdd %int %39 %int_1 +OpStore %i %40 +OpBranch %10 +%12 = OpLabel +OpReturn +OpFunctionEnd +)" + kSearchAndTest + kStreamWrite4Vert; + // clang-format on + + SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(text, true, 7, 23); +} + } // namespace } // namespace opt } // namespace spvtools From 285f6cefa634d3cf2befb79b0bb1847a446f5457 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 16 Jun 2023 10:15:46 -0400 Subject: [PATCH 180/523] roll deps (#5273) * Roll external/googletest/ e9078161e..18fa6a4db (2 commits) https://github.com/google/googletest/compare/e9078161e6d3...18fa6a4db32a $ git log e9078161e..18fa6a4db --date=short --no-merges --format='%ad %ae %s' 2023-06-15 absl-team Allow clients to un-suppress output from gUnit EXPECT_EXIT tests. 2023-06-14 dinor Skip entire test suite with `GTEST_SKIP()` in `SetUpTestSuite` Created with: roll-dep external/googletest * Roll external/spirv-headers/ 8e2ad2748..6e09e44cd (1 commit) https://github.com/KhronosGroup/SPIRV-Headers/compare/8e2ad27488ed...6e09e44cd88a $ git log 8e2ad2748..6e09e44cd --date=short --no-merges --format='%ad %ae %s' 2023-06-12 dunfanlu Reserve SPIR-V enums for Meta 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 38be88eefb..9240f7ea88 100644 --- a/DEPS +++ b/DEPS @@ -7,13 +7,13 @@ vars = { 'effcee_revision': '6d3b974a7779506b59d70cc7ecea1e47931c7183', - 'googletest_revision': 'e9078161e6d35e31535b3d76086ffd5714050a1b', + 'googletest_revision': '18fa6a4db32a30675c0b19bf72f8b5f693d21a23', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', 're2_revision': '7c5e396af825562ec8321fdbf2f1cf276b26e3ae', - 'spirv_headers_revision': '8e2ad27488ed2f87c068c01a8f5e8979f7086405', + 'spirv_headers_revision': '6e09e44cd88a5297433411b2ee52f4cf9f50fa90', } deps = { From 6b9fc793307c3bd1015f4afb2b5d47ac62063e6c Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Fri, 16 Jun 2023 07:37:21 -0700 Subject: [PATCH 181/523] Fold negation of integer vectors (#5269) --- source/opt/const_folding_rules.cpp | 61 +++++++---- source/opt/constants.cpp | 25 +++++ source/opt/constants.h | 6 ++ source/opt/type_manager.h | 11 +- test/opt/fold_test.cpp | 163 +++++++++++++++++++++++++---- 5 files changed, 220 insertions(+), 46 deletions(-) diff --git a/source/opt/const_folding_rules.cpp b/source/opt/const_folding_rules.cpp index b1a87a5570..915f41ce14 100644 --- a/source/opt/const_folding_rules.cpp +++ b/source/opt/const_folding_rules.cpp @@ -88,6 +88,22 @@ const analysis::Constant* NegateFPConst(const analysis::Type* result_type, return nullptr; } +// Returns a constants with the value |-val| of the given type. +const analysis::Constant* NegateIntConst(const analysis::Type* result_type, + const analysis::Constant* val, + analysis::ConstantManager* const_mgr) { + const analysis::Integer* int_type = result_type->AsInteger(); + assert(int_type != nullptr); + + if (val->AsNullConstant()) { + return val; + } + + uint64_t new_value = static_cast(-val->GetSignExtendedValue()); + return const_mgr->GetIntConst(new_value, int_type->width(), + int_type->IsSigned()); +} + // Folds an OpcompositeExtract where input is a composite constant. ConstantFoldingRule FoldExtractWithConstants() { return [](IRContext* context, Instruction* inst, @@ -650,25 +666,22 @@ using BinaryScalarFoldingRule = std::function; -// Returns a |ConstantFoldingRule| that folds unary floating point scalar ops -// using |scalar_rule| and unary float point vectors ops by applying +// Returns a |ConstantFoldingRule| that folds unary scalar ops +// using |scalar_rule| and unary vectors ops by applying // |scalar_rule| to the elements of the vector. The |ConstantFoldingRule| // that is returned assumes that |constants| contains 1 entry. If they are // not |nullptr|, then their type is either |Float| or |Integer| or a |Vector| // whose element type is |Float| or |Integer|. -ConstantFoldingRule FoldFPUnaryOp(UnaryScalarFoldingRule scalar_rule) { +ConstantFoldingRule FoldUnaryOp(UnaryScalarFoldingRule scalar_rule) { return [scalar_rule](IRContext* context, Instruction* inst, const std::vector& constants) -> const analysis::Constant* { + analysis::ConstantManager* const_mgr = context->get_constant_mgr(); analysis::TypeManager* type_mgr = context->get_type_mgr(); const analysis::Type* result_type = type_mgr->GetType(inst->type_id()); const analysis::Vector* vector_type = result_type->AsVector(); - if (!inst->IsFloatingPointFoldingAllowed()) { - return nullptr; - } - const analysis::Constant* arg = (inst->opcode() == spv::Op::OpExtInst) ? constants[1] : constants[0]; @@ -703,6 +716,25 @@ ConstantFoldingRule FoldFPUnaryOp(UnaryScalarFoldingRule scalar_rule) { }; } +// Returns a |ConstantFoldingRule| that folds unary floating point scalar ops +// using |scalar_rule| and unary float point vectors ops by applying +// |scalar_rule| to the elements of the vector. The |ConstantFoldingRule| +// that is returned assumes that |constants| contains 1 entry. If they are +// not |nullptr|, then their type is either |Float| or |Integer| or a |Vector| +// whose element type is |Float| or |Integer|. +ConstantFoldingRule FoldFPUnaryOp(UnaryScalarFoldingRule scalar_rule) { + auto folding_rule = FoldUnaryOp(scalar_rule); + return [folding_rule](IRContext* context, Instruction* inst, + const std::vector& constants) + -> const analysis::Constant* { + if (!inst->IsFloatingPointFoldingAllowed()) { + return nullptr; + } + + return folding_rule(context, inst, constants); + }; +} + // Returns the result of folding the constants in |constants| according the // |scalar_rule|. If |result_type| is a vector, then |scalar_rule| is applied // per component. @@ -1105,18 +1137,8 @@ ConstantFoldingRule FoldOpDotWithConstants() { }; } -// This function defines a |UnaryScalarFoldingRule| that subtracts the constant -// from zero. -UnaryScalarFoldingRule FoldFNegateOp() { - return [](const analysis::Type* result_type, const analysis::Constant* a, - analysis::ConstantManager* const_mgr) -> const analysis::Constant* { - assert(result_type != nullptr && a != nullptr); - assert(result_type == a->type()); - return NegateFPConst(result_type, a, const_mgr); - }; -} - -ConstantFoldingRule FoldFNegate() { return FoldFPUnaryOp(FoldFNegateOp()); } +ConstantFoldingRule FoldFNegate() { return FoldFPUnaryOp(NegateFPConst); } +ConstantFoldingRule FoldSNegate() { return FoldUnaryOp(NegateIntConst); } ConstantFoldingRule FoldFClampFeedingCompare(spv::Op cmp_opcode) { return [cmp_opcode](IRContext* context, Instruction* inst, @@ -1632,6 +1654,7 @@ void ConstantFoldingRules::AddFoldingRules() { rules_[spv::Op::OpTranspose].push_back(FoldTranspose); rules_[spv::Op::OpFNegate].push_back(FoldFNegate()); + rules_[spv::Op::OpSNegate].push_back(FoldSNegate()); rules_[spv::Op::OpQuantizeToF16].push_back(FoldQuantizeToF16()); // Add rules for GLSLstd450 diff --git a/source/opt/constants.cpp b/source/opt/constants.cpp index 9b4c89a655..487d024bcf 100644 --- a/source/opt/constants.cpp +++ b/source/opt/constants.cpp @@ -487,6 +487,31 @@ uint32_t ConstantManager::GetSIntConstId(int32_t val) { return GetDefiningInstruction(c)->result_id(); } +const Constant* ConstantManager::GetIntConst(uint64_t val, int32_t bitWidth, + bool isSigned) { + Type* int_type = context()->get_type_mgr()->GetIntType(bitWidth, isSigned); + + if (isSigned) { + // Sign extend the value. + int32_t num_of_bit_to_ignore = 64 - bitWidth; + val = static_cast(val << num_of_bit_to_ignore) >> + num_of_bit_to_ignore; + } else { + // Clear the upper bit that are not used. + uint64_t mask = ((1ull << bitWidth) - 1); + val &= mask; + } + + if (bitWidth <= 32) { + return GetConstant(int_type, {static_cast(val)}); + } + + // If the value is more than 32-bit, we need to split the operands into two + // 32-bit integers. + return GetConstant( + int_type, {static_cast(val >> 32), static_cast(val)}); +} + uint32_t ConstantManager::GetUIntConstId(uint32_t val) { Type* uint_type = context()->get_type_mgr()->GetUIntType(); const Constant* c = GetConstant(uint_type, {val}); diff --git a/source/opt/constants.h b/source/opt/constants.h index 410304eaee..ae8dc6259d 100644 --- a/source/opt/constants.h +++ b/source/opt/constants.h @@ -659,6 +659,12 @@ class ConstantManager { // Returns the id of a 32-bit signed integer constant with value |val|. uint32_t GetSIntConstId(int32_t val); + // Returns an integer constant with `bitWidth` and value |val|. If `isSigned` + // is true, the constant will be a signed integer. Otherwise it will be + // unsigned. Only the `bitWidth` lower order bits of |val| will be used. The + // rest will be ignored. + const Constant* GetIntConst(uint64_t val, int32_t bitWidth, bool isSigned); + // Returns the id of a 32-bit unsigned integer constant with value |val|. uint32_t GetUIntConstId(uint32_t val); diff --git a/source/opt/type_manager.h b/source/opt/type_manager.h index c49e193227..a70c371db0 100644 --- a/source/opt/type_manager.h +++ b/source/opt/type_manager.h @@ -144,18 +144,17 @@ class TypeManager { // |type| (e.g. should be called in loop of |type|'s decorations). void AttachDecoration(const Instruction& inst, Type* type); - Type* GetUIntType() { - Integer int_type(32, false); - return GetRegisteredType(&int_type); - } + Type* GetUIntType() { return GetIntType(32, false); } uint32_t GetUIntTypeId() { return GetTypeInstruction(GetUIntType()); } - Type* GetSIntType() { - Integer int_type(32, true); + Type* GetIntType(int32_t bitWidth, bool isSigned) { + Integer int_type(bitWidth, isSigned); return GetRegisteredType(&int_type); } + Type* GetSIntType() { return GetIntType(32, true); } + uint32_t GetSIntTypeId() { return GetTypeInstruction(GetSIntType()); } Type* GetFloatType() { diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index 079c45c131..f25107fa4a 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -225,6 +225,7 @@ OpName %main "main" %v2int_2_2 = OpConstantComposite %v2int %int_2 %int_2 %v2int_2_3 = OpConstantComposite %v2int %int_2 %int_3 %v2int_3_2 = OpConstantComposite %v2int %int_3 %int_2 +%v2int_n1_n24 = OpConstantComposite %v2int %int_n1 %int_n24 %v2int_4_4 = OpConstantComposite %v2int %int_4 %int_4 %v2int_min_max = OpConstantComposite %v2int %int_min %int_max %v2bool_null = OpConstantNull %v2bool @@ -317,6 +318,8 @@ OpName %main "main" %int_0xC05FD666 = OpConstant %int 0xC05FD666 %int_0x66666666 = OpConstant %int 0x66666666 %v4int_0x3FF00000_0x00000000_0xC05FD666_0x66666666 = OpConstantComposite %v4int %int_0x00000000 %int_0x3FF00000 %int_0x66666666 %int_0xC05FD666 +%ushort_0x4400 = OpConstant %ushort 0x4400 +%short_0x4400 = OpConstant %short 0x4400 %ushort_0xBC00 = OpConstant %ushort 0xBC00 %short_0xBC00 = OpConstant %short 0xBC00 )"; @@ -752,7 +755,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, 1), - // Test case 44: UClamp 1 2 x + // Test case 46: UClamp 1 2 x InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -761,7 +764,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, 2), - // Test case 45: UClamp 2 x 1 + // Test case 47: UClamp 2 x 1 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -770,7 +773,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, 1), - // Test case 46: Bit-cast int 0 to unsigned int + // Test case 48: Bit-cast int 0 to unsigned int InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -778,7 +781,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, 0), - // Test case 47: Bit-cast int -24 to unsigned int + // Test case 49: Bit-cast int -24 to unsigned int InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -786,7 +789,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, static_cast(-24)), - // Test case 48: Bit-cast float 1.0f to unsigned int + // Test case 50: Bit-cast float 1.0f to unsigned int InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -794,7 +797,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, static_cast(0x3f800000)), - // Test case 49: Bit-cast ushort 0xBC00 to ushort + // Test case 51: Bit-cast ushort 0xBC00 to ushort InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -802,7 +805,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, 0xBC00), - // Test case 50: Bit-cast short 0xBC00 to ushort + // Test case 52: Bit-cast short 0xBC00 to ushort InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -810,7 +813,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, 0xFFFFBC00), - // Test case 51: Bit-cast half 1 to ushort + // Test case 53: Bit-cast half 1 to ushort InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -818,7 +821,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, 0x3C00), - // Test case 52: Bit-cast ushort 0xBC00 to short + // Test case 54: Bit-cast ushort 0xBC00 to short InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -826,7 +829,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, 0xBC00), - // Test case 53: Bit-cast short 0xBC00 to short + // Test case 55: Bit-cast short 0xBC00 to short InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -834,7 +837,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, 0xFFFFBC00), - // Test case 54: Bit-cast half 1 to short + // Test case 56: Bit-cast half 1 to short InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -842,7 +845,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, 0x3C00), - // Test case 55: Bit-cast ushort 0xBC00 to half + // Test case 57: Bit-cast ushort 0xBC00 to half InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -850,7 +853,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, 0xBC00), - // Test case 56: Bit-cast short 0xBC00 to half + // Test case 58: Bit-cast short 0xBC00 to half InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -858,7 +861,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, 0xFFFFBC00), - // Test case 57: Bit-cast half 1 to half + // Test case 59: Bit-cast half 1 to half InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -866,7 +869,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, 0x3C00), - // Test case 58: Bit-cast ubyte 1 to byte + // Test case 60: Bit-cast ubyte 1 to byte InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -874,21 +877,61 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, 1), - // Test case 59: Bit-cast byte -1 to ubyte + // Test case 61: Bit-cast byte -1 to ubyte InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpBitcast %ubyte %byte_n1\n" + "OpReturn\n" + "OpFunctionEnd", - 2, 0xFFFFFFFF) + 2, 0xFFFFFFFF), + // Test case 62: Negate 2. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSNegate %int %int_2\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, -2), + // Test case 63: Negate negative short. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSNegate %short %short_0xBC00\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0x4400 /* expected to be sign extended. */), + // Test case 64: Negate positive short. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSNegate %short %short_0x4400\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0xFFFFBC00 /* expected to be sign extended. */), + // Test case 65: Negate a negative short. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSNegate %ushort %ushort_0xBC00\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0x4400 /* expected to be zero extended. */), + // Test case 66: Negate positive short. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSNegate %ushort %ushort_0x4400\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0xBC00 /* expected to be zero extended. */) )); // clang-format on -using IntVectorInstructionFoldingTest = +using UIntVectorInstructionFoldingTest = ::testing::TestWithParam>>; -TEST_P(IntVectorInstructionFoldingTest, Case) { +TEST_P(UIntVectorInstructionFoldingTest, Case) { const auto& tc = GetParam(); // Build module. @@ -925,7 +968,7 @@ TEST_P(IntVectorInstructionFoldingTest, Case) { } // clang-format off -INSTANTIATE_TEST_SUITE_P(TestCase, IntVectorInstructionFoldingTest, +INSTANTIATE_TEST_SUITE_P(TestCase, UIntVectorInstructionFoldingTest, ::testing::Values( // Test case 0: fold 0*n InstructionFoldingCase>( @@ -973,7 +1016,85 @@ ::testing::Values( "%2 = OpBitcast %v2uint %v2int_min_max\n" + "OpReturn\n" + "OpFunctionEnd", - 2, {2147483648, 2147483647}) + 2, {2147483648, 2147483647}), + // Test case 5: fold SNegate vector of uint + InstructionFoldingCase>( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpSNegate %v2uint %v2uint_0x3f800000_0xbf800000\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {static_cast(-0x3f800000), static_cast(-0xbf800000)}) +)); +// clang-format on + +using IntVectorInstructionFoldingTest = + ::testing::TestWithParam>>; + +TEST_P(IntVectorInstructionFoldingTest, Case) { + const auto& tc = GetParam(); + + // Build module. + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(nullptr, context); + + // Fold the instruction to test. + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); + bool succeeded = context->get_instruction_folder().FoldInstruction(inst); + + // Make sure the instruction folded as expected. + EXPECT_TRUE(succeeded); + if (succeeded && inst != nullptr) { + EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); + inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); + std::vector opcodes = {spv::Op::OpConstantComposite}; + EXPECT_THAT(opcodes, Contains(inst->opcode())); + analysis::ConstantManager* const_mrg = context->get_constant_mgr(); + const analysis::Constant* result = const_mrg->GetConstantFromInst(inst); + EXPECT_NE(result, nullptr); + if (result != nullptr) { + const std::vector& componenets = + result->AsVectorConstant()->GetComponents(); + EXPECT_EQ(componenets.size(), tc.expected_result.size()); + for (size_t i = 0; i < componenets.size(); i++) { + EXPECT_EQ(tc.expected_result[i], componenets[i]->GetS32()); + } + } + } +} + +// clang-format off +INSTANTIATE_TEST_SUITE_P(TestCase, IntVectorInstructionFoldingTest, +::testing::Values( + // Test case 0: fold negate of a vector + InstructionFoldingCase>( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSNegate %v2int %v2int_2_3\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {-2, -3}), + // Test case 1: fold negate of a vector containing negative values. + InstructionFoldingCase>( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSNegate %v2int %v2int_n1_n24\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {1, 24}), + // Test case 2: fold negate of a vector at the limits + InstructionFoldingCase>( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSNegate %v2int %v2int_min_max\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {INT_MIN, -INT_MAX}) )); // clang-format on From a720a6926e02133ef9b3824655d027acff8e953f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 17 Jun 2023 17:17:35 -0700 Subject: [PATCH 182/523] Roll external/googletest/ 18fa6a4db..9b12f749f (1 commit) (#5276) https://github.com/google/googletest/compare/18fa6a4db32a...9b12f749fa97 $ git log 18fa6a4db..9b12f749f --date=short --no-merges --format='%ad %ae %s' 2023-06-01 niranjan.nilakantan Ignore the .cache directory create by VSCode. 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 9240f7ea88..329cb2e1bb 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ vars = { 'effcee_revision': '6d3b974a7779506b59d70cc7ecea1e47931c7183', - 'googletest_revision': '18fa6a4db32a30675c0b19bf72f8b5f693d21a23', + 'googletest_revision': '9b12f749fa972d08703d8459e9bf3239617491ca', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From 951980e5ac31dbb83d6f06f1104068c364bca094 Mon Sep 17 00:00:00 2001 From: Laura Hermanns Date: Mon, 19 Jun 2023 15:01:51 -0400 Subject: [PATCH 183/523] Enable vector constant folding (#4913) (#5272) - Add test case 6 to UIntVectorInstructionFoldingTest - Add test case 3 to IntVectorInstructionFoldingTest --- source/opt/constants.cpp | 2 ++ source/opt/fold.cpp | 73 ++++++++++++++++++++++++++++++-------- source/opt/fold.h | 8 +++++ source/opt/instruction.cpp | 28 +++++++++++++-- source/opt/instruction.h | 10 ++++++ test/opt/fold_test.cpp | 20 +++++++++-- 6 files changed, 121 insertions(+), 20 deletions(-) diff --git a/source/opt/constants.cpp b/source/opt/constants.cpp index 487d024bcf..a487a45b88 100644 --- a/source/opt/constants.cpp +++ b/source/opt/constants.cpp @@ -435,6 +435,8 @@ const Constant* ConstantManager::GetNumericVectorConstantWithWords( words_per_element = float_type->width() / 32; else if (const auto* int_type = element_type->AsInteger()) words_per_element = int_type->width() / 32; + else if (element_type->AsBool() != nullptr) + words_per_element = 1; if (words_per_element != 1 && words_per_element != 2) return nullptr; diff --git a/source/opt/fold.cpp b/source/opt/fold.cpp index 453756f8c3..c2a97b6e6e 100644 --- a/source/opt/fold.cpp +++ b/source/opt/fold.cpp @@ -627,7 +627,8 @@ Instruction* InstructionFolder::FoldInstructionToConstant( Instruction* inst, std::function id_map) const { analysis::ConstantManager* const_mgr = context_->get_constant_mgr(); - if (!inst->IsFoldableByFoldScalar() && !HasConstFoldingRule(inst)) { + if (!inst->IsFoldableByFoldScalar() && !inst->IsFoldableByFoldVector() && + !GetConstantFoldingRules().HasFoldingRule(inst)) { return nullptr; } // Collect the values of the constant parameters. @@ -661,29 +662,58 @@ Instruction* InstructionFolder::FoldInstructionToConstant( } } - uint32_t result_val = 0; bool successful = false; + // If all parameters are constant, fold the instruction to a constant. - if (!missing_constants && inst->IsFoldableByFoldScalar()) { - result_val = FoldScalars(inst->opcode(), constants); - successful = true; - } + if (inst->IsFoldableByFoldScalar()) { + uint32_t result_val = 0; - if (!successful && inst->IsFoldableByFoldScalar()) { - successful = FoldIntegerOpToConstant(inst, id_map, &result_val); - } + if (!missing_constants) { + result_val = FoldScalars(inst->opcode(), constants); + successful = true; + } + + if (!successful) { + successful = FoldIntegerOpToConstant(inst, id_map, &result_val); + } + + if (successful) { + const analysis::Constant* result_const = + const_mgr->GetConstant(const_mgr->GetType(inst), {result_val}); + Instruction* folded_inst = + const_mgr->GetDefiningInstruction(result_const, inst->type_id()); + return folded_inst; + } + } else if (inst->IsFoldableByFoldVector()) { + std::vector result_val; + + if (!missing_constants) { + if (Instruction* inst_type = + context_->get_def_use_mgr()->GetDef(inst->type_id())) { + result_val = FoldVectors( + inst->opcode(), inst_type->GetSingleWordInOperand(1), constants); + successful = true; + } + } - if (successful) { - const analysis::Constant* result_const = - const_mgr->GetConstant(const_mgr->GetType(inst), {result_val}); - Instruction* folded_inst = - const_mgr->GetDefiningInstruction(result_const, inst->type_id()); - return folded_inst; + if (successful) { + const analysis::Constant* result_const = + const_mgr->GetNumericVectorConstantWithWords( + const_mgr->GetType(inst)->AsVector(), result_val); + Instruction* folded_inst = + const_mgr->GetDefiningInstruction(result_const, inst->type_id()); + return folded_inst; + } } + return nullptr; } bool InstructionFolder::IsFoldableType(Instruction* type_inst) const { + return IsFoldableScalarType(type_inst) || IsFoldableVectorType(type_inst); +} + +bool InstructionFolder::IsFoldableScalarType(Instruction* type_inst) const { // Support 32-bit integers. if (type_inst->opcode() == spv::Op::OpTypeInt) { return type_inst->GetSingleWordInOperand(0) == 32; @@ -696,6 +726,19 @@ bool InstructionFolder::IsFoldableType(Instruction* type_inst) const { return false; } +bool InstructionFolder::IsFoldableVectorType(Instruction* type_inst) const { + // Support vectors with foldable components + if (type_inst->opcode() == spv::Op::OpTypeVector) { + uint32_t component_type_id = type_inst->GetSingleWordInOperand(0); + Instruction* def_component_type = + context_->get_def_use_mgr()->GetDef(component_type_id); + return def_component_type != nullptr && + IsFoldableScalarType(def_component_type); + } + // Nothing else yet. + return false; +} + bool InstructionFolder::FoldInstruction(Instruction* inst) const { bool modified = false; Instruction* folded_inst(inst); diff --git a/source/opt/fold.h b/source/opt/fold.h index 9a131d0df5..42da65e4d2 100644 --- a/source/opt/fold.h +++ b/source/opt/fold.h @@ -86,6 +86,14 @@ class InstructionFolder { // result type is |type_inst|. bool IsFoldableType(Instruction* type_inst) const; + // Returns true if |FoldInstructionToConstant| could fold an instruction whose + // result type is |type_inst|. + bool IsFoldableScalarType(Instruction* type_inst) const; + + // Returns true if |FoldInstructionToConstant| could fold an instruction whose + // result type is |type_inst|. + bool IsFoldableVectorType(Instruction* type_inst) const; + // Tries to fold |inst| to a single constant, when the input ids to |inst| // have been substituted using |id_map|. Returns a pointer to the OpConstant* // instruction if successful. If necessary, a new constant instruction is diff --git a/source/opt/instruction.cpp b/source/opt/instruction.cpp index ece6baf92f..aa4ae26b64 100644 --- a/source/opt/instruction.cpp +++ b/source/opt/instruction.cpp @@ -751,7 +751,7 @@ bool Instruction::IsOpaqueType() const { } bool Instruction::IsFoldable() const { - return IsFoldableByFoldScalar() || + return IsFoldableByFoldScalar() || IsFoldableByFoldVector() || context()->get_instruction_folder().HasConstFoldingRule(this); } @@ -762,7 +762,7 @@ bool Instruction::IsFoldableByFoldScalar() const { } Instruction* type = context()->get_def_use_mgr()->GetDef(type_id()); - if (!folder.IsFoldableType(type)) { + if (!folder.IsFoldableScalarType(type)) { return false; } @@ -773,7 +773,29 @@ bool Instruction::IsFoldableByFoldScalar() const { Instruction* def_inst = context()->get_def_use_mgr()->GetDef(*op_id); Instruction* def_inst_type = context()->get_def_use_mgr()->GetDef(def_inst->type_id()); - return folder.IsFoldableType(def_inst_type); + return folder.IsFoldableScalarType(def_inst_type); + }); +} + +bool Instruction::IsFoldableByFoldVector() const { + const InstructionFolder& folder = context()->get_instruction_folder(); + if (!folder.IsFoldableOpcode(opcode())) { + return false; + } + + Instruction* type = context()->get_def_use_mgr()->GetDef(type_id()); + if (!folder.IsFoldableVectorType(type)) { + return false; + } + + // Even if the type of the instruction is foldable, its operands may not be + // foldable (e.g., comparisons of 64bit types). Check that all operand types + // are foldable before accepting the instruction. + return WhileEachInOperand([&folder, this](const uint32_t* op_id) { + Instruction* def_inst = context()->get_def_use_mgr()->GetDef(*op_id); + Instruction* def_inst_type = + context()->get_def_use_mgr()->GetDef(def_inst->type_id()); + return folder.IsFoldableVectorType(def_inst_type); }); } diff --git a/source/opt/instruction.h b/source/opt/instruction.h index d50e625177..c2617fba54 100644 --- a/source/opt/instruction.h +++ b/source/opt/instruction.h @@ -294,6 +294,8 @@ class Instruction : public utils::IntrusiveNodeBase { // It is the responsibility of the caller to make sure // that the instruction remains valid. inline void AddOperand(Operand&& operand); + // Adds a copy of |operand| to the list of operands of this instruction. + inline void AddOperand(const Operand& operand); // Gets the |index|-th logical operand as a single SPIR-V word. This method is // not expected to be used with logical operands consisting of multiple SPIR-V // words. @@ -522,6 +524,10 @@ class Instruction : public utils::IntrusiveNodeBase { // constant value by |FoldScalar|. bool IsFoldableByFoldScalar() const; + // Returns true if |this| is an instruction which could be folded into a + // constant value by |FoldVector|. + bool IsFoldableByFoldVector() const; + // Returns true if we are allowed to fold or otherwise manipulate the // instruction that defines |id| in the given context. This includes not // handling NaN values. @@ -676,6 +682,10 @@ inline void Instruction::AddOperand(Operand&& operand) { operands_.push_back(std::move(operand)); } +inline void Instruction::AddOperand(const Operand& operand) { + operands_.push_back(operand); +} + inline void Instruction::SetInOperand(uint32_t index, Operand::OperandData&& data) { SetOperand(index + TypeResultIdCount(), std::move(data)); diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index f25107fa4a..14ac9153f5 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -1026,7 +1026,15 @@ ::testing::Values( "%2 = OpSNegate %v2uint %v2uint_0x3f800000_0xbf800000\n" + "OpReturn\n" + "OpFunctionEnd", - 2, {static_cast(-0x3f800000), static_cast(-0xbf800000)}) + 2, {static_cast(-0x3f800000), static_cast(-0xbf800000)}), + // Test case 6: fold vector components of uint (incuding integer overflow) + InstructionFoldingCase>( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpIAdd %v2uint %v2uint_0x3f800000_0xbf800000 %v2uint_0x3f800000_0xbf800000\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {0x7f000000u, 0x7f000000u}) )); // clang-format on @@ -1094,7 +1102,15 @@ ::testing::Values( "%2 = OpSNegate %v2int %v2int_min_max\n" + "OpReturn\n" + "OpFunctionEnd", - 2, {INT_MIN, -INT_MAX}) + 2, {INT_MIN, -INT_MAX}), + // Test case 3: fold vector components of int + InstructionFoldingCase>( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpIMul %v2int %v2int_2_3 %v2int_2_3\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {4,9}) )); // clang-format on From a63ac9f73d29cd27cdb6e3388d98d1d934e512bb Mon Sep 17 00:00:00 2001 From: Juan Ramos <114601453+juan-lunarg@users.noreply.github.com> Date: Mon, 19 Jun 2023 13:02:41 -0600 Subject: [PATCH 184/523] cmake: Use modern Python3 CMake support (#5277) From the 3.27 release notes: The FindPythonInterp and FindPythonLibs modules, which have been deprecated since CMake 3.12, have been removed by policy CMP0148. Port projects to FindPython3, FindPython2, or FindPython. closes #4145 --- CMakeLists.txt | 6 +++--- source/CMakeLists.txt | 18 +++++++++--------- test/tools/CMakeLists.txt | 4 ++-- test/tools/opt/CMakeLists.txt | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 71cdc00c46..2b854a43a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -250,7 +250,7 @@ if(NOT COMMAND find_host_program) endif() # Tests require Python3 -find_host_package(PythonInterp 3 REQUIRED) +find_host_package(Python3 REQUIRED) # Check for symbol exports on Linux. # At the moment, this check will fail on the OSX build machines for the Android NDK. @@ -259,7 +259,7 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") macro(spvtools_check_symbol_exports TARGET) if (NOT "${SPIRV_SKIP_TESTS}") add_test(NAME spirv-tools-symbol-exports-${TARGET} - COMMAND ${PYTHON_EXECUTABLE} + COMMAND Python3::Interpreter ${spirv-tools_SOURCE_DIR}/utils/check_symbol_exports.py "$") endif() endmacro() @@ -358,7 +358,7 @@ endif(ENABLE_SPIRV_TOOLS_INSTALL) if (NOT "${SPIRV_SKIP_TESTS}") add_test(NAME spirv-tools-copyrights - COMMAND ${PYTHON_EXECUTABLE} utils/check_copyright.py + COMMAND Python3::Interpreter utils/check_copyright.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) endif() diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index acfa0c123b..748fbf2652 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -31,7 +31,7 @@ macro(spvtools_core_tables CONFIG_VERSION) set(GRAMMAR_INSTS_INC_FILE "${spirv-tools_BINARY_DIR}/core.insts-${CONFIG_VERSION}.inc") set(GRAMMAR_KINDS_INC_FILE "${spirv-tools_BINARY_DIR}/operand.kinds-${CONFIG_VERSION}.inc") add_custom_command(OUTPUT ${GRAMMAR_INSTS_INC_FILE} ${GRAMMAR_KINDS_INC_FILE} - COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT} + COMMAND Python3::Interpreter ${GRAMMAR_PROCESSING_SCRIPT} --spirv-core-grammar=${GRAMMAR_JSON_FILE} --extinst-debuginfo-grammar=${DEBUGINFO_GRAMMAR_JSON_FILE} --extinst-cldebuginfo100-grammar=${CLDEBUGINFO100_GRAMMAR_JSON_FILE} @@ -53,7 +53,7 @@ macro(spvtools_enum_string_mapping CONFIG_VERSION) set(GRAMMAR_ENUM_STRING_MAPPING_INC_FILE "${spirv-tools_BINARY_DIR}/enum_string_mapping.inc") add_custom_command(OUTPUT ${GRAMMAR_EXTENSION_ENUM_INC_FILE} ${GRAMMAR_ENUM_STRING_MAPPING_INC_FILE} - COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT} + COMMAND Python3::Interpreter ${GRAMMAR_PROCESSING_SCRIPT} --spirv-core-grammar=${GRAMMAR_JSON_FILE} --extinst-debuginfo-grammar=${DEBUGINFO_GRAMMAR_JSON_FILE} --extinst-cldebuginfo100-grammar=${CLDEBUGINFO100_GRAMMAR_JSON_FILE} @@ -75,7 +75,7 @@ macro(spvtools_vimsyntax CONFIG_VERSION CLVERSION) set(OPENCL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/extinst.opencl.std.100.grammar.json") set(VIMSYNTAX_FILE "${spirv-tools_BINARY_DIR}/spvasm.vim") add_custom_command(OUTPUT ${VIMSYNTAX_FILE} - COMMAND ${PYTHON_EXECUTABLE} ${VIMSYNTAX_PROCESSING_SCRIPT} + COMMAND Python3::Interpreter ${VIMSYNTAX_PROCESSING_SCRIPT} --spirv-core-grammar=${GRAMMAR_JSON_FILE} --extinst-debuginfo-grammar=${DEBUGINFO_GRAMMAR_JSON_FILE} --extinst-glsl-grammar=${GLSL_GRAMMAR_JSON_FILE} @@ -91,7 +91,7 @@ macro(spvtools_glsl_tables CONFIG_VERSION) set(GLSL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/extinst.glsl.std.450.grammar.json") set(GRAMMAR_INC_FILE "${spirv-tools_BINARY_DIR}/glsl.std.450.insts.inc") add_custom_command(OUTPUT ${GRAMMAR_INC_FILE} - COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT} + COMMAND Python3::Interpreter ${GRAMMAR_PROCESSING_SCRIPT} --extinst-glsl-grammar=${GLSL_GRAMMAR_JSON_FILE} --glsl-insts-output=${GRAMMAR_INC_FILE} --output-language=c++ @@ -105,7 +105,7 @@ macro(spvtools_opencl_tables CONFIG_VERSION) set(OPENCL_GRAMMAR_JSON_FILE "${SPIRV_HEADER_INCLUDE_DIR}/spirv/${CONFIG_VERSION}/extinst.opencl.std.100.grammar.json") set(GRAMMAR_INC_FILE "${spirv-tools_BINARY_DIR}/opencl.std.insts.inc") add_custom_command(OUTPUT ${GRAMMAR_INC_FILE} - COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT} + COMMAND Python3::Interpreter ${GRAMMAR_PROCESSING_SCRIPT} --extinst-opencl-grammar=${OPENCL_GRAMMAR_JSON_FILE} --opencl-insts-output=${GRAMMAR_INC_FILE} DEPENDS ${GRAMMAR_PROCESSING_SCRIPT} ${CORE_GRAMMAR_JSON_FILE} ${OPENCL_GRAMMAR_JSON_FILE} @@ -120,7 +120,7 @@ macro(spvtools_vendor_tables VENDOR_TABLE SHORT_NAME OPERAND_KIND_PREFIX) set(GRAMMAR_FILE "${spirv-tools_SOURCE_DIR}/source/extinst.${VENDOR_TABLE}.grammar.json") endif() add_custom_command(OUTPUT ${INSTS_FILE} - COMMAND ${PYTHON_EXECUTABLE} ${GRAMMAR_PROCESSING_SCRIPT} + COMMAND Python3::Interpreter ${GRAMMAR_PROCESSING_SCRIPT} --extinst-vendor-grammar=${GRAMMAR_FILE} --vendor-insts-output=${INSTS_FILE} --vendor-operand-kind-prefix=${OPERAND_KIND_PREFIX} @@ -134,7 +134,7 @@ endmacro(spvtools_vendor_tables) macro(spvtools_extinst_lang_headers NAME GRAMMAR_FILE) set(OUT_H ${spirv-tools_BINARY_DIR}/${NAME}.h) add_custom_command(OUTPUT ${OUT_H} - COMMAND ${PYTHON_EXECUTABLE} ${LANG_HEADER_PROCESSING_SCRIPT} + COMMAND Python3::Interpreter ${LANG_HEADER_PROCESSING_SCRIPT} --extinst-grammar=${GRAMMAR_FILE} --extinst-output-path=${OUT_H} DEPENDS ${LANG_HEADER_PROCESSING_SCRIPT} ${GRAMMAR_FILE} @@ -168,7 +168,7 @@ set_property(TARGET spirv-tools-vimsyntax PROPERTY FOLDER "SPIRV-Tools utilities set(GENERATOR_INC_FILE ${spirv-tools_BINARY_DIR}/generators.inc) set(SPIRV_XML_REGISTRY_FILE ${SPIRV_HEADER_INCLUDE_DIR}/spirv/spir-v.xml) add_custom_command(OUTPUT ${GENERATOR_INC_FILE} - COMMAND ${PYTHON_EXECUTABLE} ${XML_REGISTRY_PROCESSING_SCRIPT} + COMMAND Python3::Interpreter ${XML_REGISTRY_PROCESSING_SCRIPT} --xml=${SPIRV_XML_REGISTRY_FILE} --generator-output=${GENERATOR_INC_FILE} DEPENDS ${XML_REGISTRY_PROCESSING_SCRIPT} ${SPIRV_XML_REGISTRY_FILE} @@ -198,7 +198,7 @@ set(SPIRV_TOOLS_BUILD_VERSION_INC_GENERATOR set(SPIRV_TOOLS_CHANGES_FILE ${spirv-tools_SOURCE_DIR}/CHANGES) add_custom_command(OUTPUT ${SPIRV_TOOLS_BUILD_VERSION_INC} - COMMAND ${PYTHON_EXECUTABLE} + COMMAND Python3::Interpreter ${SPIRV_TOOLS_BUILD_VERSION_INC_GENERATOR} ${SPIRV_TOOLS_CHANGES_FILE} ${SPIRV_TOOLS_BUILD_VERSION_INC} DEPENDS ${SPIRV_TOOLS_BUILD_VERSION_INC_GENERATOR} diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 4c8989fe3b..37fe2b9786 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -13,10 +13,10 @@ # limitations under the License. add_test(NAME spirv-tools_expect_unittests - COMMAND ${PYTHON_EXECUTABLE} -m unittest expect_unittest.py + COMMAND Python3::Interpreter -m unittest expect_unittest.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_test(NAME spirv-tools_spirv_test_framework_unittests - COMMAND ${PYTHON_EXECUTABLE} -m unittest spirv_test_framework_unittest.py + COMMAND Python3::Interpreter -m unittest spirv_test_framework_unittest.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_spvtools_unittest( diff --git a/test/tools/opt/CMakeLists.txt b/test/tools/opt/CMakeLists.txt index 21aa247f1f..966ffbb56d 100644 --- a/test/tools/opt/CMakeLists.txt +++ b/test/tools/opt/CMakeLists.txt @@ -13,9 +13,9 @@ # limitations under the License. if(NOT ${SPIRV_SKIP_TESTS}) - if(${PYTHONINTERP_FOUND}) + if(${Python3_Interpreter_FOUND}) add_test(NAME spirv_opt_cli_tools_tests - COMMAND ${PYTHON_EXECUTABLE} + COMMAND Python3::Interpreter ${CMAKE_CURRENT_SOURCE_DIR}/../spirv_test_framework.py $ $ $ --test-dir ${CMAKE_CURRENT_SOURCE_DIR}) From a6b57f2f0ed3a9f35fdcf7dcc5ace9d28e2326b7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 21 Jun 2023 12:58:32 -0400 Subject: [PATCH 185/523] Roll external/googletest/ 9b12f749f..fb11778f4 (4 commits) (#5279) * Roll external/effcee/ 6d3b974a7..19b4aa87a (1 commit) https://github.com/google/effcee/compare/6d3b974a7779...19b4aa87af25 $ git log 6d3b974a7..19b4aa87a --date=short --no-merges --format='%ad %ae %s' 2023-06-21 stevenperron Add binary dir for abseil Created with: roll-dep external/effcee * Roll external/googletest/ 9b12f749f..fb11778f4 (4 commits) https://github.com/google/googletest/compare/9b12f749fa97...fb11778f43d5 $ git log 9b12f749f..fb11778f4 --date=short --no-merges --format='%ad %ae %s' 2023-06-20 juan cmake: Clean up policy code 2023-06-19 juan cmake: Raise min to 3.6 2023-06-19 git Change C++11 requirement to C++14 2023-06-16 73937934+zencatalyst Update README.md Created with: roll-dep external/googletest * Roll external/spirv-headers/ 6e09e44cd..10db9d4e1 (1 commit) https://github.com/KhronosGroup/SPIRV-Headers/compare/6e09e44cd88a...10db9d4e1942 $ git log 6e09e44cd..10db9d4e1 --date=short --no-merges --format='%ad %ae %s' 2023-06-21 kevin.petit Add definitions for SVP_EXT_image_raw10_raw12 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 329cb2e1bb..d9270b8320 100644 --- a/DEPS +++ b/DEPS @@ -5,15 +5,15 @@ vars = { 'abseil_revision': '79ca5d7aad63973c83a4962a66ab07cd623131ea', - 'effcee_revision': '6d3b974a7779506b59d70cc7ecea1e47931c7183', + 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '9b12f749fa972d08703d8459e9bf3239617491ca', + 'googletest_revision': 'fb11778f43d5844ca9e2016bae75b22d26ea451f', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', 're2_revision': '7c5e396af825562ec8321fdbf2f1cf276b26e3ae', - 'spirv_headers_revision': '6e09e44cd88a5297433411b2ee52f4cf9f50fa90', + 'spirv_headers_revision': '10db9d4e194246a020a4148e220837ac7c68cfd9', } deps = { From 54691dcd737c7b01e524bedcd5e9eb844f1f2d59 Mon Sep 17 00:00:00 2001 From: John Cater Date: Wed, 21 Jun 2023 15:32:27 -0400 Subject: [PATCH 186/523] Migrate `exec_tools` back to `tools`. (#5280) The host transition migration is done so these can now be moved back and `exec_tools` can be removed. --- BUILD.bazel | 23 ++++++++++++----------- build_defs.bzl | 12 ++++++------ 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index ae7f35c6d3..a2342770e7 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -94,7 +94,7 @@ genrule( outs = ["generators.inc"], cmd = "$(location :generate_registry_tables) --xml=$(location @spirv_headers//:spirv_xml_registry) --generator-output=$(location generators.inc)", cmd_bat = "$(location :generate_registry_tables) --xml=$(location @spirv_headers//:spirv_xml_registry) --generator-output=$(location generators.inc)", - exec_tools = [":generate_registry_tables"], + tools = [":generate_registry_tables"], ) py_binary( @@ -108,10 +108,8 @@ genrule( outs = ["build-version.inc"], cmd = "SOURCE_DATE_EPOCH=0 $(location :update_build_version) $(location CHANGES) $(location build-version.inc)", cmd_bat = "set SOURCE_DATE_EPOCH=0 && $(location :update_build_version) $(location CHANGES) $(location build-version.inc)", - # This is explicitly tools and not exec_tools because we run it locally (on the host platform) instead of - # (potentially remotely) on the execution platform. - tools = [":update_build_version"], local = True, + tools = [":update_build_version"], ) # Libraries @@ -146,7 +144,6 @@ cc_library( ":gen_extinst_lang_headers_OpenCLDebugInfo100", ":gen_glsl_tables_unified1", ":gen_opencl_tables_unified1", - ":generators_inc", ":gen_vendor_tables_debuginfo", ":gen_vendor_tables_nonsemantic_clspvreflection", ":gen_vendor_tables_nonsemantic_shader_debuginfo_100", @@ -155,6 +152,7 @@ cc_library( ":gen_vendor_tables_spv_amd_shader_ballot", ":gen_vendor_tables_spv_amd_shader_explicit_vertex_parameter", ":gen_vendor_tables_spv_amd_shader_trinary_minmax", + ":generators_inc", ], hdrs = [ "include/spirv-tools/libspirv.h", @@ -307,17 +305,17 @@ cc_binary( cc_binary( name = "spirv-objdump", srcs = [ - "tools/objdump/objdump.cpp", "tools/objdump/extract_source.cpp", "tools/objdump/extract_source.h", + "tools/objdump/objdump.cpp", ], copts = COMMON_COPTS, visibility = ["//visibility:public"], deps = [ - ":tools_io", - ":tools_util", ":spirv_tools_internal", ":spirv_tools_opt_internal", + ":tools_io", + ":tools_util", "@spirv_headers//:spirv_cpp_headers", ], ) @@ -439,20 +437,23 @@ cc_library( name = "base_{testcase}_test".format(testcase = f[len("test/"):-len("_test.cpp")]), size = "small", srcs = [f], - copts = TEST_COPTS + ['-DTESTING'], + copts = TEST_COPTS + ["-DTESTING"], linkstatic = 1, target_compatible_with = { "test/timer_test.cpp": incompatible_with(["@bazel_tools//src/conditions:windows"]), }.get(f, []), deps = [ + "tools_util", ":spirv_tools_internal", ":test_lib", - "tools_util", "@com_google_googletest//:gtest", "@com_google_googletest//:gtest_main", ], ) for f in glob( - ["test/*_test.cpp", "test/tools/*_test.cpp"], + [ + "test/*_test.cpp", + "test/tools/*_test.cpp", + ], exclude = [ "test/cpp_interface_test.cpp", "test/log_test.cpp", diff --git a/build_defs.bzl b/build_defs.bzl index 4d6f15cb22..76bf3e7923 100644 --- a/build_defs.bzl +++ b/build_defs.bzl @@ -88,7 +88,7 @@ def generate_core_tables(version): outs = outs.values(), cmd = cmd, cmd_bat = cmd, - exec_tools = [":generate_grammar_tables"], + tools = [":generate_grammar_tables"], visibility = ["//visibility:private"], ) @@ -123,7 +123,7 @@ def generate_enum_string_mapping(version): outs = outs.values(), cmd = cmd, cmd_bat = cmd, - exec_tools = [":generate_grammar_tables"], + tools = [":generate_grammar_tables"], visibility = ["//visibility:private"], ) @@ -151,7 +151,7 @@ def generate_opencl_tables(version): outs = outs.values(), cmd = cmd, cmd_bat = cmd, - exec_tools = [":generate_grammar_tables"], + tools = [":generate_grammar_tables"], visibility = ["//visibility:private"], ) @@ -179,7 +179,7 @@ def generate_glsl_tables(version): outs = outs.values(), cmd = cmd, cmd_bat = cmd, - exec_tools = [":generate_grammar_tables"], + tools = [":generate_grammar_tables"], visibility = ["//visibility:private"], ) @@ -207,7 +207,7 @@ def generate_vendor_tables(extension, operand_kind_prefix = ""): outs = outs.values(), cmd = cmd, cmd_bat = cmd, - exec_tools = [":generate_grammar_tables"], + tools = [":generate_grammar_tables"], visibility = ["//visibility:private"], ) @@ -229,6 +229,6 @@ def generate_extinst_lang_headers(name, grammar = None): outs = outs.values(), cmd = cmd, cmd_bat = cmd, - exec_tools = [":generate_language_headers"], + tools = [":generate_language_headers"], visibility = ["//visibility:private"], ) From b12c0fe6f42ef56b7e397d04bdb6e662d08f2b37 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 22 Jun 2023 05:52:44 -0700 Subject: [PATCH 187/523] Roll external/googletest/ fb11778f4..af39146b4 (1 commit) (#5285) https://github.com/google/googletest/compare/fb11778f43d5...af39146b4561 $ git log fb11778f4..af39146b4 --date=short --no-merges --format='%ad %ae %s' 2023-06-20 juan cmake: Remove remaining checks for CMAKE_VERSION 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 d9270b8320..284797f9b0 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': 'fb11778f43d5844ca9e2016bae75b22d26ea451f', + 'googletest_revision': 'af39146b45619b7b0d98d1c85138bdb571975598', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From a68ef7b2c520bada945b5017bb098c7403762448 Mon Sep 17 00:00:00 2001 From: Juan Ramos <114601453+juan-lunarg@users.noreply.github.com> Date: Thu, 22 Jun 2023 07:08:47 -0600 Subject: [PATCH 188/523] cmake: Remove unused SPIRV-Headers variables (#5284) These were removed from SPIRV-Headers a while ago. --- external/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index c412d16f20..d036db0895 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -41,8 +41,6 @@ if (IS_DIRECTORY ${SPIRV_HEADER_DIR}) # Do this so enclosing projects can use SPIRV-Headers_SOURCE_DIR to find # headers to include. if (NOT DEFINED SPIRV-Headers_SOURCE_DIR) - set(SPIRV_HEADERS_SKIP_INSTALL ON) - set(SPIRV_HEADERS_SKIP_EXAMPLES ON) add_subdirectory(${SPIRV_HEADER_DIR}) endif() else() From daee1e7d34704d5f9966f221a1ae060b7438329b Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Thu, 22 Jun 2023 09:39:49 -0600 Subject: [PATCH 189/523] instrument: Combine descriptor length and init state checking (#5274) Simplify what we add to user code by moving most of it into a function that checks both that the descriptor index is in bounds and the initialization state. Move error logging into this function as well. Remove many options to turn off parts of the instrumentation, because there were far too many permutations to keep working and test properly. Combine Buffer and TexBuffer error checking. This requires that VVL set the length of TexBuffers in the descriptor input state, rather than relying on the instrumentation code to call OpImageQuerySize. Since the error log includes the descriptor set and binding numbers we can use a single OOB error code rather than having 4 per-type error codes. Since the error codes are getting renumbered, make them start at 1 rather than 0 so it is easier to determine if the error code was actually set by the instrumentation. --- include/spirv-tools/instrument.hpp | 17 +- include/spirv-tools/optimizer.hpp | 12 +- source/opt/inst_bindless_check_pass.cpp | 701 +++---- source/opt/inst_bindless_check_pass.h | 107 +- source/opt/inst_buff_addr_check_pass.cpp | 4 +- source/opt/inst_debug_printf_pass.cpp | 6 +- source/opt/instrument_pass.cpp | 207 +-- source/opt/instrument_pass.h | 33 +- source/opt/ir_builder.h | 16 + source/opt/optimizer.cpp | 29 +- test/opt/inst_bindless_check_test.cpp | 2108 +++++++++------------- test/opt/inst_buff_addr_check_test.cpp | 271 ++- test/opt/inst_debug_printf_test.cpp | 109 +- 13 files changed, 1422 insertions(+), 2198 deletions(-) diff --git a/include/spirv-tools/instrument.hpp b/include/spirv-tools/instrument.hpp index 448cf8ab79..34e169a9ef 100644 --- a/include/spirv-tools/instrument.hpp +++ b/include/spirv-tools/instrument.hpp @@ -182,18 +182,11 @@ static const int kInstMaxOutCnt = kInstStageOutCnt + 6; // Validation Error Codes // // These are the possible validation error codes. -static const int kInstErrorBindlessBounds = 0; -static const int kInstErrorBindlessUninit = 1; -static const int kInstErrorBuffAddrUnallocRef = 2; -// Deleted: static const int kInstErrorBindlessBuffOOB = 3; -// This comment will will remain for 2 releases to allow -// for the transition of all builds. Buffer OOB is -// generating the following four differentiated codes instead: -static const int kInstErrorBuffOOBUniform = 4; -static const int kInstErrorBuffOOBStorage = 5; -static const int kInstErrorBuffOOBUniformTexel = 6; -static const int kInstErrorBuffOOBStorageTexel = 7; -static const int kInstErrorMax = kInstErrorBuffOOBStorageTexel; +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 // diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp index 3ac12b9484..ddc8384f7a 100644 --- a/include/spirv-tools/optimizer.hpp +++ b/include/spirv-tools/optimizer.hpp @@ -769,16 +769,8 @@ Optimizer::PassToken CreateCombineAccessChainsPass(); // 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. -// |desc_length_enable| controls instrumentation of runtime descriptor array -// references, |desc_init_enable| controls instrumentation of descriptor -// initialization checking, and |buff_oob_enable| controls instrumentation -// of storage and uniform buffer bounds checking, all of which require input -// buffer support. |texbuff_oob_enable| controls instrumentation of texel -// buffers, which does not require input buffer support. -Optimizer::PassToken CreateInstBindlessCheckPass( - uint32_t desc_set, uint32_t shader_id, bool desc_length_enable = false, - bool desc_init_enable = false, bool buff_oob_enable = false, - bool texbuff_oob_enable = false); +Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t desc_set, + uint32_t shader_id); // Create a pass to instrument physical buffer address checking // This pass instruments all physical buffer address references to check that diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp index e8c412ffe1..f265cdd042 100644 --- a/source/opt/inst_bindless_check_pass.cpp +++ b/source/opt/inst_bindless_check_pass.cpp @@ -31,15 +31,12 @@ constexpr int kSpvLoadPtrIdInIdx = 0; constexpr int kSpvAccessChainBaseIdInIdx = 0; constexpr int kSpvAccessChainIndex0IdInIdx = 1; constexpr int kSpvTypeArrayTypeIdInIdx = 0; -constexpr int kSpvTypeArrayLengthIdInIdx = 1; -constexpr int kSpvConstantValueInIdx = 0; constexpr int kSpvVariableStorageClassInIdx = 0; constexpr int kSpvTypePtrTypeIdInIdx = 1; constexpr int kSpvTypeImageDim = 1; constexpr int kSpvTypeImageDepth = 2; constexpr int kSpvTypeImageArrayed = 3; constexpr int kSpvTypeImageMS = 4; -constexpr int kSpvTypeImageSampled = 5; } // namespace void InstBindlessCheckPass::SetupInputBufferIds() { @@ -135,228 +132,76 @@ void InstBindlessCheckPass::SetupInputBufferIds() { // clang-format off // GLSL: -// uint inst_bindless_read_binding_length(uint desc_set_idx, uint binding_idx) -// { -// if (desc_set_idx >= inst_bindless_input_buffer.desc_sets.length()) { -// return 0; -// } -// -// DescriptorSetData set_data = inst_bindless_input_buffer.desc_sets[desc_set_idx]; -// uvec2 ptr_as_vec = uvec2(set_data); -// if ((ptr_as_vec.x == 0u) && (_ptr_as_vec.y == 0u)) -// { -// return 0u; -// } -// uint num_bindings = set_data.num_bindings; -// if (binding_idx >= num_bindings) { -// return 0; -// } -// return set_data.data[binding_idx]; -// } +//bool inst_bindless_check_desc(uint shader_id, uint line, uvec4 stage_info, uint desc_set_idx, uint binding_idx, uint desc_idx, +// uint offset) +//{ +// if (desc_set_idx >= inst_bindless_input_buffer.desc_sets.length()) { +// // kInstErrorBindlessBounds +// inst_bindless_stream_write_6(shader_id, line, stage_info, 1, desc_set_idx, binding_idx, desc_idx, 0, 0); +// return false; +// } +// DescriptorSetData set_data = inst_bindless_input_buffer.desc_sets[desc_set_idx]; +// uvec2 ptr_vec = uvec2(set_data); +// if (ptr_vec.x == 0 && ptr_vec.y == 0) { +// // kInstErrorBindlessBounds +// inst_bindless_stream_write_6(shader_id, line, stage_info, 1, desc_set_idx, binding_idx, desc_idx, 0, 0); +// return false; +// } +// uint num_bindings = set_data.num_bindings; +// if (binding_idx >= num_bindings) { +// // kInstErrorBindlessBounds +// inst_bindless_stream_write_6(shader_id, line, stage_info, 1, desc_set_idx, binding_idx, desc_idx, 0, 0); +// return false; +// } +// uint binding_length = set_data.data[binding_idx]; +// if (desc_idx >= binding_length) { +// // kInstErrorBindlessBounds +// inst_bindless_stream_write_6(shader_id, line, stage_info, 1, desc_set_idx, binding_idx, desc_idx, binding_length, 0); +// return false; +// } +// uint desc_records_start = set_data.data[num_bindings + binding_idx]; +// uint init_or_len = set_data.data[desc_records_start + desc_idx]; +// if (init_or_len == 0) { +// // kInstErrorBindlessUninit +// inst_bindless_stream_write_6(shader_id, line, stage_info, 2, desc_set_idx, binding_idx, desc_idx, 0, 0); +// return false; +// } +// if (offset >= init_or_len) { +// // kInstErrorOOB +// inst_bindless_stream_write_6(shader_id, line, stage_info, 4, desc_set_idx, binding_idx, desc_idx, offset, +// init_or_len); +// return false; +// } +// return true; +//} // clang-format on -uint32_t InstBindlessCheckPass::GenDebugReadLengthFunctionId() { - if (read_length_func_id_ != 0) { - return read_length_func_id_; - } - SetupInputBufferIds(); - const analysis::Integer* uint_type = GetInteger(32, false); - const std::vector param_types(2, uint_type); - - const uint32_t func_id = TakeNextId(); - std::unique_ptr func = - StartFunction(func_id, uint_type, param_types); - - const std::vector param_ids = AddParameters(*func, param_types); - - // Create block - auto new_blk_ptr = MakeUnique(NewLabel(TakeNextId())); - InstructionBuilder builder( - context(), new_blk_ptr.get(), - IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); - Instruction* inst; - - inst = builder.AddBinaryOp( - GetBoolId(), spv::Op::OpUGreaterThanEqual, param_ids[0], - builder.GetUintConstantId(kDebugInputBindlessMaxDescSets)); - const uint32_t desc_cmp_id = inst->result_id(); - - uint32_t error_blk_id = TakeNextId(); - uint32_t merge_blk_id = TakeNextId(); - std::unique_ptr merge_label(NewLabel(merge_blk_id)); - std::unique_ptr error_label(NewLabel(error_blk_id)); - (void)builder.AddConditionalBranch(desc_cmp_id, error_blk_id, merge_blk_id, - merge_blk_id); - - func->AddBasicBlock(std::move(new_blk_ptr)); - - // error return - new_blk_ptr = MakeUnique(std::move(error_label)); - builder.SetInsertPoint(&*new_blk_ptr); - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, - builder.GetUintConstantId(0)); - func->AddBasicBlock(std::move(new_blk_ptr)); - - // check descriptor set table entry is non-null - new_blk_ptr = MakeUnique(std::move(merge_label)); - builder.SetInsertPoint(&*new_blk_ptr); - - analysis::TypeManager* type_mgr = context()->get_type_mgr(); - const uint32_t desc_set_ptr_ptr = type_mgr->FindPointerToType( - desc_set_ptr_id_, spv::StorageClass::StorageBuffer); - - inst = builder.AddAccessChain(desc_set_ptr_ptr, input_buffer_id_, - {builder.GetUintConstantId(0), param_ids[0]}); - 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(); - - 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, - builder.GetUintConstantId(0)); - 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, - builder.GetUintConstantId(0)); - 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(); - - error_blk_id = TakeNextId(); - merge_blk_id = TakeNextId(); - merge_label = NewLabel(merge_blk_id); - error_label = NewLabel(error_blk_id); - (void)builder.AddConditionalBranch(is_null_id, error_blk_id, merge_blk_id, - merge_blk_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - // error return - new_blk_ptr = MakeUnique(std::move(error_label)); - builder.SetInsertPoint(&*new_blk_ptr); - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, - builder.GetUintConstantId(0)); - func->AddBasicBlock(std::move(new_blk_ptr)); - - // check binding is in range - new_blk_ptr = MakeUnique(std::move(merge_label)); - builder.SetInsertPoint(&*new_blk_ptr); - - const uint32_t uint_ptr = type_mgr->FindPointerToType( - GetUintId(), spv::StorageClass::PhysicalStorageBuffer); - - inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id, - {builder.GetUintConstantId(0)}); - 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(); - - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual, - param_ids[1], num_bindings_id); - const uint32_t bindings_cmp_id = inst->result_id(); - - error_blk_id = TakeNextId(); - merge_blk_id = TakeNextId(); - merge_label = NewLabel(merge_blk_id); - error_label = NewLabel(error_blk_id); - (void)builder.AddConditionalBranch(bindings_cmp_id, error_blk_id, - merge_blk_id, merge_blk_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - // error return - new_blk_ptr = MakeUnique(std::move(error_label)); - builder.SetInsertPoint(&*new_blk_ptr); - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, - builder.GetUintConstantId(0)); - func->AddBasicBlock(std::move(new_blk_ptr)); - - // read binding length - new_blk_ptr = MakeUnique(std::move(merge_label)); - builder.SetInsertPoint(&*new_blk_ptr); - - inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id, - {{builder.GetUintConstantId(1), param_ids[1]}}); - 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(); - - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, length_id); - - func->AddBasicBlock(std::move(new_blk_ptr)); - func->SetFunctionEnd(EndFunction()); - - context()->AddFunction(std::move(func)); - context()->AddDebug2Inst(NewGlobalName(func_id, "read_binding_length")); - - read_length_func_id_ = func_id; - // Make sure this function doesn't get processed by - // InstrumentPass::InstProcessCallTreeFromRoots() - param2output_func_id_[2] = func_id; - return read_length_func_id_; -} - -// clang-format off -// GLSL: -// result = inst_bindless_read_binding_length(desc_set_id, binding_id); -// clang-format on -uint32_t InstBindlessCheckPass::GenDebugReadLength( - uint32_t var_id, InstructionBuilder* builder) { - const uint32_t func_id = GenDebugReadLengthFunctionId(); - - const std::vector args = { - builder->GetUintConstantId(var2desc_set_[var_id]), - builder->GetUintConstantId(var2binding_[var_id]), +uint32_t InstBindlessCheckPass::GenDescCheckFunctionId() { + enum { + kShaderId = 0, + kInstructionIndex = 1, + kStageInfo = 2, + kDescSet = 3, + kDescBinding = 4, + kDescIndex = 5, + kByteOffset = 6, + kNumArgs }; - return GenReadFunctionCall(func_id, args, builder); -} - -// clang-format off -// GLSL: -// uint inst_bindless_read_desc_init(uint desc_set_idx, uint binding_idx, uint desc_idx) -// { -// if (desc_set_idx >= uint(inst_bindless_input_buffer.desc_sets.length())) -// { -// return 0u; -// } -// DescriptorSetData set_data = inst_bindless_input_buffer.desc_sets[desc_set_idx]; -// uvec2 ptr_as_vec = uvec2(set_data) -// if ((ptr_as_vec .x == 0u) && (ptr_as_vec.y == 0u)) -// { -// return 0u; -// } -// if (binding_idx >= set_data.num_bindings) -// { -// return 0u; -// } -// if (desc_idx >= set_data.data[binding_idx]) -// { -// return 0u; -// } -// uint desc_records_start = set_data.data[set_data.num_bindings + binding_idx]; -// return set_data.data[desc_records_start + desc_idx]; -// } -// clang-format on -uint32_t InstBindlessCheckPass::GenDebugReadInitFunctionId() { - if (read_init_func_id_ != 0) { - return read_init_func_id_; + if (desc_check_func_id_ != 0) { + return desc_check_func_id_; } + SetupInputBufferIds(); + analysis::TypeManager* type_mgr = context()->get_type_mgr(); const analysis::Integer* uint_type = GetInteger(32, false); - const std::vector param_types(3, uint_type); + const analysis::Vector v4uint(uint_type, 4); + const analysis::Type* v4uint_type = type_mgr->GetRegisteredType(&v4uint); + std::vector param_types(kNumArgs, uint_type); + param_types[2] = v4uint_type; const uint32_t func_id = TakeNextId(); std::unique_ptr func = - StartFunction(func_id, uint_type, param_types); + StartFunction(func_id, type_mgr->GetBoolType(), param_types); const std::vector param_ids = AddParameters(*func, param_types); @@ -365,10 +210,12 @@ uint32_t InstBindlessCheckPass::GenDebugReadInitFunctionId() { InstructionBuilder builder( context(), new_blk_ptr.get(), IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + const uint32_t false_id = builder.GetBoolConstantId(false); + const uint32_t true_id = builder.GetBoolConstantId(true); Instruction* inst; inst = builder.AddBinaryOp( - GetBoolId(), spv::Op::OpUGreaterThanEqual, param_ids[0], + GetBoolId(), spv::Op::OpUGreaterThanEqual, param_ids[kDescSet], builder.GetUintConstantId(kDebugInputBindlessMaxDescSets)); const uint32_t desc_cmp_id = inst->result_id(); @@ -383,20 +230,19 @@ uint32_t InstBindlessCheckPass::GenDebugReadInitFunctionId() { // error return new_blk_ptr = MakeUnique(std::move(error_label)); builder.SetInsertPoint(&*new_blk_ptr); - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, - builder.GetUintConstantId(0)); + (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, false_id); func->AddBasicBlock(std::move(new_blk_ptr)); // check descriptor set table entry is non-null new_blk_ptr = MakeUnique(std::move(merge_label)); builder.SetInsertPoint(&*new_blk_ptr); - analysis::TypeManager* type_mgr = context()->get_type_mgr(); const uint32_t desc_set_ptr_ptr = type_mgr->FindPointerToType( desc_set_ptr_id_, spv::StorageClass::StorageBuffer); - inst = builder.AddAccessChain(desc_set_ptr_ptr, input_buffer_id_, - {builder.GetUintConstantId(0), param_ids[0]}); + inst = builder.AddAccessChain( + desc_set_ptr_ptr, input_buffer_id_, + {builder.GetUintConstantId(0), param_ids[kDescSet]}); const uint32_t set_access_chain_id = inst->result_id(); inst = builder.AddLoad(desc_set_ptr_id_, set_access_chain_id); @@ -434,8 +280,13 @@ uint32_t InstBindlessCheckPass::GenDebugReadInitFunctionId() { // error return new_blk_ptr = MakeUnique(std::move(error_label)); builder.SetInsertPoint(&*new_blk_ptr); - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, - builder.GetUintConstantId(0)); + GenDebugStreamWrite( + param_ids[kShaderId], param_ids[kInstructionIndex], param_ids[kStageInfo], + {builder.GetUintConstantId(kInstErrorBindlessBounds), param_ids[kDescSet], + param_ids[kDescBinding], param_ids[kDescIndex], + builder.GetUintConstantId(0), builder.GetUintConstantId(0)}, + &builder); + (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, false_id); func->AddBasicBlock(std::move(new_blk_ptr)); // check binding is in range @@ -453,7 +304,7 @@ uint32_t InstBindlessCheckPass::GenDebugReadInitFunctionId() { const uint32_t num_bindings_id = inst->result_id(); inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual, - param_ids[1], num_bindings_id); + param_ids[kDescBinding], num_bindings_id); const uint32_t bindings_cmp_id = inst->result_id(); error_blk_id = TakeNextId(); @@ -466,16 +317,22 @@ uint32_t InstBindlessCheckPass::GenDebugReadInitFunctionId() { // error return new_blk_ptr = MakeUnique(std::move(error_label)); builder.SetInsertPoint(&*new_blk_ptr); - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, - builder.GetUintConstantId(0)); + GenDebugStreamWrite( + param_ids[kShaderId], param_ids[kInstructionIndex], param_ids[kStageInfo], + {builder.GetUintConstantId(kInstErrorBindlessBounds), param_ids[kDescSet], + param_ids[kDescBinding], param_ids[kDescIndex], + builder.GetUintConstantId(0), builder.GetUintConstantId(0)}, + &builder); + (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, false_id); func->AddBasicBlock(std::move(new_blk_ptr)); // read binding length new_blk_ptr = MakeUnique(std::move(merge_label)); builder.SetInsertPoint(&*new_blk_ptr); - inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id, - {{builder.GetUintConstantId(1), param_ids[1]}}); + 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)); @@ -483,7 +340,7 @@ uint32_t InstBindlessCheckPass::GenDebugReadInitFunctionId() { // Check descriptor index in bounds inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual, - param_ids[2], length_id); + param_ids[kDescIndex], length_id); const uint32_t desc_idx_range_id = inst->result_id(); error_blk_id = TakeNextId(); @@ -496,15 +353,20 @@ uint32_t InstBindlessCheckPass::GenDebugReadInitFunctionId() { // Error return new_blk_ptr = MakeUnique(std::move(error_label)); builder.SetInsertPoint(&*new_blk_ptr); - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, - builder.GetUintConstantId(0)); + GenDebugStreamWrite( + param_ids[kShaderId], param_ids[kInstructionIndex], param_ids[kStageInfo], + {builder.GetUintConstantId(kInstErrorBindlessBounds), param_ids[kDescSet], + param_ids[kDescBinding], param_ids[kDescIndex], length_id, + builder.GetUintConstantId(0)}, + &builder); + (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, false_id); func->AddBasicBlock(std::move(new_blk_ptr)); // Read descriptor init status new_blk_ptr = MakeUnique(std::move(merge_label)); builder.SetInsertPoint(&*new_blk_ptr); - inst = builder.AddIAdd(GetUintId(), num_bindings_id, param_ids[1]); + inst = builder.AddIAdd(GetUintId(), num_bindings_id, param_ids[kDescBinding]); const uint32_t state_offset_id = inst->result_id(); inst = @@ -515,7 +377,7 @@ uint32_t InstBindlessCheckPass::GenDebugReadInitFunctionId() { 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[2]); + 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 @@ -528,35 +390,90 @@ uint32_t InstBindlessCheckPass::GenDebugReadInitFunctionId() { inst = builder.AddLoad(GetUintId(), init_ac_id, sizeof(uint32_t)); const uint32_t init_status_id = inst->result_id(); - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, init_status_id); + // Check for uninitialized descriptor + inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, init_status_id, + builder.GetUintConstantId(0)); + const uint32_t uninit_check_id = inst->result_id(); + error_blk_id = TakeNextId(); + merge_blk_id = TakeNextId(); + merge_label = NewLabel(merge_blk_id); + error_label = NewLabel(error_blk_id); + (void)builder.AddConditionalBranch(uninit_check_id, error_blk_id, + merge_blk_id, merge_blk_id); + func->AddBasicBlock(std::move(new_blk_ptr)); + new_blk_ptr = MakeUnique(std::move(error_label)); + builder.SetInsertPoint(&*new_blk_ptr); + GenDebugStreamWrite( + param_ids[kShaderId], param_ids[kInstructionIndex], param_ids[kStageInfo], + {builder.GetUintConstantId(kInstErrorBindlessUninit), param_ids[kDescSet], + param_ids[kDescBinding], param_ids[kDescIndex], + builder.GetUintConstantId(0), builder.GetUintConstantId(0)}, + &builder); + (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, false_id); + func->AddBasicBlock(std::move(new_blk_ptr)); + // Check for OOB. + new_blk_ptr = MakeUnique(std::move(merge_label)); + builder.SetInsertPoint(&*new_blk_ptr); + inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual, + param_ids[kByteOffset], init_status_id); + const uint32_t buf_offset_range_id = inst->result_id(); + + error_blk_id = TakeNextId(); + merge_blk_id = TakeNextId(); + merge_label = NewLabel(merge_blk_id); + error_label = NewLabel(error_blk_id); + (void)builder.AddConditionalBranch(buf_offset_range_id, error_blk_id, + merge_blk_id, merge_blk_id); func->AddBasicBlock(std::move(new_blk_ptr)); + // Error return + new_blk_ptr = MakeUnique(std::move(error_label)); + builder.SetInsertPoint(&*new_blk_ptr); + GenDebugStreamWrite( + param_ids[kShaderId], param_ids[kInstructionIndex], param_ids[kStageInfo], + {builder.GetUintConstantId(kInstErrorOOB), param_ids[kDescSet], + param_ids[kDescBinding], param_ids[kDescIndex], param_ids[kByteOffset], + init_status_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, "read_desc_init")); + context()->AddDebug2Inst(NewGlobalName(func_id, "desc_check")); - read_init_func_id_ = func_id; + desc_check_func_id_ = func_id; // Make sure function doesn't get processed by // InstrumentPass::InstProcessCallTreeFromRoots() param2output_func_id_[3] = func_id; - return read_init_func_id_; + return desc_check_func_id_; } // clang-format off // GLSL: -// result = inst_bindless_read_desc_init(desc_set_id, binding_id, desc_idx_id); +// result = inst_bindless_desc_check(shader_id, inst_idx, stage_info, desc_set, binding, desc_idx, offset); // // clang-format on -uint32_t InstBindlessCheckPass::GenDebugReadInit(uint32_t var_id, - uint32_t desc_idx_id, - InstructionBuilder* builder) { - const uint32_t func_id = GenDebugReadInitFunctionId(); +uint32_t InstBindlessCheckPass::GenDescCheckCall( + uint32_t inst_idx, uint32_t stage_idx, uint32_t var_id, + uint32_t desc_idx_id, uint32_t offset_id, InstructionBuilder* builder) { + const uint32_t func_id = GenDescCheckFunctionId(); const std::vector args = { + builder->GetUintConstantId(shader_id_), + builder->GetUintConstantId(inst_idx), + GenStageInfo(stage_idx, builder), builder->GetUintConstantId(var2desc_set_[var_id]), builder->GetUintConstantId(var2binding_[var_id]), - GenUintCastCode(desc_idx_id, builder)}; - return GenReadFunctionCall(func_id, args, builder); + GenUintCastCode(desc_idx_id, builder), + offset_id}; + return GenReadFunctionCall(GetBoolId(), func_id, args, builder); } uint32_t InstBindlessCheckPass::CloneOriginalImage( @@ -1047,29 +964,30 @@ void InstBindlessCheckPass::GenCheckCode( // Gen invalid block new_blk_ptr.reset(new BasicBlock(std::move(invalid_label))); builder.SetInsertPoint(&*new_blk_ptr); - 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(uid2offset_[ref->ref_inst->unique_id()], stage_idx, - {error_id, u_set_id, u_binding_id, u_index_id, - u_offset_id, u_length_id}, - &builder); - } else if (buffer_bounds_enabled_ || texel_buffer_enabled_) { - // Uninitialized Descriptor - Return additional unused zero so all error - // modes will use same debug stream write function - GenDebugStreamWrite(uid2offset_[ref->ref_inst->unique_id()], stage_idx, - {error_id, u_set_id, u_binding_id, u_index_id, - u_length_id, builder.GetUintConstantId(0)}, - &builder); - } else { - // Uninitialized Descriptor - Normal error return - GenDebugStreamWrite( - uid2offset_[ref->ref_inst->unique_id()], stage_idx, - {error_id, u_set_id, u_binding_id, u_index_id, u_length_id}, &builder); + 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) { @@ -1106,77 +1024,42 @@ void InstBindlessCheckPass::GenCheckCode( context()->KillInst(ref->ref_inst); } -void InstBindlessCheckPass::GenDescIdxCheckCode( +void InstBindlessCheckPass::GenDescCheckCode( BasicBlock::iterator ref_inst_itr, UptrVectorIterator ref_block_itr, uint32_t stage_idx, std::vector>* new_blocks) { - // Look for reference through indexed descriptor. If found, analyze and - // save components. If not, return. + // Look for reference through descriptor. If not, return. RefAnalysis ref; if (!AnalyzeDescriptorReference(&*ref_inst_itr, &ref)) return; - Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref.ptr_id); - if (ptr_inst->opcode() != spv::Op::OpAccessChain) return; - // If index and bound both compile-time constants and index < bound, - // return without changing - Instruction* var_inst = get_def_use_mgr()->GetDef(ref.var_id); - Instruction* desc_type_inst = GetPointeeTypeInst(var_inst); - uint32_t length_id = 0; - if (desc_type_inst->opcode() == spv::Op::OpTypeArray) { - length_id = - desc_type_inst->GetSingleWordInOperand(kSpvTypeArrayLengthIdInIdx); - Instruction* index_inst = get_def_use_mgr()->GetDef(ref.desc_idx_id); - Instruction* length_inst = get_def_use_mgr()->GetDef(length_id); - if (index_inst->opcode() == spv::Op::OpConstant && - length_inst->opcode() == spv::Op::OpConstant && - index_inst->GetSingleWordInOperand(kSpvConstantValueInIdx) < - length_inst->GetSingleWordInOperand(kSpvConstantValueInIdx)) - return; - } else if (!desc_idx_enabled_ || - desc_type_inst->opcode() != spv::Op::OpTypeRuntimeArray) { - return; - } - // Move original block's preceding instructions into first new block std::unique_ptr new_blk_ptr; + // Move original block's preceding instructions into first new block MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr); InstructionBuilder builder( context(), &*new_blk_ptr, IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); new_blocks->push_back(std::move(new_blk_ptr)); - uint32_t error_id = builder.GetUintConstantId(kInstErrorBindlessBounds); - // If length id not yet set, descriptor array is runtime size so - // generate load of length from stage's debug input buffer. - if (length_id == 0) { - assert(desc_type_inst->opcode() == spv::Op::OpTypeRuntimeArray && - "unexpected bindless type"); - length_id = GenDebugReadLength(ref.var_id, &builder); - } - // Generate full runtime bounds test code with true branch - // being full reference and false branch being debug output and zero - // for the referenced value. - uint32_t desc_idx_32b_id = Gen32BitCvtCode(ref.desc_idx_id, &builder); - uint32_t length_32b_id = Gen32BitCvtCode(length_id, &builder); - Instruction* ult_inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpULessThan, - desc_idx_32b_id, length_32b_id); - ref.desc_idx_id = desc_idx_32b_id; - GenCheckCode(ult_inst->result_id(), error_id, 0u, length_id, stage_idx, &ref, - new_blocks); - // Move original block's remaining code into remainder/merge block and add - // to new blocks - BasicBlock* back_blk_ptr = &*new_blocks->back(); - MovePostludeCode(ref_block_itr, back_blk_ptr); -} - -void InstBindlessCheckPass::GenDescInitCheckCode( - BasicBlock::iterator ref_inst_itr, - UptrVectorIterator ref_block_itr, uint32_t stage_idx, - std::vector>* new_blocks) { - // Look for reference through descriptor. If not, return. - RefAnalysis ref; - if (!AnalyzeDescriptorReference(&*ref_inst_itr, &ref)) return; // Determine if we can only do initialization check - bool init_check = false; - if (ref.desc_load_id != 0 || !buffer_bounds_enabled_) { - init_check = true; + uint32_t ref_id = builder.GetUintConstantId(0u); + spv::Op op = ref.ref_inst->opcode(); + if (ref.desc_load_id != 0) { + uint32_t num_in_oprnds = ref.ref_inst->NumInOperands(); + if ((op == spv::Op::OpImageRead && num_in_oprnds == 2) || + (op == spv::Op::OpImageFetch && num_in_oprnds == 2) || + (op == spv::Op::OpImageWrite && num_in_oprnds == 3)) { + Instruction* image_inst = get_def_use_mgr()->GetDef(ref.image_id); + uint32_t image_ty_id = image_inst->type_id(); + Instruction* image_ty_inst = get_def_use_mgr()->GetDef(image_ty_id); + if (spv::Dim(image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDim)) == + spv::Dim::Buffer) { + if ((image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDepth) == 0) && + (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageArrayed) == + 0) && + (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageMS) == 0)) { + ref_id = GenUintCastCode(ref.ref_inst->GetSingleWordInOperand(1), + &builder); + } + } + } } else { // For now, only do bounds check for non-aggregate types. Otherwise // just do descriptor initialization check. @@ -1184,106 +1067,24 @@ void InstBindlessCheckPass::GenDescInitCheckCode( Instruction* ref_ptr_inst = get_def_use_mgr()->GetDef(ref.ptr_id); Instruction* pte_type_inst = GetPointeeTypeInst(ref_ptr_inst); spv::Op pte_type_op = pte_type_inst->opcode(); - if (pte_type_op == spv::Op::OpTypeArray || - pte_type_op == spv::Op::OpTypeRuntimeArray || - pte_type_op == spv::Op::OpTypeStruct) - init_check = true; + if (pte_type_op != spv::Op::OpTypeArray && + pte_type_op != spv::Op::OpTypeRuntimeArray && + pte_type_op != spv::Op::OpTypeStruct) { + ref_id = GenLastByteIdx(&ref, &builder); + } } - // If initialization check and not enabled, return - if (init_check && !desc_init_enabled_) return; - // Move original block's preceding instructions into first new block - std::unique_ptr new_blk_ptr; - MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr); - InstructionBuilder builder( - context(), &*new_blk_ptr, - IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); - new_blocks->push_back(std::move(new_blk_ptr)); - // If initialization check, use reference value of zero. - // Else use the index of the last byte referenced. - uint32_t ref_id = init_check ? builder.GetUintConstantId(0u) - : GenLastByteIdx(&ref, &builder); // Read initialization/bounds from debug input buffer. If index id not yet // set, binding is single descriptor, so set index to constant 0. if (ref.desc_idx_id == 0) ref.desc_idx_id = builder.GetUintConstantId(0u); - uint32_t init_id = GenDebugReadInit(ref.var_id, ref.desc_idx_id, &builder); - // Generate runtime initialization/bounds test code with true branch - // being full reference and false branch being debug output and zero - // for the referenced value. - Instruction* ult_inst = - builder.AddBinaryOp(GetBoolId(), spv::Op::OpULessThan, ref_id, init_id); - uint32_t error = - init_check - ? kInstErrorBindlessUninit - : (spv::StorageClass(ref.strg_class) == spv::StorageClass::Uniform - ? kInstErrorBuffOOBUniform - : kInstErrorBuffOOBStorage); - uint32_t error_id = builder.GetUintConstantId(error); - GenCheckCode(ult_inst->result_id(), error_id, init_check ? 0 : ref_id, - init_check ? builder.GetUintConstantId(0u) : init_id, stage_idx, - &ref, new_blocks); - // Move original block's remaining code into remainder/merge block and add - // to new blocks - BasicBlock* back_blk_ptr = &*new_blocks->back(); - MovePostludeCode(ref_block_itr, back_blk_ptr); -} + uint32_t check_id = + GenDescCheckCall(ref.ref_inst->unique_id(), stage_idx, ref.var_id, + ref.desc_idx_id, ref_id, &builder); -void InstBindlessCheckPass::GenTexBuffCheckCode( - BasicBlock::iterator ref_inst_itr, - UptrVectorIterator ref_block_itr, uint32_t stage_idx, - std::vector>* new_blocks) { - // Only process OpImageRead and OpImageWrite with no optional operands - Instruction* ref_inst = &*ref_inst_itr; - spv::Op op = ref_inst->opcode(); - uint32_t num_in_oprnds = ref_inst->NumInOperands(); - if (!((op == spv::Op::OpImageRead && num_in_oprnds == 2) || - (op == spv::Op::OpImageFetch && num_in_oprnds == 2) || - (op == spv::Op::OpImageWrite && num_in_oprnds == 3))) - return; - // Pull components from descriptor reference - RefAnalysis ref; - if (!AnalyzeDescriptorReference(ref_inst, &ref)) return; - // Only process if image is texel buffer - Instruction* image_inst = get_def_use_mgr()->GetDef(ref.image_id); - uint32_t image_ty_id = image_inst->type_id(); - Instruction* image_ty_inst = get_def_use_mgr()->GetDef(image_ty_id); - if (spv::Dim(image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDim)) != - spv::Dim::Buffer) { - return; - } - if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDepth) != 0) return; - if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageArrayed) != 0) return; - if (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageMS) != 0) return; - // Enable ImageQuery Capability if not yet enabled - context()->AddCapability(spv::Capability::ImageQuery); - // Move original block's preceding instructions into first new block - std::unique_ptr new_blk_ptr; - MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr); - InstructionBuilder builder( - context(), &*new_blk_ptr, - IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); - new_blocks->push_back(std::move(new_blk_ptr)); - // Get texel coordinate - uint32_t coord_id = - GenUintCastCode(ref_inst->GetSingleWordInOperand(1), &builder); - // If index id not yet set, binding is single descriptor, so set index to - // constant 0. - if (ref.desc_idx_id == 0) ref.desc_idx_id = builder.GetUintConstantId(0u); - // Get texel buffer size. - Instruction* size_inst = - builder.AddUnaryOp(GetUintId(), spv::Op::OpImageQuerySize, ref.image_id); - uint32_t size_id = size_inst->result_id(); // Generate runtime initialization/bounds test code with true branch - // being full reference and false branch being debug output and zero + // being full reference and false branch being zero // for the referenced value. - Instruction* ult_inst = - builder.AddBinaryOp(GetBoolId(), spv::Op::OpULessThan, coord_id, size_id); - uint32_t error = - (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageSampled) == 2) - ? kInstErrorBuffOOBStorageTexel - : kInstErrorBuffOOBUniformTexel; - uint32_t error_id = builder.GetUintConstantId(error); - GenCheckCode(ult_inst->result_id(), error_id, coord_id, size_id, stage_idx, - &ref, new_blocks); + GenCheckCode(check_id, 0, 0, 0, stage_idx, &ref, new_blocks); + // Move original block's remaining code into remainder/merge block and add // to new blocks BasicBlock* back_blk_ptr = &*new_blocks->back(); @@ -1293,58 +1094,32 @@ void InstBindlessCheckPass::GenTexBuffCheckCode( void InstBindlessCheckPass::InitializeInstBindlessCheck() { // Initialize base class InitializeInstrument(); - // If runtime array length support or buffer bounds checking are enabled, - // create variable mappings. Length support is always enabled if descriptor - // init check is enabled. - if (desc_idx_enabled_ || buffer_bounds_enabled_ || texel_buffer_enabled_) - for (auto& anno : get_module()->annotations()) - if (anno.opcode() == spv::Op::OpDecorate) { - if (spv::Decoration(anno.GetSingleWordInOperand(1u)) == - spv::Decoration::DescriptorSet) { - var2desc_set_[anno.GetSingleWordInOperand(0u)] = - anno.GetSingleWordInOperand(2u); - } else if (spv::Decoration(anno.GetSingleWordInOperand(1u)) == - spv::Decoration::Binding) { - var2binding_[anno.GetSingleWordInOperand(0u)] = - anno.GetSingleWordInOperand(2u); - } + for (auto& anno : get_module()->annotations()) { + if (anno.opcode() == spv::Op::OpDecorate) { + if (spv::Decoration(anno.GetSingleWordInOperand(1u)) == + spv::Decoration::DescriptorSet) { + var2desc_set_[anno.GetSingleWordInOperand(0u)] = + anno.GetSingleWordInOperand(2u); + } else if (spv::Decoration(anno.GetSingleWordInOperand(1u)) == + spv::Decoration::Binding) { + var2binding_[anno.GetSingleWordInOperand(0u)] = + anno.GetSingleWordInOperand(2u); } + } + } } Pass::Status InstBindlessCheckPass::ProcessImpl() { - // Perform bindless bounds check on each entry point function in module + bool modified = false; InstProcessFunction pfn = [this](BasicBlock::iterator ref_inst_itr, UptrVectorIterator ref_block_itr, uint32_t stage_idx, std::vector>* new_blocks) { - return GenDescIdxCheckCode(ref_inst_itr, ref_block_itr, stage_idx, - new_blocks); + return GenDescCheckCode(ref_inst_itr, ref_block_itr, stage_idx, + new_blocks); }; - bool modified = InstProcessEntryPointCallTree(pfn); - if (desc_init_enabled_ || buffer_bounds_enabled_) { - // Perform descriptor initialization and/or buffer bounds check on each - // entry point function in module - pfn = [this](BasicBlock::iterator ref_inst_itr, - UptrVectorIterator ref_block_itr, - uint32_t stage_idx, - std::vector>* new_blocks) { - return GenDescInitCheckCode(ref_inst_itr, ref_block_itr, stage_idx, - new_blocks); - }; - modified |= InstProcessEntryPointCallTree(pfn); - } - if (texel_buffer_enabled_) { - // Perform texel buffer bounds check on each entry point function in - // module. Generate after descriptor bounds and initialization checks. - pfn = [this](BasicBlock::iterator ref_inst_itr, - UptrVectorIterator ref_block_itr, - uint32_t stage_idx, - std::vector>* new_blocks) { - return GenTexBuffCheckCode(ref_inst_itr, ref_block_itr, stage_idx, - new_blocks); - }; - modified |= InstProcessEntryPointCallTree(pfn); - } + + modified = InstProcessEntryPointCallTree(pfn); return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; } diff --git a/source/opt/inst_bindless_check_pass.h b/source/opt/inst_bindless_check_pass.h index f89af025a9..289f02f1ab 100644 --- a/source/opt/inst_bindless_check_pass.h +++ b/source/opt/inst_bindless_check_pass.h @@ -28,16 +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, - bool desc_idx_enable, bool desc_init_enable, - bool buffer_bounds_enable, bool texel_buffer_enable, - bool opt_direct_reads) - : InstrumentPass(desc_set, shader_id, kInstValidationIdBindless, - opt_direct_reads), - desc_idx_enabled_(desc_idx_enable), - desc_init_enabled_(desc_init_enable), - buffer_bounds_enabled_(buffer_bounds_enable), - texel_buffer_enabled_(texel_buffer_enable) {} + InstBindlessCheckPass(uint32_t desc_set, uint32_t shader_id) + : InstrumentPass(desc_set, shader_id, kInstValidationIdBindless, true) {} ~InstBindlessCheckPass() override = default; @@ -47,82 +39,18 @@ class InstBindlessCheckPass : public InstrumentPass { const char* name() const override { return "inst-bindless-check-pass"; } private: - // These functions do bindless checking instrumentation on a single - // instruction which references through a descriptor (ie references into an - // image or buffer). Refer to Vulkan API for further information on - // descriptors. GenDescIdxCheckCode checks that an index into a descriptor - // array (array of images or buffers) is in-bounds. GenDescInitCheckCode - // checks that the referenced descriptor has been initialized, if the - // SPV_EXT_descriptor_indexing extension is enabled, and initialized large - // enough to handle the reference, if RobustBufferAccess is disabled. - // GenDescInitCheckCode checks for uniform and storage buffer overrun. - // GenTexBuffCheckCode checks for texel buffer overrun and should be - // run after GenDescInitCheckCode to first make sure that the descriptor - // is initialized because it uses OpImageQuerySize on the descriptor. - // - // The functions are designed to be passed to - // InstrumentPass::InstProcessEntryPointCallTree(), which applies the - // function to each instruction in a module and replaces the instruction - // if warranted. - // - // If |ref_inst_itr| is a bindless reference, return in |new_blocks| the - // result of instrumenting it with validation code within its block at - // |ref_block_itr|. The validation code first executes a check for the - // specific condition called for. If the check passes, it executes - // the remainder of the reference, otherwise writes a record to the debug - // output buffer stream including |function_idx, instruction_idx, stage_idx| - // and replaces the reference with the null value of the original type. The - // block at |ref_block_itr| can just be replaced with the blocks in - // |new_blocks|, which will contain at least two blocks. The last block will - // comprise all instructions following |ref_inst_itr|, - // preceded by a phi instruction. - // - // These instrumentation functions utilize GenDebugDirectRead() to read data - // from the debug input buffer, specifically the lengths of variable length - // descriptor arrays, and the initialization status of each descriptor. - // The format of the debug input buffer is documented in instrument.hpp. - // - // These instrumentation functions utilize GenDebugStreamWrite() to write its - // error records. The validation-specific part of the error record will - // have the format: - // - // Validation Error Code (=kInstErrorBindlessBounds) - // Descriptor Index - // Descriptor Array Size - // - // The Descriptor Index is the index which has been determined to be - // out-of-bounds. - // - // The Descriptor Array Size is the size of the descriptor array which was - // indexed. - void GenDescIdxCheckCode( - BasicBlock::iterator ref_inst_itr, - UptrVectorIterator ref_block_itr, uint32_t stage_idx, - std::vector>* new_blocks); - - void GenDescInitCheckCode( - BasicBlock::iterator ref_inst_itr, - UptrVectorIterator ref_block_itr, uint32_t stage_idx, - std::vector>* new_blocks); - - void GenTexBuffCheckCode( - BasicBlock::iterator ref_inst_itr, - UptrVectorIterator ref_block_itr, uint32_t stage_idx, - std::vector>* new_blocks); + void GenDescCheckCode(BasicBlock::iterator ref_inst_itr, + UptrVectorIterator ref_block_itr, + uint32_t stage_idx, + std::vector>* new_blocks); void SetupInputBufferIds(); - uint32_t GenDebugReadLengthFunctionId(); - // Generate instructions into |builder| to read length of runtime descriptor - // array |var_id| from debug input buffer and return id of value. - uint32_t GenDebugReadLength(uint32_t var_id, InstructionBuilder* builder); + uint32_t GenDescCheckFunctionId(); - uint32_t GenDebugReadInitFunctionId(); - // Generate instructions into |builder| to read initialization status of - // descriptor array |image_id| at |index_id| from debug input buffer and - // return id of value. - uint32_t GenDebugReadInit(uint32_t image_id, uint32_t index_id, - InstructionBuilder* builder); + uint32_t GenDescCheckCall(uint32_t inst_idx, uint32_t stage_idx, + uint32_t var_id, uint32_t index_id, + uint32_t byte_offset, InstructionBuilder* builder); // Analysis data for descriptor reference components, generated by // AnalyzeDescriptorReference. It is necessary and sufficient for further @@ -190,26 +118,13 @@ class InstBindlessCheckPass : public InstrumentPass { // GenDescInitCheckCode to every instruction in module. Pass::Status ProcessImpl(); - // Enable instrumentation of runtime array length checking - bool desc_idx_enabled_; - - // Enable instrumentation of descriptor initialization checking - bool desc_init_enabled_; - - // Enable instrumentation of uniform and storage buffer overrun checking - bool buffer_bounds_enabled_; - - // Enable instrumentation of texel buffer overrun checking - bool texel_buffer_enabled_; - // Mapping from variable to descriptor set std::unordered_map var2desc_set_; // Mapping from variable to binding std::unordered_map var2binding_; - uint32_t read_length_func_id_{0}; - uint32_t read_init_func_id_{0}; + 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}; diff --git a/source/opt/inst_buff_addr_check_pass.cpp b/source/opt/inst_buff_addr_check_pass.cpp index 2333d668a3..6b90e5888e 100644 --- a/source/opt/inst_buff_addr_check_pass.cpp +++ b/source/opt/inst_buff_addr_check_pass.cpp @@ -113,7 +113,9 @@ void InstBuffAddrCheckPass::GenCheckCode( Instruction* hi_uptr_inst = builder.AddUnaryOp( GetUintId(), spv::Op::OpUConvert, rshift_uptr_inst->result_id()); GenDebugStreamWrite( - uid2offset_[ref_inst->unique_id()], stage_idx, + 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 diff --git a/source/opt/inst_debug_printf_pass.cpp b/source/opt/inst_debug_printf_pass.cpp index 4f97277812..49347d1745 100644 --- a/source/opt/inst_debug_printf_pass.cpp +++ b/source/opt/inst_debug_printf_pass.cpp @@ -165,8 +165,10 @@ void InstDebugPrintfPass::GenOutputCode( GenOutputValues(opnd_inst, &val_ids, &builder); } }); - GenDebugStreamWrite(uid2offset_[printf_inst->unique_id()], stage_idx, val_ids, - &builder); + GenDebugStreamWrite( + builder.GetUintConstantId(shader_id_), + builder.GetUintConstantId(uid2offset_[printf_inst->unique_id()]), + GenStageInfo(stage_idx, &builder), val_ids, &builder); context()->KillInst(printf_inst); } diff --git a/source/opt/instrument_pass.cpp b/source/opt/instrument_pass.cpp index 9233ffd7fb..6f800c3784 100644 --- a/source/opt/instrument_pass.cpp +++ b/source/opt/instrument_pass.cpp @@ -22,9 +22,6 @@ namespace spvtools { namespace opt { namespace { -// Common Parameter Positions -constexpr int kInstCommonParamInstIdx = 0; -constexpr int kInstCommonParamCnt = 1; // Indices of operands in SPIR-V instructions constexpr int kEntryPointFunctionIdInIdx = 1; } // namespace @@ -216,34 +213,6 @@ void InstrumentPass::GenDebugOutputFieldCode(uint32_t base_offset_id, (void)builder->AddStore(achain_inst->result_id(), val_id); } -void InstrumentPass::GenCommonStreamWriteCode(uint32_t record_sz, - uint32_t inst_id, - uint32_t stage_idx, - uint32_t base_offset_id, - InstructionBuilder* builder) { - // Store record size - GenDebugOutputFieldCode(base_offset_id, kInstCommonOutSize, - builder->GetUintConstantId(record_sz), builder); - // Store Shader Id - GenDebugOutputFieldCode(base_offset_id, kInstCommonOutShaderId, - builder->GetUintConstantId(shader_id_), builder); - // Store Instruction Idx - GenDebugOutputFieldCode(base_offset_id, kInstCommonOutInstructionIdx, inst_id, - builder); - // Store Stage Idx - GenDebugOutputFieldCode(base_offset_id, kInstCommonOutStageIdx, - builder->GetUintConstantId(stage_idx), builder); -} - -void InstrumentPass::GenFragCoordEltDebugOutputCode( - uint32_t base_offset_id, uint32_t uint_frag_coord_id, uint32_t element, - InstructionBuilder* builder) { - Instruction* element_val_inst = - builder->AddCompositeExtract(GetUintId(), uint_frag_coord_id, {element}); - GenDebugOutputFieldCode(base_offset_id, kInstFragOutFragCoordX + element, - element_val_inst->result_id(), builder); -} - uint32_t InstrumentPass::GenVarLoad(uint32_t var_id, InstructionBuilder* builder) { Instruction* var_inst = get_def_use_mgr()->GetDef(var_id); @@ -252,28 +221,23 @@ uint32_t InstrumentPass::GenVarLoad(uint32_t var_id, return load_inst->result_id(); } -void InstrumentPass::GenBuiltinOutputCode(uint32_t builtin_id, - uint32_t builtin_off, - uint32_t base_offset_id, - InstructionBuilder* builder) { - // Load and store builtin - uint32_t load_id = GenVarLoad(builtin_id, builder); - GenDebugOutputFieldCode(base_offset_id, builtin_off, load_id, builder); -} - -void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx, - uint32_t base_offset_id, - InstructionBuilder* builder) { +uint32_t InstrumentPass::GenStageInfo(uint32_t stage_idx, + InstructionBuilder* builder) { + std::vector ids(4, builder->GetUintConstantId(0)); + ids[0] = builder->GetUintConstantId(stage_idx); + // %289 = OpCompositeConstruct %v4uint %uint_0 %285 %288 %uint_0 // TODO(greg-lunarg): Add support for all stages switch (spv::ExecutionModel(stage_idx)) { case spv::ExecutionModel::Vertex: { // Load and store VertexId and InstanceId - GenBuiltinOutputCode( + uint32_t load_id = GenVarLoad( context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::VertexIndex)), - kInstVertOutVertexIndex, base_offset_id, builder); - GenBuiltinOutputCode(context()->GetBuiltinInputVarId( + builder); + ids[1] = load_id; + load_id = GenVarLoad(context()->GetBuiltinInputVarId( uint32_t(spv::BuiltIn::InstanceIndex)), - kInstVertOutInstanceIndex, base_offset_id, builder); + builder); + ids[2] = load_id; } break; case spv::ExecutionModel::GLCompute: case spv::ExecutionModel::TaskNV: @@ -284,56 +248,50 @@ void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx, uint32_t load_id = GenVarLoad(context()->GetBuiltinInputVarId(uint32_t( spv::BuiltIn::GlobalInvocationId)), builder); - Instruction* x_inst = - builder->AddCompositeExtract(GetUintId(), load_id, {0}); - Instruction* y_inst = - builder->AddCompositeExtract(GetUintId(), load_id, {1}); - Instruction* z_inst = - builder->AddCompositeExtract(GetUintId(), load_id, {2}); - GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdX, - x_inst->result_id(), builder); - GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdY, - y_inst->result_id(), builder); - GenDebugOutputFieldCode(base_offset_id, kInstCompOutGlobalInvocationIdZ, - z_inst->result_id(), builder); + for (uint32_t u = 0; u < 3u; ++u) { + ids[u + 1] = builder->AddCompositeExtract(GetUintId(), load_id, {u}) + ->result_id(); + } } break; case spv::ExecutionModel::Geometry: { // Load and store PrimitiveId and InvocationId. - GenBuiltinOutputCode( + uint32_t load_id = GenVarLoad( context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)), - kInstGeomOutPrimitiveId, base_offset_id, builder); - GenBuiltinOutputCode( + builder); + ids[1] = load_id; + load_id = GenVarLoad( context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::InvocationId)), - kInstGeomOutInvocationId, base_offset_id, builder); + builder); + ids[2] = load_id; } break; case spv::ExecutionModel::TessellationControl: { // Load and store InvocationId and PrimitiveId - GenBuiltinOutputCode( + uint32_t load_id = GenVarLoad( context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::InvocationId)), - kInstTessCtlOutInvocationId, base_offset_id, builder); - GenBuiltinOutputCode( + builder); + ids[1] = load_id; + load_id = GenVarLoad( context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)), - kInstTessCtlOutPrimitiveId, base_offset_id, builder); + builder); + ids[2] = load_id; } break; case spv::ExecutionModel::TessellationEvaluation: { // Load and store PrimitiveId and TessCoord.uv - GenBuiltinOutputCode( - context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)), - kInstTessEvalOutPrimitiveId, base_offset_id, builder); uint32_t load_id = GenVarLoad( + context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::PrimitiveId)), + builder); + ids[1] = load_id; + load_id = GenVarLoad( context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::TessCoord)), builder); Instruction* uvec3_cast_inst = builder->AddUnaryOp(GetVec3UintId(), spv::Op::OpBitcast, load_id); uint32_t uvec3_cast_id = uvec3_cast_inst->result_id(); - Instruction* u_inst = - builder->AddCompositeExtract(GetUintId(), uvec3_cast_id, {0}); - Instruction* v_inst = - builder->AddCompositeExtract(GetUintId(), uvec3_cast_id, {1}); - GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordU, - u_inst->result_id(), builder); - GenDebugOutputFieldCode(base_offset_id, kInstTessEvalOutTessCoordV, - v_inst->result_id(), builder); + for (uint32_t u = 0; u < 2u; ++u) { + ids[u + 2] = + builder->AddCompositeExtract(GetUintId(), uvec3_cast_id, {u}) + ->result_id(); + } } break; case spv::ExecutionModel::Fragment: { // Load FragCoord and convert to Uint @@ -342,9 +300,13 @@ void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx, context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::FragCoord))); Instruction* uint_frag_coord_inst = builder->AddUnaryOp( GetVec4UintId(), spv::Op::OpBitcast, frag_coord_inst->result_id()); - for (uint32_t u = 0; u < 2u; ++u) - GenFragCoordEltDebugOutputCode( - base_offset_id, uint_frag_coord_inst->result_id(), u, builder); + for (uint32_t u = 0; u < 2u; ++u) { + ids[u + 1] = + builder + ->AddCompositeExtract(GetUintId(), + uint_frag_coord_inst->result_id(), {u}) + ->result_id(); + } } break; case spv::ExecutionModel::RayGenerationNV: case spv::ExecutionModel::IntersectionNV: @@ -356,33 +318,26 @@ void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx, uint32_t launch_id = GenVarLoad( context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::LaunchIdNV)), builder); - Instruction* x_launch_inst = - builder->AddCompositeExtract(GetUintId(), launch_id, {0}); - Instruction* y_launch_inst = - builder->AddCompositeExtract(GetUintId(), launch_id, {1}); - Instruction* z_launch_inst = - builder->AddCompositeExtract(GetUintId(), launch_id, {2}); - GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdX, - x_launch_inst->result_id(), builder); - GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdY, - y_launch_inst->result_id(), builder); - GenDebugOutputFieldCode(base_offset_id, kInstRayTracingOutLaunchIdZ, - z_launch_inst->result_id(), builder); + for (uint32_t u = 0; u < 3u; ++u) { + ids[u + 1] = builder->AddCompositeExtract(GetUintId(), launch_id, {u}) + ->result_id(); + } } break; default: { assert(false && "unsupported stage"); } break; } + return builder->AddCompositeConstruct(GetVec4UintId(), ids)->result_id(); } void InstrumentPass::GenDebugStreamWrite( - uint32_t instruction_idx, uint32_t stage_idx, + 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 = {builder->GetUintConstantId(instruction_idx)}; + 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(stage_idx, val_id_cnt), args); + (void)builder->AddFunctionCall(GetVoidId(), + GetStreamWriteFunctionId(val_id_cnt), args); } bool InstrumentPass::AllConstant(const std::vector& ids) { @@ -398,11 +353,12 @@ uint32_t InstrumentPass::GenDebugDirectRead( // 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(input_func_id, offset_ids, builder); + return GenReadFunctionCall(GetUintId(), input_func_id, offset_ids, builder); } uint32_t InstrumentPass::GenReadFunctionCall( - uint32_t func_id, const std::vector& func_call_args, + uint32_t return_id, uint32_t func_id, + const std::vector& func_call_args, InstructionBuilder* ref_builder) { // If optimizing direct reads and the call has already been generated, // use its result @@ -423,8 +379,7 @@ uint32_t InstrumentPass::GenReadFunctionCall( builder.SetInsertPoint(insert_before); } uint32_t res_id = - builder.AddFunctionCall(GetUintId(), func_id, func_call_args) - ->result_id(); + builder.AddFunctionCall(return_id, func_id, func_call_args)->result_id(); if (insert_in_first_block) call2id_[func_call_args] = res_id; return res_id; } @@ -817,18 +772,27 @@ uint32_t InstrumentPass::GetVoidId() { return void_id_; } -uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx, - uint32_t val_spec_param_cnt) { +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 - uint32_t param_cnt = kInstCommonParamCnt + val_spec_param_cnt; if (param2output_func_id_[param_cnt] == 0) { // Create function param2output_func_id_[param_cnt] = TakeNextId(); analysis::TypeManager* type_mgr = context()->get_type_mgr(); - const std::vector param_types(param_cnt, - GetInteger(32, false)); + 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); @@ -841,10 +805,10 @@ uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx, context(), &*new_blk_ptr, IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); // Gen test if debug output buffer size will not be exceeded. - uint32_t val_spec_offset = kInstStageOutCnt; - uint32_t obuf_record_sz = val_spec_offset + val_spec_param_cnt; - uint32_t buf_id = GetOutputBufferId(); - uint32_t buf_uint_ptr_id = GetOutputBufferPtrId(); + 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)}); @@ -884,13 +848,26 @@ uint32_t InstrumentPass::GetStreamWriteFunctionId(uint32_t stage_idx, new_blk_ptr = MakeUnique(std::move(write_label)); builder.SetInsertPoint(&*new_blk_ptr); // Generate common and stage-specific debug record members - GenCommonStreamWriteCode(obuf_record_sz, param_ids[kInstCommonParamInstIdx], - stage_idx, obuf_curr_sz_id, &builder); - GenStageStreamWriteCode(stage_idx, obuf_curr_sz_id, &builder); + 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 < val_spec_param_cnt; ++i) { + for (uint32_t i = 0; i < param_cnt; ++i) { GenDebugOutputFieldCode(obuf_curr_sz_id, val_spec_offset + i, - param_ids[kInstCommonParamCnt + i], &builder); + param_ids[kFirstParam + i], &builder); } // Close write block and gen merge block (void)builder.AddBranch(merge_blk_id); diff --git a/source/opt/instrument_pass.h b/source/opt/instrument_pass.h index 4bbbb09813..092b361dee 100644 --- a/source/opt/instrument_pass.h +++ b/source/opt/instrument_pass.h @@ -196,7 +196,8 @@ class InstrumentPass : public Pass { // 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 instruction_idx, uint32_t stage_idx, + void GenDebugStreamWrite(uint32_t shader_id, uint32_t instruction_idx_id, + uint32_t stage_info_id, const std::vector& validation_ids, InstructionBuilder* builder); @@ -214,7 +215,7 @@ class InstrumentPass : public Pass { uint32_t GenDebugDirectRead(const std::vector& offset_ids, InstructionBuilder* builder); - uint32_t GenReadFunctionCall(uint32_t func_id, + uint32_t GenReadFunctionCall(uint32_t return_id, uint32_t func_id, const std::vector& args, InstructionBuilder* builder); @@ -323,8 +324,7 @@ class InstrumentPass : public Pass { // 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 stage_idx, - uint32_t val_spec_param_cnt); + 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. @@ -355,34 +355,11 @@ class InstrumentPass : public Pass { uint32_t field_value_id, InstructionBuilder* builder); - // Generate instructions into |builder| which will write the members - // of the debug output record common for all stages and validations at - // |base_off|. - void GenCommonStreamWriteCode(uint32_t record_sz, uint32_t instruction_idx, - uint32_t stage_idx, uint32_t base_off, - InstructionBuilder* builder); - - // Generate instructions into |builder| which will write - // |uint_frag_coord_id| at |component| of the record at |base_offset_id| of - // the debug output buffer . - void GenFragCoordEltDebugOutputCode(uint32_t base_offset_id, - uint32_t uint_frag_coord_id, - uint32_t component, - 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); - // Generate instructions into |builder| which will load the uint |builtin_id| - // and write it into the debug output buffer at |base_off| + |builtin_off|. - void GenBuiltinOutputCode(uint32_t builtin_id, uint32_t builtin_off, - uint32_t base_off, InstructionBuilder* builder); - - // Generate instructions into |builder| which will write the |stage_idx|- - // specific members of the debug output stream at |base_off|. - void GenStageStreamWriteCode(uint32_t stage_idx, uint32_t base_off, - InstructionBuilder* builder); + uint32_t GenStageInfo(uint32_t stage_idx, InstructionBuilder* builder); // Return true if instruction must be in the same block that its result // is used. diff --git a/source/opt/ir_builder.h b/source/opt/ir_builder.h index 48e08ee7af..f3e0afceae 100644 --- a/source/opt/ir_builder.h +++ b/source/opt/ir_builder.h @@ -440,6 +440,22 @@ class InstructionBuilder { return GetContext()->get_constant_mgr()->GetDefiningInstruction(constant); } + Instruction* GetBoolConstant(bool value) { + analysis::Bool type; + uint32_t type_id = GetContext()->get_type_mgr()->GetTypeInstruction(&type); + analysis::Type* rebuilt_type = + GetContext()->get_type_mgr()->GetType(type_id); + uint32_t word = value; + const analysis::Constant* constant = + GetContext()->get_constant_mgr()->GetConstant(rebuilt_type, {word}); + return GetContext()->get_constant_mgr()->GetDefiningInstruction(constant); + } + + uint32_t GetBoolConstantId(bool value) { + Instruction* inst = GetBoolConstant(value); + return (inst != nullptr ? inst->result_id() : 0); + } + Instruction* AddCompositeExtract(uint32_t type, uint32_t id_of_composite, const std::vector& index_list) { std::vector operands; diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index 212e247ed0..0e31f26140 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -429,20 +429,11 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { RegisterPass(CreateWorkaround1209Pass()); } else if (pass_name == "replace-invalid-opcode") { RegisterPass(CreateReplaceInvalidOpcodePass()); - } else if (pass_name == "inst-bindless-check") { - RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false)); - RegisterPass(CreateSimplificationPass()); - RegisterPass(CreateDeadBranchElimPass()); - RegisterPass(CreateBlockMergePass()); - RegisterPass(CreateAggressiveDCEPass(true)); - } else if (pass_name == "inst-desc-idx-check") { - RegisterPass(CreateInstBindlessCheckPass(7, 23, true, true)); - RegisterPass(CreateSimplificationPass()); - RegisterPass(CreateDeadBranchElimPass()); - RegisterPass(CreateBlockMergePass()); - RegisterPass(CreateAggressiveDCEPass(true)); - } else if (pass_name == "inst-buff-oob-check") { - RegisterPass(CreateInstBindlessCheckPass(7, 23, false, false, true, true)); + } else if (pass_name == "inst-bindless-check" || + pass_name == "inst-desc-idx-check" || + pass_name == "inst-buff-oob-check") { + // preserve legacy names + RegisterPass(CreateInstBindlessCheckPass(7, 23)); RegisterPass(CreateSimplificationPass()); RegisterPass(CreateDeadBranchElimPass()); RegisterPass(CreateBlockMergePass()); @@ -955,14 +946,10 @@ Optimizer::PassToken CreateUpgradeMemoryModelPass() { MakeUnique()); } -Optimizer::PassToken CreateInstBindlessCheckPass( - uint32_t desc_set, uint32_t shader_id, bool desc_length_enable, - bool desc_init_enable, bool buff_oob_enable, bool texbuff_oob_enable) { +Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t desc_set, + uint32_t shader_id) { return MakeUnique( - MakeUnique( - desc_set, shader_id, desc_length_enable, desc_init_enable, - buff_oob_enable, texbuff_oob_enable, - desc_length_enable || desc_init_enable || buff_oob_enable)); + MakeUnique(desc_set, shader_id)); } Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set, diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp index dd4b6f6075..c138d5a2e4 100644 --- a/test/opt/inst_bindless_check_test.cpp +++ b/test/opt/inst_bindless_check_test.cpp @@ -41,18 +41,21 @@ static const std::string kOutputGlobals = R"( ; CHECK: [[output_buffer_var]] = OpVariable [[output_ptr_type]] StorageBuffer )"; -static const std::string kStreamWrite6Begin = R"( +static const std::string kStreamWrite6 = R"( ; CHECK: %inst_bindless_stream_write_6 = OpFunction %void None {{%\w+}} -; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_5:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_6:%\w+]] = OpFunctionParameter %uint +; 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_12 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_12 +; 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 @@ -60,211 +63,52 @@ static const std::string kStreamWrite6Begin = R"( ; 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_13 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} %uint_23 +; 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+}} [[param_1]] -)"; - -static const std::string kStreamWrite6End = R"( -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[param_2]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[param_3]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_9 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[param_4]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_10 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[param_5]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_11 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[param_6]] -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpReturn -; CHECK: OpFunctionEnd -)"; - -// clang-format off -static const std::string kStreamWrite6Frag = kStreamWrite6Begin + R"( +; 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+}} %uint_4 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; 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 {{%\w+}} 1 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}} -)" + kStreamWrite6End; - -static const std::string kStreamWrite6Tese = kStreamWrite6Begin + R"( -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} %uint_2 -; CHECK: {{%\w+}} = OpLoad %uint %gl_PrimitiveID +; 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+}} = OpLoad %v3float %gl_TessCoord -; CHECK: {{%\w+}} = OpBitcast %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +; 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+}} -)" + kStreamWrite6End; - -static const std::string kStreamWrite6Vert = kStreamWrite6Begin + R"( -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex -; 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+}} = OpLoad %uint %gl_InstanceIndex -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -)" + kStreamWrite6End; - -static const std::string kStreamWrite6Compute = kStreamWrite6Begin + R"( -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} %uint_5 -; 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+}} = OpIAdd %uint {{%\w+}} %uint_4 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -; 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+}} = OpIAdd %uint {{%\w+}} %uint_6 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -)" + kStreamWrite6End; - -static const std::string kStreamWrite6Ray = kStreamWrite6Begin + R"( -; 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+}} = OpLoad %v3uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -; 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+}} = OpIAdd %uint {{%\w+}} %uint_5 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_6 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -)" + kStreamWrite6End; -// clang-format on - -static const std::string kStreamWrite7Begin = R"( -; CHECK: %inst_bindless_stream_write_7 = OpFunction %void None {{%\w+}} -; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_5:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_6:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_7:%\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+}} %uint_23 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_2 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[param_1]] -)"; - -static const std::string kStreamWrite7End = R"( ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[param_2]] +; 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+}} [[param_3]] +; 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+}} [[param_4]] +; 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+}} [[param_5]] +; 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+}} [[param_6]] +; 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+}} [[param_7]] +; CHECK: OpStore {{%\w+}} [[sw_param_6]] ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: OpReturn ; CHECK: OpFunctionEnd )"; - -// clang-format off -static const std::string kStreamWrite7Frag = kStreamWrite7Begin + R"( -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} %uint_4 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; 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 {{%\w+}} 1 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -)" + kStreamWrite7End; - -static const std::string kStreamWrite7Vert = kStreamWrite7Begin + R"( -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex -; 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+}} = OpLoad %uint %gl_InstanceIndex -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} {{%\w+}} -)" + kStreamWrite7End; // clang-format on static const std::string kInputDecorations = R"( @@ -286,18 +130,23 @@ static const std::string kInputGlobals = R"( ; CHECK: [[input_buffer_var]] = OpVariable [[input_ptr_type]] StorageBuffer )"; -static const std::string kReadBindingLength = R"( -; CHECK: %inst_bindless_read_binding_length = OpFunction %uint None {{%\w+}} -; CHECK: [[bl_desc_set_idx:%\w+]] = OpFunctionParameter %uint -; CHECK: [[bl_binding_idx:%\w+]] = OpFunctionParameter %uint +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_idx:%\w+]] = OpFunctionParameter %uint +; CHECK: [[di_binding_idx:%\w+]] = OpFunctionParameter %uint +; CHECK: [[di_desc_idx:%\w+]] = OpFunctionParameter %uint +; CHECK: [[di_byte_offset:%\w+]] = OpFunctionParameter %uint ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[bl_desc_set_idx]] %uint_32 +; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_desc_set_idx]] %uint_32 ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: OpReturnValue %uint_0 +; CHECK: OpReturnValue %false ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData %inst_bindless_input_buffer %uint_0 [[bl_desc_set_idx]] +; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData %inst_bindless_input_buffer %uint_0 [[di_desc_set_idx]] ; CHECK: {{%\w+}} = OpLoad %_ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData {{%\w+}} ; CHECK: {{%\w+}} = OpBitcast %v2uint {{%\w+}} ; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 @@ -308,223 +157,50 @@ static const std::string kReadBindingLength = R"( ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: OpReturnValue %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 [[di_shader_id]] [[di_line]] [[di_stage_info]] %uint_1 [[di_desc_set_idx]] [[di_binding_idx]] [[di_desc_idx]] %uint_0 %uint_0 +; CHECK: OpReturnValue %false ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 8 -; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[bl_binding_idx]] {{%\w+}} +; CHECK: [[di_num_bindings:%\w+]] = OpLoad %uint {{%\w+}} Aligned 8 +; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_binding_idx]] [[di_num_bindings]] ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: OpReturnValue %uint_0 -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 [[bl_binding_idx]] -; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 4 -; CHECK: OpReturnValue {{%\w+}} -; CHECK: OpFunctionEnd -)"; - -static const std::string kReadDescInit = R"( -; CHECK: %inst_bindless_read_desc_init = OpFunction %uint None {{%\w+}} -; CHECK: [[di_desc_set_idx:%\w+]] = OpFunctionParameter %uint -; CHECK: [[di_binding_idx:%\w+]] = OpFunctionParameter %uint -; CHECK: [[di_desc_idx:%\w+]] = OpFunctionParameter %uint +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 [[di_shader_id]] [[di_line]] [[di_stage_info]] %uint_1 [[di_desc_set_idx]] [[di_binding_idx]] [[di_desc_idx]] %uint_0 %uint_0 +; CHECK: OpReturnValue %false ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_desc_set_idx]] %uint_32 +; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 [[di_binding_idx]] +; CHECK: [[di_desc_array_len:%\w+]] = OpLoad %uint {{%\w+}} Aligned 4 +; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_desc_idx]] [[di_desc_array_len]] ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: OpReturnValue %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 [[di_shader_id]] [[di_line]] [[di_stage_info]] %uint_1 [[di_desc_set_idx]] [[di_binding_idx]] [[di_desc_idx]] [[di_desc_array_len]] %uint_0 +; CHECK: OpReturnValue %false ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData %inst_bindless_input_buffer %uint_0 [[di_desc_set_idx]] -; CHECK: {{%\w+}} = OpLoad %_ptr_PhysicalStorageBuffer_inst_bindless_DescriptorSetData {{%\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: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}} +; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 {{%\w+}} +; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 4 +; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 {{%\w+}} +; CHECK: [[di_init_status:%\w+]] = OpLoad %uint {{%\w+}} Aligned 4 +; CHECK: {{%\w+}} = OpIEqual %bool [[di_init_status]] %uint_0 ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: OpReturnValue %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 [[di_shader_id]] [[di_line]] [[di_stage_info]] %uint_2 [[di_desc_set_idx]] [[di_binding_idx]] [[di_desc_idx]] %uint_0 %uint_0 +; CHECK: OpReturnValue %false ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_0 -; CHECK: [[di_num_bindings:%\w+]] = OpLoad %uint {{%\w+}} Aligned 8 -; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_binding_idx]] [[di_num_bindings]] +; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool {{%\w+}} {{%\w+}} ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: OpReturnValue %uint_0 +; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 [[di_shader_id]] [[di_line]] [[di_stage_info]] %uint_4 [[di_desc_set_idx]] [[di_binding_idx]] [[di_desc_idx]] [[di_byte_offset]] [[di_init_status]] +; CHECK: OpReturnValue %false ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 4 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %uint {{%\w+}} Aligned 4 -; CHECK: OpReturnValue {{%\w+}} +; CHECK: OpReturnValue %true ; CHECK: OpFunctionEnd )"; -TEST_F(InstBindlessTest, NoInstrumentConstIndexInbounds) { - // Texture2D g_tColor[128]; - // - // SamplerState g_sAniso; - // - // struct PS_INPUT - // { - // float2 vTextureCoords : TEXCOORD2; - // }; - // - // struct PS_OUTPUT - // { - // float4 vColor : SV_Target0; - // }; - // - // PS_OUTPUT MainPs(PS_INPUT i) - // { - // PS_OUTPUT ps_output; - // - // ps_output.vColor = g_tColor[ 37 ].Sample(g_sAniso, i.vTextureCoords.xy); - // return ps_output; - // } - - const std::string before = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor -OpExecutionMode %MainPs OriginUpperLeft -OpSource HLSL 500 -OpName %MainPs "MainPs" -OpName %g_tColor "g_tColor" -OpName %g_sAniso "g_sAniso" -OpName %i_vTextureCoords "i.vTextureCoords" -OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" -OpDecorate %g_tColor DescriptorSet 3 -OpDecorate %g_tColor Binding 5 -OpDecorate %g_sAniso DescriptorSet 3 -OpDecorate %i_vTextureCoords Location 0 -OpDecorate %_entryPointOutput_vColor Location 0 -%void = OpTypeVoid -%8 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v2float = OpTypeVector %float 2 -%v4float = OpTypeVector %float 4 -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%int_37 = OpConstant %int 37 -%15 = OpTypeImage %float 2D 0 0 0 1 Unknown -%uint = OpTypeInt 32 0 -%uint_128 = OpConstant %uint 128 -%_arr_15_uint_128 = OpTypeArray %15 %uint_128 -%_ptr_UniformConstant__arr_15_uint_128 = OpTypePointer UniformConstant %_arr_15_uint_128 -%g_tColor = OpVariable %_ptr_UniformConstant__arr_15_uint_128 UniformConstant -%_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15 -%21 = OpTypeSampler -%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21 -%g_sAniso = OpVariable %_ptr_UniformConstant_21 UniformConstant -%23 = OpTypeSampledImage %15 -%_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 -%MainPs = OpFunction %void None %8 -%26 = OpLabel -%27 = OpLoad %v2float %i_vTextureCoords -%28 = OpAccessChain %_ptr_UniformConstant_15 %g_tColor %int_37 -%29 = OpLoad %15 %28 -%30 = OpLoad %21 %g_sAniso -%31 = OpSampledImage %23 %29 %30 -%32 = OpImageSampleImplicitLod %v4float %31 %27 -OpStore %_entryPointOutput_vColor %32 -OpReturn -OpFunctionEnd -)"; - - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndCheck( - before, before, true, true, 7u, 23u, false, false, false, false, false); -} - -TEST_F(InstBindlessTest, NoInstrumentNonBindless) { - // This test verifies that the pass will correctly not instrument vanilla - // texture sample. - // - // Texture2D g_tColor; - // - // SamplerState g_sAniso; - // - // struct PS_INPUT - // { - // float2 vTextureCoords : TEXCOORD2; - // }; - // - // struct PS_OUTPUT - // { - // float4 vColor : SV_Target0; - // }; - // - // PS_OUTPUT MainPs(PS_INPUT i) - // { - // PS_OUTPUT ps_output; - // ps_output.vColor = - // g_tColor.Sample(g_sAniso, i.vTextureCoords.xy); - // return ps_output; - // } - - const std::string whole_file = - R"(OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %MainPs "MainPs" %i_vTextureCoords %_entryPointOutput_vColor -OpExecutionMode %MainPs OriginUpperLeft -OpSource HLSL 500 -OpName %MainPs "MainPs" -OpName %g_tColor "g_tColor" -OpName %g_sAniso "g_sAniso" -OpName %i_vTextureCoords "i.vTextureCoords" -OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" -OpDecorate %g_tColor DescriptorSet 6 -OpDecorate %g_tColor Binding 4 -OpDecorate %g_sAniso DescriptorSet 6 -OpDecorate %g_sAniso Binding 4 -OpDecorate %i_vTextureCoords Location 0 -OpDecorate %_entryPointOutput_vColor Location 0 -%void = OpTypeVoid -%8 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v2float = OpTypeVector %float 2 -%v4float = OpTypeVector %float 4 -%12 = OpTypeImage %float 2D 0 0 0 1 Unknown -%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12 -%g_tColor = OpVariable %_ptr_UniformConstant_12 UniformConstant -%14 = OpTypeSampler -%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14 -%g_sAniso = OpVariable %_ptr_UniformConstant_14 UniformConstant -%16 = OpTypeSampledImage %12 -%_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 -%MainPs = OpFunction %void None %8 -%19 = OpLabel -%20 = OpLoad %v2float %i_vTextureCoords -%21 = OpLoad %12 %g_tColor -%22 = OpLoad %14 %g_sAniso -%23 = OpSampledImage %16 %21 %22 -%24 = OpImageSampleImplicitLod %v4float %23 %20 -OpStore %_entryPointOutput_vColor %24 -OpReturn -OpFunctionEnd -)"; - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndCheck(whole_file, whole_file, true, - true, 7u, 23u, false, false, - false, false, false); -} - TEST_F(InstBindlessTest, Simple) { // Texture2D g_tColor[128]; // @@ -613,7 +289,6 @@ 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: %bool = OpTypeBool ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint )" + kOutputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint @@ -637,7 +312,7 @@ OpDecorate %_entryPointOutput_vColor Location 0 OpStore %_entryPointOutput_vColor %37 ; CHECK-NOT: %37 = OpImageSampleImplicitLod %v4float %36 %30 ; CHECK-NOT: OpStore %_entryPointOutput_vColor %37 -; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} %uint_128 +; 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 @@ -646,7 +321,6 @@ OpStore %_entryPointOutput_vColor %37 ; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %30 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_56 %uint_0 %uint_3 %uint_0 %32 %uint_128 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} @@ -655,12 +329,12 @@ OpReturn OpFunctionEnd )"; - const std::string output_func = kStreamWrite6Frag; + const std::string output_func = kStreamWrite6 + kCheckDesc; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch( + SinglePassRunAndMatch( entry + names_annots + consts_types_vars + main_func + output_func, true, - 7u, 23u, false, false, false, false, false); + 7u, 23u); } TEST_F(InstBindlessTest, InstrumentMultipleInstructions) { @@ -721,7 +395,7 @@ OpDecorate %g_sAniso DescriptorSet 3 OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %10 = OpTypeFunction %void @@ -750,14 +424,12 @@ 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: %bool = OpTypeBool -; CHECK: {{%\w+}} = OpTypeFunction %void %uint %uint %uint %uint ; 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: %v4uint = OpTypeVector %uint 4 ; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -774,19 +446,23 @@ OpDecorate %_entryPointOutput_vColor Location 0 %37 = OpSampledImage %27 %35 %36 %38 = OpImageSampleImplicitLod %v4float %37 %31 ; CHECK-NOT: %38 = OpImageSampleImplicitLod %v4float %37 %31 -; CHECK: %48 = OpULessThan %bool %33 %uint_128 -; CHECK: OpSelectionMerge %49 None -; CHECK: OpBranchConditional %48 %50 %51 -; CHECK: %50 = OpLabel -; CHECK: %52 = OpLoad %17 %34 -; CHECK: %53 = OpSampledImage %27 %52 %36 -; CHECK: %54 = OpImageSampleImplicitLod %v4float %53 %31 -; CHECK: OpBranch %49 -; CHECK: %51 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_58 %uint_0 %uint_3 %uint_4 %33 %uint_128 -; CHECK: OpBranch %49 -; CHECK: %49 = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float %54 %50 [[null_v4float]] %51 +; 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+}} %39 = OpAccessChain %_ptr_PushConstant_uint %_ %int_1 %40 = OpLoad %uint %39 %41 = OpAccessChain %_ptr_UniformConstant_17 %g_tColor %40 @@ -796,7 +472,12 @@ OpDecorate %_entryPointOutput_vColor Location 0 %45 = OpFAdd %v4float %38 %44 ; CHECK-NOT: %44 = OpImageSampleImplicitLod %v4float %43 %31 ; CHECK-NOT: %45 = OpFAdd %v4float %38 %44 -; CHECK: {{%\w+}} = OpULessThan %bool %40 %uint_128 +; 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 @@ -805,7 +486,6 @@ OpDecorate %_entryPointOutput_vColor Location 0 ; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %31 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_64 %uint_0 %uint_3 %uint_4 %40 %uint_128 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} @@ -815,12 +495,11 @@ OpReturn OpFunctionEnd )"; - const std::string output_func = kStreamWrite6Frag; + const std::string output_func = kStreamWrite6 + kCheckDesc; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + output_func, - true, 7u, 23u, false, false, - false, false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, InstrumentOpImage) { @@ -853,7 +532,7 @@ OpDecorate %PerViewConstantBuffer_t Block OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %3 = OpTypeFunction %void @@ -878,14 +557,11 @@ 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: uint_0 = OpConstant %uint 0 -; CHECK: bool = OpTypeBool ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kOutputGlobals + R"( +)" + 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: %v4uint = OpTypeVector %uint 4 ; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -903,30 +579,33 @@ OpDecorate %_entryPointOutput_vColor Location 0 OpStore %_entryPointOutput_vColor %71 ; CHECK-NOT: %71 = OpImageRead %v4float %75 %53 ; CHECK-NOT: OpStore %_entryPointOutput_vColor %71 -; CHECK: %78 = OpULessThan %bool %64 %uint_128 -; CHECK: OpSelectionMerge %79 None -; CHECK: OpBranchConditional %78 %80 %81 -; CHECK: %80 = OpLabel -; CHECK: %82 = OpLoad %39 %65 -; CHECK: %83 = OpImage %20 %82 -; CHECK: %84 = OpImageRead %v4float %83 %53 -; CHECK: OpBranch %79 -; CHECK: %81 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_3 %uint_9 %64 %uint_128 -; CHECK: OpBranch %79 -; CHECK: %79 = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float %84 %80 [[null_v4float]] %81 +; 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+}} OpReturn OpFunctionEnd )"; - const std::string output_func = kStreamWrite6Frag; + const std::string output_func = kStreamWrite6 + kCheckDesc; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + output_func, - true, 7u, 23u, false, false, - false, false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, InstrumentSampledImage) { @@ -957,7 +636,7 @@ OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 OpDecorate %PerViewConstantBuffer_t Block OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %3 = OpTypeFunction %void @@ -982,14 +661,11 @@ 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: uint_0 = OpConstant %uint 0 -; CHECK: bool = OpTypeBool ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kOutputGlobals + R"( +)" + 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: %v4uint = OpTypeVector %uint 4 ; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -1006,29 +682,32 @@ OpDecorate %_entryPointOutput_vColor Location 0 OpStore %_entryPointOutput_vColor %71 ; CHECK-NOT: %71 = OpImageSampleImplicitLod %v4float %66 %53 ; CHECK-NOT: OpStore %_entryPointOutput_vColor %71 -; CHECK: %74 = OpULessThan %bool %64 %uint_128 -; CHECK: OpSelectionMerge %75 None -; CHECK: OpBranchConditional %74 %76 %77 -; CHECK: %76 = OpLabel -; CHECK: %78 = OpLoad %39 %65 -; CHECK: %79 = OpImageSampleImplicitLod %v4float %78 %53 -; CHECK: OpBranch %75 -; CHECK: %77 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_49 %uint_0 %uint_4 %uint_11 %64 %uint_128 -; CHECK: OpBranch %75 -; CHECK: %75 = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float %79 %76 [[null_v4float]] %77 +; 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+}} OpReturn OpFunctionEnd )"; - const std::string output_func = kStreamWrite6Frag; + const std::string output_func = kStreamWrite6 + kCheckDesc; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + output_func, - true, 7u, 23u, false, false, - false, false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, InstrumentImageWrite) { @@ -1061,7 +740,7 @@ OpDecorate %PerViewConstantBuffer_t Block OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %3 = OpTypeFunction %void @@ -1087,11 +766,12 @@ 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 )"; // clang-format on @@ -1107,28 +787,32 @@ OpImageWrite %66 %53 %80 OpStore %_entryPointOutput_vColor %80 ; CHECK-NOT: OpImageWrite %66 %53 %80 ; CHECK-NOT: OpStore %_entryPointOutput_vColor %80 -; CHECK: %35 = OpULessThan %bool %30 %uint_128 -; CHECK: OpSelectionMerge %36 None -; CHECK: OpBranchConditional %35 %37 %38 -; CHECK: %37 = OpLabel -; CHECK: %39 = OpLoad %16 %31 -; CHECK: OpImageWrite %39 %28 %19 -; CHECK: OpBranch %36 -; CHECK: %38 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_30 %uint_2 %30 %uint_128 -; CHECK: OpBranch %36 -; CHECK: %36 = OpLabel +; 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 OpReturn OpFunctionEnd )"; - const std::string output_func = kStreamWrite6Frag; + const std::string output_func = kStreamWrite6 + kCheckDesc; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + output_func, - true, 7u, 23u, false, false, - false, false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, InstrumentVertexSimple) { @@ -1160,7 +844,7 @@ OpMemberName %foo 0 "g_idx" OpName %__0 "" OpName %coords2D "coords2D" ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex ; CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex OpMemberDecorate %gl_PerVertex 0 BuiltIn Position @@ -1205,9 +889,8 @@ OpDecorate %coords2D Location 0 %v2float = OpTypeVector %float 2 %_ptr_Input_v2float = OpTypePointer Input %v2float %coords2D = OpVariable %_ptr_Input_v2float Input -; CHECK: %bool = OpTypeBool ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kOutputGlobals + R"( +)" + 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 @@ -1235,31 +918,49 @@ 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: %46 = OpULessThan %bool %37 %uint_128 -; CHECK: OpSelectionMerge %47 None -; CHECK: OpBranchConditional %46 %48 %49 -; CHECK: %48 = OpLabel -; CHECK: %50 = OpLoad %25 %38 -; CHECK: %51 = OpImageSampleExplicitLod %v4float %50 %40 Lod %41 -; CHECK: OpBranch %47 -; CHECK: %49 = OpLabel -; CHECK: {{%\w+}} = OpBitcast %uint %37 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_74 %uint_0 %uint_2 %uint_13 {{%\w+}} %uint_128 -; CHECK: OpBranch %47 -; CHECK: %47 = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float %51 %48 [[null_v4float]] %49 +; 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+}} OpReturn OpFunctionEnd )"; - const std::string output_func = kStreamWrite6Vert; + const std::string output_func = kStreamWrite6 + kCheckDesc; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + output_func, - true, 7u, 23u, false, false, - false, false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, InstrumentTeseSimple) { @@ -1320,7 +1021,7 @@ OpDecorate %ufoo Block OpDecorate %uniform_index_buffer DescriptorSet 9 OpDecorate %uniform_index_buffer Binding 2 ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId ; CHECK: OpDecorate %gl_TessCoord BuiltIn TessCoord %void = OpTypeVoid @@ -1346,9 +1047,8 @@ 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: %bool = OpTypeBool ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kOutputGlobals + R"( +)" + 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 @@ -1368,31 +1068,52 @@ OpDecorate %uniform_index_buffer Binding 2 %28 = OpAccessChain %_ptr_StorageBuffer_v4float %adds %26 %int_0 %29 = OpLoad %v4float %28 ; CHECK-NOT: %29 = OpLoad %v4float %28 -; CHECK: %34 = OpULessThan %bool %28 %uint_11 -; CHECK: OpSelectionMerge %35 None -; CHECK: OpBranchConditional %34 %36 %37 -; CHECK: %36 = OpLabel -; CHECK: %38 = OpLoad %v4float %29 -; CHECK: OpBranch %35 -; CHECK: %37 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_63 %uint_0 %uint_9 %uint_1 %28 %uint_11 -; CHECK: OpBranch %35 -; CHECK: %35 = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float %38 %36 [[null_v4float]] %37 +; 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+}} %31 = OpAccessChain %_ptr_Output_v4float %_ %int_0 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: OpStore %31 {{%\w+}} +; 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]] OpReturn OpFunctionEnd )"; - const std::string output_func = kStreamWrite6Tese; + const std::string output_func = kStreamWrite6 + kCheckDesc; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch(defs + main_func + output_func, - true, 7u, 23u, false, false, - false, false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, MultipleDebugFunctions) { @@ -1436,7 +1157,7 @@ OpDecorate %g_sAniso Binding 3 OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %4 = OpTypeFunction %void @@ -1471,13 +1192,11 @@ 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: %bool = OpTypeBool ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kOutputGlobals + R"( +)" + 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: %v4uint = OpTypeVector %uint 4 ; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -1516,23 +1235,27 @@ OpLine %1 24 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: %62 = OpULessThan %bool %50 %uint_128 -; CHECK: OpSelectionMerge %63 None -; CHECK: OpBranchConditional %62 %64 %65 -; CHECK: %64 = OpLabel -; CHECK: %66 = OpLoad %27 %51 -; CHECK: %67 = OpSampledImage %37 %66 %53 +; 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: %68 = OpImageSampleImplicitLod %v4float %67 %56 +; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} {{%\w+}} ; CHECK: OpNoLine -; CHECK: OpBranch %63 -; CHECK: %65 = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_109 %uint_0 %uint_1 %uint_2 %50 %uint_128 -; CHECK: OpBranch %63 -; CHECK: %63 = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %v4float %68 %64 [[null_v4float]] %65 -; CHECK: OpLine %5 24 0 +; 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 @@ -1544,12 +1267,11 @@ OpReturnValue %48 OpFunctionEnd )"; - const std::string output_func = kStreamWrite6Frag; + const std::string output_func = kStreamWrite6 + kCheckDesc; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch( - defs + func1 + func2 + output_func, true, 7u, 23u, false, false, false, - false, false); + defs + func1 + func2 + output_func, true, 7u, 23u); } TEST_F(InstBindlessTest, RuntimeArray) { @@ -1617,7 +1339,6 @@ OpDecorate %_entryPointOutput_vColor Location 0 )" + kInputGlobals + kOutputGlobals + R"( ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -; CHECK: %v4uint = OpTypeVector %uint 4 ; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -1636,45 +1357,33 @@ OpDecorate %_entryPointOutput_vColor Location 0 OpStore %_entryPointOutput_vColor %71 ; CHECK-NOT: %71 = OpImageSampleImplicitLod %v4float %68 %53 ; CHECK-NOT: OpStore %_entryPointOutput_vColor %71 -; CHECK: [[length_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_1 %uint_2 -; CHECK: {{%\w+}} = OpULessThan %bool %32 [[length_result]] -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %16 %33 -; CHECK: {{%\w+}} = OpSampledImage %26 {{%\w+}} %35 -; CHECK: [[state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %32 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[state_result]] +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_59 %uint_1 %uint_1 %uint_2 %32 %uint_0 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %30 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_59 %uint_0 %uint_1 %uint_2 %32 {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float [[phi_result_1]] {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: OpStore %_entryPointOutput_vColor [[phi_result_2]] +; 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 = - kReadBindingLength + kStreamWrite6Frag + kReadDescInit; + 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, true, true, false, - false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, InstrumentInitCheckOnScalarDescriptor) { @@ -1726,9 +1435,6 @@ OpDecorate %_entryPointOutput_vColor Location 0 %_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: %v4uint = OpTypeVector %uint 4 ; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -1744,17 +1450,15 @@ OpDecorate %_entryPointOutput_vColor Location 0 OpStore %_entryPointOutput_vColor %24 ; CHECK-NOT: %24 = OpImageSampleImplicitLod %v4float %23 %20 ; CHECK-NOT: OpStore %_entryPointOutput_vColor %24 -; CHECK: [[state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[state_result]] +; 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 {{%\w+}} {{%\w+}} {{%\w+}} +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_39 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} @@ -1763,12 +1467,11 @@ OpReturn OpFunctionEnd )"; - const std::string new_funcs = kReadDescInit + kStreamWrite6Frag; + 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, true, true, false, - false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, SPV14AddToEntryPoint) { @@ -1824,8 +1527,7 @@ OpFunctionEnd )"; SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4); - SinglePassRunAndMatch(text, true, 7u, 23u, true, true, - false, false, false); + SinglePassRunAndMatch(text, true, 7u, 23u); } TEST_F(InstBindlessTest, SPV14AddToEntryPoints) { @@ -1883,8 +1585,7 @@ OpFunctionEnd )"; SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4); - SinglePassRunAndMatch(text, true, 7u, 23u, true, true, - false, false, false); + SinglePassRunAndMatch(text, true, 7u, 23u); } TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedUBOArray) { @@ -1932,10 +1633,9 @@ OpDecorate %nu_ii Location 0 OpDecorate %nu_ii NonUniform OpDecorate %16 NonUniform OpDecorate %20 NonUniform -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + R"( ; CHECK: OpDecorate {{%\w+}} NonUniform -)" + kOutputDecorations + R"( +; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 +)" + kInputDecorations + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord ; CHECK: OpDecorate {{%\w+}} NonUniform %void = OpTypeVoid @@ -1952,11 +1652,12 @@ OpDecorate %20 NonUniform %nu_ii = OpVariable %_ptr_Input_int Input %int_0 = OpConstant %int 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -)" + kInputGlobals + kOutputGlobals + R"( +)" + 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: %v4uint = OpTypeVector %uint 4 ; CHECK: [[null_float:%\w+]] = OpConstantNull %float )"; // clang-format on @@ -1970,44 +1671,32 @@ OpDecorate %20 NonUniform OpStore %b %20 ; CHECK-NOT: %20 = OpLoad %float %19 ; CHECK-NOT: OpStore %b %20 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_6 %uint_3 -; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel +; 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 %uint %inst_bindless_read_desc_init %uint_6 %uint_3 {{%\w+}} -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; 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: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_1 %uint_6 %uint_3 {{%\w+}} %uint_0 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_0 %uint_6 %uint_3 [[bitcast_result]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}} -; CHECK: OpStore %b [[phi_result_2]] +; CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: OpStore %b [[phi_result]] OpReturn OpFunctionEnd )"; - const std::string new_funcs = - kReadBindingLength + kStreamWrite6Frag + kReadDescInit; + 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, true, true, false, - false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArrayDeprecated) { @@ -2074,11 +1763,12 @@ OpDecorate %20 NonUniform %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float ; CHECK: %uint = OpTypeInt 32 0 ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + kOutputGlobals + R"( +)" + 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: %v4uint = OpTypeVector %uint 4 ; CHECK: [[null_float:%\w+]] = OpConstantNull %float )"; // clang-format on @@ -2092,44 +1782,32 @@ OpDecorate %20 NonUniform OpStore %b %20 ; CHECK-NOT: %20 = OpLoad %float %19 ; CHECK-NOT: OpStore %b %20 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_7 %uint_3 -; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[bitcast_result_1:%\w+]] = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_7 %uint_3 [[bitcast_result_1]] -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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+}} = 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: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_1 %uint_7 %uint_3 {{%\w+}} %uint_0 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: [[bitcast_result_2:%\w+]] = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_0 %uint_7 %uint_3 [[bitcast_result_2]] {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}} -; CHECK: OpStore %b [[phi_result_2]] +; CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: OpStore %b [[phi_result]] OpReturn OpFunctionEnd )"; - const std::string new_funcs = - kReadBindingLength + kStreamWrite6Frag + kReadDescInit; + 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, true, true, false, - false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArray) { @@ -2166,10 +1844,9 @@ OpDecorate %nu_ii Location 0 OpDecorate %nu_ii NonUniform OpDecorate %16 NonUniform OpDecorate %20 NonUniform -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + R"( ; CHECK: OpDecorate {{%\w+}} NonUniform -)" + kOutputDecorations + R"( +; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 +)" + kInputDecorations + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord ; CHECK: OpDecorate {{%\w+}} NonUniform %void = OpTypeVoid @@ -2186,11 +1863,12 @@ OpDecorate %20 NonUniform %nu_ii = OpVariable %_ptr_Input_int Input %int_0 = OpConstant %int 0 %_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float -)" + kInputGlobals + kOutputGlobals + R"( +)" + 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: %v4uint = OpTypeVector %uint 4 ; CHECK: [[null_float:%\w+]] = OpConstantNull %float )"; // clang-format on @@ -2204,44 +1882,32 @@ OpDecorate %20 NonUniform OpStore %b %20 ; CHECK-NOT: %20 = OpLoad %float %19 ; CHECK-NOT: OpStore %b %20 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_0 %uint_3 -; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel +; 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 %uint %inst_bindless_read_desc_init %uint_0 %uint_3 {{%\w+}} -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; 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: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_1 %uint_0 %uint_3 {{%\w+}} %uint_0 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[bitcast_result:%\w+]] = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_0 %uint_0 %uint_3 [[bitcast_result]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}} -; CHECK: OpStore %b [[phi_result_2]] +; CHECK: {{%\w+}} = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: OpStore %b {{%\w+}} OpReturn OpFunctionEnd )"; - const std::string new_funcs = - kReadBindingLength + kStreamWrite6Frag + kReadDescInit; + 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, true, true, false, - false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, InstInitLoadUBOScalar) { @@ -2296,11 +1962,12 @@ OpDecorate %uniformBuffer Binding 3 ; CHECK: %_ptr_Uniform_float = OpTypePointer Uniform %float ; CHECK: %uint = OpTypeInt 32 0 ; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kInputGlobals + kOutputGlobals + R"( +)" + 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: %v4uint = OpTypeVector %uint 4 ; CHECK: [[null_float:%\w+]] = OpConstantNull %float )"; // clang-format on @@ -2313,29 +1980,31 @@ OpDecorate %uniformBuffer Binding 3 OpStore %b %16 ; CHECK-NOT: %16 = OpLoad %float %15 ; CHECK-NOT: OpStore %b %16 -; CHECK: [[check_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_7 %uint_3 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[check_result]] +; 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 {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: OpBranchConditional [[check_result]] {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpLoad %float %15 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_32 %uint_1 %uint_7 %uint_3 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}} +; CHECK: [[phi_result:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: OpStore %b [[phi_result]] OpReturn OpFunctionEnd )"; - const std::string new_funcs = kReadDescInit + kStreamWrite6Frag; + 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, true, true, false, - false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, InstBoundsInitStoreUnsizedSSBOArray) { @@ -2398,9 +2067,10 @@ OpDecorate %b Location 1 %_ptr_Input_float = OpTypePointer Input %float %b = OpVariable %_ptr_Input_float Input %_ptr_Uniform_float = OpTypePointer Uniform %float -)" + kInputGlobals + kOutputGlobals + R"( -; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input +)" + kInputGlobals + R"( ; CHECK: %v4uint = OpTypeVector %uint 4 +)" + kOutputGlobals + R"( +; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input )"; // clang-format on @@ -2412,41 +2082,30 @@ OpDecorate %b Location 1 %20 = OpAccessChain %_ptr_Uniform_float %storageBuffer %14 %int_0 OpStore %20 %18 ; CHECK-NOT: OpStore %20 %18 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_5 %uint_4 -; CHECK: {{%\w+}} = OpULessThan %bool %7 {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel +; 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 %uint %inst_bindless_read_desc_init %uint_5 %uint_4 {{%\w+}} -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; 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 {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: OpBranchConditional [[check_result]] {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: OpStore %20 %19 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_1 %uint_5 %uint_4 {{%\w+}} %uint_0 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_45 %uint_0 %uint_5 %uint_4 {{%\w+}} {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - const std::string new_funcs = - kReadBindingLength + kStreamWrite6Frag + kReadDescInit; + 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, true, true, false, - false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, InstBoundsInitLoadSizedUBOArray) { @@ -2494,9 +2153,8 @@ OpDecorate %nu_ii NonUniform OpDecorate %18 NonUniform OpDecorate %22 NonUniform ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -)" + kInputDecorations + R"( ; CHECK: OpDecorate [[load_result:%\w+]] NonUniform %void = OpTypeVoid %3 = OpTypeFunction %void @@ -2514,13 +2172,11 @@ OpDecorate %22 NonUniform %nu_ii = OpVariable %_ptr_Input_int Input %int_0 = OpConstant %int 0 %_ptr_Uniform_float = OpTypePointer Uniform %float -)" + kOutputGlobals + R"( -; CHECK: %v4float = OpTypeVector %float 4 +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float ; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -; CHECK: %v4uint = OpTypeVector %uint 4 ; CHECK: [[null_float:%\w+]] = OpConstantNull %float -)" + kInputGlobals; +)"; // clang-format on const std::string main_func = R"( @@ -2532,42 +2188,32 @@ OpDecorate %22 NonUniform OpStore %b %22 ; CHECK-NOT: %22 = OpLoad %float %21 ; CHECK-NOT: OpStore %b %22 -; CHECK: {{%\w+}} = OpULessThan %bool %7 %uint_128 -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel +; 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 %uint %inst_bindless_read_desc_init %uint_1 %uint_3 {{%\w+}} -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; 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: [[load_result]] = OpLoad %float %22 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_46 %uint_1 %uint_1 %uint_3 {{%\w+}} %uint_0 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result_1:%\w+]] = OpPhi %float {{%\w+}} {{%\w+}} [[null_float]] {{%\w+}} +; CHECK: {{%\w+}} = OpLoad %float %22 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpBitcast %uint %7 -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_46 %uint_0 %uint_1 %uint_3 {{%\w+}} %uint_128 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result_2:%\w+]] = OpPhi %float [[phi_result_1]] {{%\w+}} [[null_float]] {{%\w+}} -; CHECK: OpStore %b [[phi_result_2]] +; CHECK: {{%\w+}} = OpPhi %float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} +; CHECK: OpStore %b {{%\w+}} OpReturn OpFunctionEnd )"; - const std::string new_funcs = kStreamWrite6Frag + kReadDescInit; + 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, true, true, false, - false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, @@ -2644,8 +2290,8 @@ OpDecorate %images NonWritable ; CHECK: %v3uint = OpTypeVector %uint 3 ; CHECK: %_ptr_Input_v3uint = OpTypePointer Input %v3uint ; CHECK: %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float ; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -2661,69 +2307,64 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_0 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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_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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_47 %uint_1 %uint_2 %uint_0 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result_1:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} -; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} -; CHECK: %28 = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_2 %uint_1 -; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_1 [[phi_result_1]] -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; 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 %27 +; CHECK: {{%\w+}} = OpLoad %13 {{%\w+}} ; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_50 %uint_1 %uint_2 %uint_1 {{%\w+}} %uint_0 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_50 %uint_0 %uint_2 %uint_1 {{%\w+}} {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float [[phi_result_2]] {{%\w+}} [[null_v4float]] {{%\w+}} +; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpCompositeExtract %float {{%\w+}} 0 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_Uniform_float %sbo %int_1 -; CHECK: [[desc_state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_0 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 [[desc_state_result]] +; 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 {{%\w+}} {{%\w+}} +; CHECK: OpStore %31 {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_53 %uint_1 %uint_2 %uint_0 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - const std::string new_funcs = - kReadBindingLength + kStreamWrite6Compute + kReadDescInit; + 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, true, true, false, - false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, @@ -2797,8 +2438,8 @@ OpDecorate %images NonWritable %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float )" + kInputGlobals + kOutputGlobals + R"( -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float ; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -2814,69 +2455,64 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_3 %uint_1 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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_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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_3 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} -; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} -; CHECK: %28 = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_3 %uint_5 -; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_3 %uint_5 {{%\w+}} -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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 %27 +; CHECK: {{%\w+}} = OpLoad %13 {{%\w+}} ; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_3 %uint_5 {{%\w+}} %uint_0 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_3 %uint_5 {{%\w+}} {{%\w+}} ; 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+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_3 %uint_1 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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 %31 %30 +; CHECK: OpStore {{%\w+}} {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_3 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - const std::string new_funcs = - kReadBindingLength + kStreamWrite6Ray + kReadDescInit; + 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, true, true, false, - false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, @@ -2951,8 +2587,8 @@ OpDecorate %images NonWritable %_ptr_Uniform_float = OpTypePointer Uniform %float )" + kInputGlobals + kOutputGlobals + R"( ; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float ; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -2968,69 +2604,63 @@ OpDecorate %images NonWritable %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 OpStore %31 %29 ; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_5 %uint_1 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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_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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_5 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} -; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} -; CHECK: %28 = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_5 %uint_3 -; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_5 %uint_3 {{%\w+}} -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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 %27 +; CHECK: {{%\w+}} = OpLoad %13 {{%\w+}} ; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_5 %uint_3 {{%\w+}} %uint_0 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_5 %uint_3 {{%\w+}} {{%\w+}} ; 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+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_5 %uint_1 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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 %30 +; CHECK: OpStore %31 {{%\w+}} ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_5 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - const std::string new_funcs = - kReadBindingLength + kStreamWrite6Ray + kReadDescInit; + 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, true, true, false, - false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, @@ -3105,8 +2735,8 @@ OpDecorate %images NonWritable %_ptr_Uniform_float = OpTypePointer Uniform %float )" + kInputGlobals + kOutputGlobals + R"( ; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float ; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -3121,29 +2751,36 @@ 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+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_1 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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_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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_2 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} -; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} +; 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+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_2 %uint_3 -; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_3 {{%\w+}} -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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_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 @@ -3151,40 +2788,34 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_2 %uint_3 {{%\w+}} %uint_0 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_2 %uint_3 {{%\w+}} {{%\w+}} ; 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+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_2 %uint_1 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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_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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_2 %uint_1 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - const std::string new_funcs = - kReadBindingLength + kStreamWrite6Ray + kReadDescInit; + 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, true, true, false, - false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, @@ -3259,8 +2890,8 @@ OpDecorate %images NonWritable %_ptr_Uniform_float = OpTypePointer Uniform %float )" + kInputGlobals + kOutputGlobals + R"( ; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float ; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -3275,29 +2906,36 @@ 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+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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_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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0 ; 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+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_1 %uint_3 -; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_3 {{%\w+}} -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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_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 @@ -3305,40 +2943,34 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_1 %uint_3 {{%\w+}} %uint_0 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_1 %uint_3 {{%\w+}} {{%\w+}} ; 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+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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_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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_1 %uint_2 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - const std::string new_funcs = - kReadBindingLength + kStreamWrite6Ray + kReadDescInit; + 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, true, true, false, - false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, @@ -3413,8 +3045,8 @@ OpDecorate %images NonWritable %_ptr_Uniform_float = OpTypePointer Uniform %float )" + kInputGlobals + kOutputGlobals + R"( ; CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float ; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -3429,29 +3061,33 @@ 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+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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_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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0 ; 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+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_1 %uint_3 -; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_3 {{%\w+}} -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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_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 @@ -3459,40 +3095,34 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_1 %uint_3 {{%\w+}} %uint_0 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_1 %uint_3 {{%\w+}} {{%\w+}} ; 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+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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_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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - const std::string new_funcs = - kReadBindingLength + kStreamWrite6Ray + kReadDescInit; + 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, true, true, false, - false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, @@ -3566,8 +3196,8 @@ OpDecorate %images NonWritable %uint_0 = OpConstant %uint 0 %_ptr_Uniform_float = OpTypePointer Uniform %float )" + kInputGlobals + kOutputGlobals + R"( -; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float ; CHECK: [[null_uint:%\w+]] = OpConstantNull %uint +; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float )"; // clang-format on @@ -3580,31 +3210,33 @@ OpDecorate %images NonWritable %23 = OpLoad %13 %22 %27 = OpImageRead %v4float %23 %25 %29 = OpCompositeExtract %float %27 0 -%31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 -OpStore %31 %29 -; CHECK-NOT: OpStore %31 %29 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_48 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} ; CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images {{%\w+}} -; CHECK: %28 = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_binding_length %uint_1 %uint_3 -; CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\w+}} -; CHECK: OpSelectionMerge {{%\w+}} None -; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpLoad %13 %27 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_3 {{%\w+}} -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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 @@ -3612,40 +3244,38 @@ OpStore %31 %29 ; CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_1 %uint_1 %uint_3 {{%\w+}} %uint_0 -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_51 %uint_0 %uint_1 %uint_3 {{%\w+}} {{%\w+}} ; 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+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +%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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_54 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel OpReturn OpFunctionEnd )"; - const std::string new_funcs = - kReadBindingLength + kStreamWrite6Ray + kReadDescInit; + 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, true, true, false, - false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, InstBoundsInitSameBlockOpReplication) { @@ -3715,11 +3345,11 @@ OpDecorate %Uniforms Block OpDecorate %uniforms DescriptorSet 1 OpDecorate %uniforms Binding 0 OpDecorate %outColor Location 0 -; CHECK: OpDecorate %63 NonUniform +; CHECK: OpDecorate {{%\w+}} NonUniform +; CHECK: OpDecorate {{%\w+}} NonUniform ; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -)" + kInputDecorations + R"( ; CHECK: OpDecorate [[desc_state_result:%\w+]] NonUniform %void = OpTypeVoid %3 = OpTypeFunction %void @@ -3752,9 +3382,8 @@ OpDecorate %outColor Location 0 %_ptr_Output_v4float = OpTypePointer Output %v4float %outColor = OpVariable %_ptr_Output_v4float Output %float_0 = OpConstant %float 0 -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -)" + kInputGlobals + R"( ; CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float )"; // clang-format on @@ -3774,6 +3403,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+}} OpStore %x %36 %39 = OpLoad %13 %uniformTex %40 = OpLoad %23 %uniformSampler @@ -3782,25 +3431,36 @@ OpStore %x %36 %47 = OpAccessChain %_ptr_Uniform_v2float %uniforms %int_0 %48 = OpLoad %v2float %47 %49 = OpFMul %v2float %42 %48 -%50 = OpImageSampleImplicitLod %v4float %41 %49 -%51 = OpCompositeExtract %float %50 0 -; CHECK-NOT: %51 = OpCompositeExtract %float %50 0 -; CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_0 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_87 %uint_1 %uint_1 %uint_0 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} -; CHECK: %49 = OpFMul %v2float %42 {{%\w+}} +; 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+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 %uint_0 -; CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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 %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 @@ -3809,7 +3469,6 @@ OpStore %x %36 ; CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %49 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_89 %uint_1 %uint_1 %uint_2 %uint_0 %uint_0 ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} @@ -3823,12 +3482,11 @@ OpReturn OpFunctionEnd )"; - const std::string new_funcs = kStreamWrite6Frag + kReadDescInit; + 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, true, true, false, - false, false); + true, 7u, 23u); } TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { @@ -3936,18 +3594,14 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output - )" + kInputGlobals + kOutputGlobals + R"( + )" + 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: %v4uint = OpTypeVector %uint 4 ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float %MainPs = OpFunction %void None %3 %5 = OpLabel - ;CHECK: [[desc_state_result:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_1 %uint_0 - ;CHECK: OpBranch %117 - ;CHECK: %117 = OpLabel - ;CHECK: OpBranch %116 - ;CHECK: %116 = OpLabel %69 = OpLoad %v2float %i_vTextureCoords %82 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 %83 = OpLoad %uint %82 @@ -3958,15 +3612,20 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { %86 = OpAccessChain %_ptr_Uniform_v2float %__0 %int_0 %87 = OpLoad %v2float %86 ;CHECK-NOT: %87 = OpLoad %v2float %86 - ;CHECK: %119 = OpIAdd %uint %uint_0 %uint_7 - ;CHECK: {{%\w+}} = OpULessThan %bool %119 [[desc_state_result]] + ;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 {{%\w+}} {{%\w+}} {{%\w+}} + ;CHECK: OpBranchConditional [[desc_state_result]] {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpLoad %v2float %86 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel - ;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_71 %uint_4 %uint_0 %uint_1 %uint_0 %119 {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} @@ -3976,14 +3635,18 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { %90 = OpLoad %v2float %89 ;CHECK-NOT: %90 = OpLoad %v2float %89 ;CHECK: {{%\w+}} = OpIAdd %uint %uint_8 %uint_7 - ;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\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 %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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_75 %uint_4 %uint_0 %uint_1 %uint_0 {{%\w+}} {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} @@ -4000,13 +3663,12 @@ TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { OpStore %_entryPointOutput_vColor %100 OpReturn OpFunctionEnd -)" + kReadDescInit + kStreamWrite7Frag; +)" + kStreamWrite6 + kCheckDesc; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u, false, - false, true, false, true); + SinglePassRunAndMatch(text, true, 7u, 23u); } TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { @@ -4123,18 +3785,14 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -)" + kInputGlobals + kOutputGlobals + R"( +)" + 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: %v4uint = OpTypeVector %uint 4 ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float %MainPs = OpFunction %void None %3 %5 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_2 %uint_0 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel %66 = OpLoad %v2float %i_vTextureCoords %79 = OpAccessChain %_ptr_PushConstant_uint %__0 %int_0 %80 = OpLoad %uint %79 @@ -4145,14 +3803,18 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { ;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64 ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 -;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\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 %bool %inst_bindless_desc_check %uint_23 %uint_79 {{%\w+}} %uint_0 %uint_2 %uint_0 {{%\w+}} ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpLoad %v2float %81 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_78 %uint_4 %uint_0 %uint_2 %uint_0 {{%\w+}} {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} @@ -4166,13 +3828,12 @@ TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { OpStore %_entryPointOutput_vColor %91 OpReturn OpFunctionEnd -)" + kReadDescInit + kStreamWrite7Frag; +)" + kStreamWrite6 + kCheckDesc; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u, false, - false, true, false, true); + SinglePassRunAndMatch(text, true, 7u, 23u); } TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { @@ -4260,20 +3921,15 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -)" + kInputGlobals + kOutputGlobals + R"( +)" + 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: %v4uint = OpTypeVector %uint 4 ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float ;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float %MainPs = OpFunction %void None %3 %5 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_2 %uint_0 -;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel %66 = OpLoad %v2float %i_vTextureCoords %79 = OpAccessChain %_ptr_PushConstant_uint %__0 %int_0 %80 = OpLoad %uint %79 @@ -4286,14 +3942,18 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64 ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 -;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\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 %bool %inst_bindless_desc_check %uint_23 %uint_79 {{%\w+}} %uint_0 %uint_2 %uint_0 {{%\w+}} ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpLoad %v2float %81 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_78 %uint_4 %uint_0 %uint_2 %uint_0 {{%\w+}} {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} @@ -4305,7 +3965,12 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { OpStore %_entryPointOutput_vColor %91 ;CHECK-NOT: %91 = OpImageSampleImplicitLod %v4float %89 %86 ;CHECK-NOT: OpStore %_entryPointOutput_vColor %91 -;CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\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 %bool %inst_bindless_desc_check %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 @@ -4314,20 +3979,18 @@ TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { ;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %86 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_83 %uint_1 %uint_0 %uint_0 %uint_0 %uint_0 %uint_0 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} ;CHECK: OpStore %_entryPointOutput_vColor {{%\w+}} OpReturn OpFunctionEnd -)" + kReadDescInit + kStreamWrite7Frag; +)" + kStreamWrite6 + kCheckDesc; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u, true, true, - true, false, true); + SinglePassRunAndMatch(text, true, 7u, 23u); } TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { @@ -4341,11 +4004,11 @@ TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { OpCapability Shader OpCapability Int16 OpCapability StoragePushConstant16 -;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" +;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_output_buffer %gl_FragCoord %inst_bindless_input_buffer +;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" @@ -4364,10 +4027,9 @@ TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { OpDecorate %g_sAniso Binding 2 OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 -;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -)" + kInputDecorations + R"( +;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 +)" + kInputDecorations + kOutputDecorations + R"( +;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %10 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -4395,17 +4057,14 @@ TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { %i_vTextureCoords = OpVariable %_ptr_Input_v2float Input %_ptr_Output_v4float = OpTypePointer Output %v4float %_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ;CHECK:%_ptr_Input_v4float = OpTypePointer Input %v4float ;CHECK:%gl_FragCoord = OpVariable %_ptr_Input_v4float Input ;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -)" + kInputGlobals + R"( %MainPs = OpFunction %void None %10 %30 = OpLabel -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: OpBranch %39 -;CHECK: %39 = OpLabel +;CHECK: OpBranch %39 +;CHECK: %39 = OpLabel %31 = OpLoad %v2float %i_vTextureCoords %32 = OpAccessChain %_ptr_PushConstant_ushort %_ %int_0 %33 = OpLoad %ushort %32 @@ -4417,45 +4076,33 @@ TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { OpStore %_entryPointOutput_vColor %38 ;CHECK-NOT: %38 = OpImageSampleImplicitLod %v4float %37 %31 ;CHECK-NOT: OpStore %_entryPointOutput_vColor %38 -;CHECK: %41 = OpUConvert %uint %33 -;CHECK: {{%\w+}} = OpULessThan %bool %41 %uint_128 -;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpLoad %16 %34 -;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %36 -;CHECK: {{%\w+}} = OpUConvert %uint %33 -;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_1 %uint_2 {{%\w+}} -;CHECK: {{%\w+}} = OpULessThan %bool %uint_0 {{%\w+}} -;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpLoad %16 %34 -;CHECK: {{%\w+}} = OpSampledImage %27 {{%\w+}} %36 -;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %31 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpUConvert %uint %33 -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_60 %uint_1 %uint_1 %uint_2 {{%\w+}} %uint_0 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: [[phi_result_1:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -;CHECK: OpBranch %44 -;CHECK: %46 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 %uint_60 %uint_0 %uint_1 %uint_2 %41 %uint_128 -;CHECK: OpBranch %44 -;CHECK: %44 = OpLabel -;CHECK: [[phi_result_2:%\w+]] = OpPhi %v4float [[phi_result_1]] {{%\w+}} [[null_v4float]] %46 -;CHECK: OpStore %_entryPointOutput_vColor [[phi_result_2]] +;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: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %16 %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: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} +;CHECK: OpStore %_entryPointOutput_vColor [[phi_result]] OpReturn OpFunctionEnd -)" + kStreamWrite6Frag + kReadDescInit; +)" + kStreamWrite6 + kCheckDesc; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u, true, true, - false, false, true); + SinglePassRunAndMatch(text, true, 7u, 23u); } TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { @@ -4582,11 +4229,6 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float %MainPs = OpFunction %void None %14 %37 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel %38 = OpLoad %v2float %i_vTextureCoords %39 = OpAccessChain %_ptr_PushConstant_ushort %__0 %int_0 %40 = OpLoad %ushort %39 @@ -4600,14 +4242,18 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { ;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64 ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 -;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\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 %bool %inst_bindless_desc_check %uint_23 %uint_82 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpLoad %v2float %41 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_81 %uint_4 %uint_0 %uint_0 %uint_0 {{%\w+}} {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: {{%\w+}} = OpPhi %v2float {{%\w+}} {{%\w+}} [[null_v2float]] {{%\w+}} @@ -4619,13 +4265,12 @@ TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { OpStore %_entryPointOutput_vColor %47 OpReturn OpFunctionEnd - )" + kReadDescInit + kStreamWrite7Frag; + )" + kStreamWrite6 + kCheckDesc; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u, false, - false, true, false, true); + SinglePassRunAndMatch(text, true, 7u, 23u); } TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { @@ -4678,11 +4323,10 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision OpDecorate %a_position Location 0 ;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + R"( -;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + 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 @@ -4709,9 +4353,6 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;CHECK: [[null_float:%\w+]] = OpConstantNull %float %main = OpFunction %void None %3 %5 = OpLabel -;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel %20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1 @@ -4722,14 +4363,16 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;CHECK: {{%\w+}} = OpIMul %uint %uint_16 %uint_1 ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 -;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} [[desc_state]] +;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: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: OpBranchConditional [[desc_state]] {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[load_result]] = OpLoad %float %20 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_45 %uint_4 %uint_0 %uint_0 %uint_0 {{%\w+}} {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[phi_result]] = OpPhi %float [[load_result]] {{%\w+}} [[null_float]] {{%\w+}} @@ -4738,13 +4381,12 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;CHECK: OpStore %v_vtxResult [[phi_result]] OpReturn OpFunctionEnd - )" + kReadDescInit + kStreamWrite7Vert; + )" + kStreamWrite6 + kCheckDesc; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u, false, - false, true, false, true); + SinglePassRunAndMatch(text, true, 7u, 23u); } TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { @@ -4797,11 +4439,10 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { ;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision OpDecorate %a_position Location 0 ;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + R"( -;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + 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 @@ -4828,43 +4469,41 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { ;CHECK: [[null_float:%\w+]] = OpConstantNull %float %main = OpFunction %void None %3 %5 = OpLabel -;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 -;CHECK: OpBranch %26 -;CHECK: %26 = OpLabel -;CHECK: OpBranch %25 -;CHECK: %25 = OpLabel %20 = OpAccessChain %_ptr_Uniform_float %_ %int_0 %int_2 %uint_1 %21 = OpLoad %float %20 -;CHECK-NOT: %21 = OpLoad %float %20 -;CHECK: %29 = OpIMul %uint %uint_8 %int_2 -;CHECK: %30 = OpIAdd %uint %uint_0 %29 -;CHECK: %32 = OpIMul %uint %uint_4 %uint_1 -;CHECK: %33 = OpIAdd %uint %30 %32 -;CHECK: %35 = OpIAdd %uint %33 %uint_3 -;CHECK: {{%\w+}} = OpULessThan %bool %35 [[desc_state]] +;CHECK-NOT: %21 = OpLoad %float %20 +;CHECK: OpBranch {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpIMul %uint %uint_8 %int_2 +;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} +;CHECK: {{%\w+}} = OpIMul %uint %uint_4 %uint_1 +;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 +;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: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: OpBranchConditional [[desc_state]] {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK:[[load_result]] = OpLoad %float %20 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_45 %uint_4 %uint_0 %uint_0 %uint_0 %35 {{%\w+}} ;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-NOT: OpStore %v_vtxResult %21 ;CHECK: OpStore %v_vtxResult [[phi_result]] OpReturn OpFunctionEnd - )" + kReadDescInit + kStreamWrite7Vert; + )" + kStreamWrite6 + kCheckDesc; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); ValidatorOptions()->uniform_buffer_standard_layout = true; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u, false, - false, true, false, true); + SinglePassRunAndMatch(text, true, 7u, 23u); } TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { @@ -4917,11 +4556,10 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { ;CHECK: OpDecorate [[phi_result:%\w+]] RelaxedPrecision OpDecorate %a_position Location 0 ;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kInputDecorations + R"( -;CHECK: OpDecorate [[load_result:%\w+]] RelaxedPrecision -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + 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 @@ -4953,44 +4591,40 @@ TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { ;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float %main = OpFunction %void None %3 %5 = OpLabel -;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_3 %uint_7 %uint_0 -;CHECK: OpBranch %31 -;CHECK: %31 = OpLabel -;CHECK: OpBranch %30 -;CHECK: %30 = 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 +;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpIMul %uint %uint_4 %int_1 +;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_19 +;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-NOT: %26 = OpLoad %v2float %25 ;CHECK-NOT: OpStore %v_vtxResult %26 -;CHECK: %34 = OpIMul %uint %uint_128 %int_2 -;CHECK: %35 = OpIAdd %uint %uint_0 %34 -;CHECK: %37 = OpIMul %uint %uint_32 %int_3 -;CHECK: %38 = OpIAdd %uint %35 %37 -;CHECK: %40 = OpIMul %uint %uint_4 %int_1 -;CHECK: %41 = OpIAdd %uint %38 %40 -;CHECK: %43 = OpIAdd %uint %41 %uint_19 -;CHECK: {{%\w+}} = OpULessThan %bool %43 [[desc_state]] ;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: OpBranchConditional [[desc_state]] {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[load_result]] = OpLoad %v2float %25 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_51 %uint_4 %uint_3 %uint_7 %uint_0 {{%\w+}} {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[phi_result]] = OpPhi %v2float [[load_result]] {{%\w+}} [[null_v2float]] {{%\w+}} ;CHECK: OpStore %v_vtxResult [[phi_result]] OpReturn OpFunctionEnd - )" + kReadDescInit + kStreamWrite7Vert; + )" + kStreamWrite6 + kCheckDesc; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u, false, - false, true, false, true); + SinglePassRunAndMatch(text, true, 7u, 23u); } TEST_F(InstBindlessTest, ImageBufferOOBRead) { @@ -5009,7 +4643,6 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { const std::string text = R"( OpCapability Shader OpCapability ImageBuffer -;CHECK: OpCapability ImageQuery ;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 @@ -5027,7 +4660,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { OpDecorate %ii Flat OpDecorate %ii Location 13 ;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + R"( ;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %3 = OpTypeFunction %void @@ -5041,20 +4674,14 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { %int = OpTypeInt 32 1 %_ptr_Input_int = OpTypePointer Input %int %ii = OpVariable %_ptr_Input_int Input -;CHECK: %uint = OpTypeInt 32 0 -;CHECK: %bool = OpTypeBool ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kOutputGlobals + R"( +)" + 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 -;CHECK: OpBranch %21 -;CHECK: %21 = OpLabel -;CHECK: OpBranch %20 -;CHECK: %20 = OpLabel ;CHECK: OpBranch %19 ;CHECK: %19 = OpLabel %13 = OpLoad %10 %s @@ -5063,30 +4690,31 @@ TEST_F(InstBindlessTest, ImageBufferOOBRead) { OpStore %x %18 ;CHECK-NOT: %18 = OpImageRead %v4float %13 %17 ;CHECK-NOT: OpStore %x %18 -;CHECK: %23 = OpBitcast %uint %17 -;CHECK: %25 = OpImageQuerySize %uint %13 -;CHECK: %27 = OpULessThan %bool %23 %25 -;CHECK: OpSelectionMerge %29 None -;CHECK: OpBranchConditional %27 %30 %31 -;CHECK: %30 = OpLabel -;CHECK: %32 = OpLoad %10 %s -;CHECK: %33 = OpImageRead %v4float %32 %17 -;CHECK: OpBranch %29 -;CHECK: %31 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_33 %uint_7 %uint_3 %uint_7 %uint_0 %23 %25 -;CHECK: OpBranch %29 -;CHECK: %29 = OpLabel -;CHECK: [[phi_result:%\w+]] = OpPhi %v4float %33 %30 [[null_v4float]] %31 -;CHECK: OpStore %x [[phi_result]] - OpReturn - OpFunctionEnd - )" + kStreamWrite7Frag; +;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: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %10 %s +;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %17 +;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 %x [[phi_result]] +OpReturn +OpFunctionEnd + )" + kStreamWrite6 + kCheckDesc; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u, false, - false, true, true, true); + SinglePassRunAndMatch(text, true, 7u, 23u); } TEST_F(InstBindlessTest, ImageBufferOOBWrite) { @@ -5105,12 +4733,11 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { const std::string text = R"( OpCapability Shader OpCapability ImageBuffer -;CHECK: OpCapability ImageQuery ;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_output_buffer %gl_FragCoord +;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" @@ -5124,7 +4751,7 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { OpDecorate %ii Location 13 OpDecorate %x Location 11 ;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + R"( ;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %3 = OpTypeFunction %void @@ -5138,50 +4765,44 @@ TEST_F(InstBindlessTest, ImageBufferOOBWrite) { %v4float = OpTypeVector %float 4 %_ptr_Output_v4float = OpTypePointer Output %v4float %x = OpVariable %_ptr_Output_v4float Output -;CHECK: %uint = OpTypeInt 32 0 -;CHECK: %bool = OpTypeBool -;CHECK: {{%\w+}} = OpTypeFunction %void %uint %uint %uint %uint %uint ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kOutputGlobals + R"( +)" + 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: %v4uint = OpTypeVector %uint 4 %main = OpFunction %void None %3 %5 = OpLabel -;CHECK: OpBranch %21 -;CHECK: %21 = OpLabel -;CHECK: OpBranch %20 -;CHECK: %20 = OpLabel -;CHECK: OpBranch %19 +;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: %23 = OpBitcast %uint %14 -;CHECK: %25 = OpImageQuerySize %uint %10 -;CHECK: %27 = OpULessThan %bool %23 %25 -;CHECK: OpSelectionMerge %29 None -;CHECK: OpBranchConditional %27 %30 %31 -;CHECK: %30 = OpLabel -;CHECK: %32 = OpLoad %7 %s -;CHECK: OpImageWrite %32 %14 %18 -;CHECK: OpBranch %29 -;CHECK: %31 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_34 %uint_7 %uint_3 %uint_7 %uint_0 %23 %25 -;CHECK: OpBranch %29 -;CHECK: %29 = OpLabel - OpReturn - OpFunctionEnd - )" + kStreamWrite7Frag; +;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 +OpReturn +OpFunctionEnd +)" + kStreamWrite6 + kCheckDesc; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u, false, - false, true, true, true); + SinglePassRunAndMatch(text, true, 7u, 23u); } TEST_F(InstBindlessTest, TextureBufferOOBFetch) { @@ -5200,12 +4821,11 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { const std::string text = R"( OpCapability Shader OpCapability SampledBuffer -;CHECK: OpCapability ImageQuery ;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_output_buffer %gl_FragCoord +;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" @@ -5217,8 +4837,7 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { OpDecorate %s Binding 7 OpDecorate %ii Flat OpDecorate %ii Location 13 -;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + R"( ;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %3 = OpTypeFunction %void @@ -5232,20 +4851,14 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { %int = OpTypeInt 32 1 %_ptr_Input_int = OpTypePointer Input %int %ii = OpVariable %_ptr_Input_int Input -;CHECK: %uint = OpTypeInt 32 0 -;CHECK: %bool = OpTypeBool ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kOutputGlobals + R"( +)" + 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 -;CHECK: OpBranch %21 -;CHECK: %21 = OpLabel -;CHECK: OpBranch %20 -;CHECK: %20 = OpLabel ;CHECK: OpBranch %19 ;CHECK: %19 = OpLabel %13 = OpLoad %10 %s @@ -5254,30 +4867,31 @@ TEST_F(InstBindlessTest, TextureBufferOOBFetch) { OpStore %x %18 ;CHECK-NOT: %18 = OpImageFetch %v4float %13 %17 ;CHECK-NOT: OpStore %x %18 -;CHECK: %23 = OpBitcast %uint %17 -;CHECK: %25 = OpImageQuerySize %uint %13 -;CHECK: %27 = OpULessThan %bool %23 %25 -;CHECK: OpSelectionMerge %29 None -;CHECK: OpBranchConditional %27 %30 %31 -;CHECK: %30 = OpLabel -;CHECK: %32 = OpLoad %10 %s -;CHECK: %33 = OpImageFetch %v4float %32 %17 -;CHECK: OpBranch %29 -;CHECK: %31 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_32 %uint_6 %uint_3 %uint_7 %uint_0 %23 %25 -;CHECK: OpBranch %29 -;CHECK: %29 = OpLabel -;CHECK: [[phi_result:%\w+]] = OpPhi %v4float %33 %30 [[null_v4float]] %31 -;CHECK: OpStore %x [[phi_result]] - OpReturn - OpFunctionEnd - )" + kStreamWrite7Frag; +;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: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %10 %s +;CHECK: {{%\w+}} = OpImageFetch %v4float {{%\w+}} %17 +;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 %x [[phi_result]] +OpReturn +OpFunctionEnd + )" + kStreamWrite6 + kCheckDesc; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u, false, - false, true, true, true); + SinglePassRunAndMatch(text, true, 7u, 23u); } TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { @@ -5296,12 +4910,11 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { const std::string text = R"( OpCapability Shader OpCapability SampledBuffer -;CHECK: OpCapability ImageQuery ;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_output_buffer %gl_FragCoord +;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" @@ -5314,7 +4927,7 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { OpDecorate %ii Flat OpDecorate %ii Location 13 ;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + R"( ;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %3 = OpTypeFunction %void @@ -5329,20 +4942,13 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { %int = OpTypeInt 32 1 %_ptr_Input_int = OpTypePointer Input %int %ii = OpVariable %_ptr_Input_int Input -;CHECK: %uint = OpTypeInt 32 0 -;CHECK: %bool = OpTypeBool -;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kOutputGlobals + R"( +)" + 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 -;CHECK: OpBranch %23 -;CHECK: %23 = OpLabel -;CHECK: OpBranch %22 -;CHECK: %22 = OpLabel ;CHECK: OpBranch %21 ;CHECK: %21 = OpLabel %14 = OpLoad %11 %s @@ -5352,31 +4958,32 @@ TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { OpStore %x %20 ;CHECK-NOT: %20 = OpImageFetch %v4float %19 %18 ;CHECK-NOT: OpStore %x %20 -;CHECK: %25 = OpBitcast %uint %18 -;CHECK: %27 = OpImageQuerySize %uint %19 -;CHECK: %29 = OpULessThan %bool %25 %27 -;CHECK: OpSelectionMerge %31 None -;CHECK: OpBranchConditional %29 %32 %33 -;CHECK: %32 = OpLabel -;CHECK: %34 = OpLoad %11 %s -;CHECK: %35 = OpImage %10 %34 -;CHECK: %36 = OpImageFetch %v4float %35 %18 -;CHECK: OpBranch %31 -;CHECK: %33 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_34 %uint_6 %uint_3 %uint_7 %uint_0 %25 %27 -;CHECK: OpBranch %31 -;CHECK: %31 = OpLabel -;CHECK: [[phi_result:%\w+]] = OpPhi %v4float %36 %32 [[null_v4float]] %33 -;CHECK: OpStore %x [[phi_result]] - OpReturn - OpFunctionEnd - )" + kStreamWrite7Frag; +;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 %11 %s +;CHECK: {{%\w+}} = OpImage %10 {{%\w+}} +;CHECK: {{%\w+}} = OpImageFetch %v4float {{%\w+}} {{%\w+}} +;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 %x [[phi_result]] +OpReturn +OpFunctionEnd +)" + kStreamWrite6 + kCheckDesc; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u, false, - false, true, true, true); + SinglePassRunAndMatch(text, true, 7u, 23u); } TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { @@ -5396,12 +5003,11 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { const std::string text = R"( OpCapability Shader OpCapability SampledBuffer -;CHECK: OpCapability ImageQuery ;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_output_buffer %gl_FragCoord +;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" @@ -5416,8 +5022,7 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { OpDecorate %s Binding 8 OpDecorate %ii Flat OpDecorate %ii Location 13 -;CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( +)" + kInputDecorations + kOutputDecorations + R"( ;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord %void = OpTypeVoid %3 = OpTypeFunction %void @@ -5435,22 +5040,14 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { %int = OpTypeInt 32 1 %_ptr_Input_int = OpTypePointer Input %int %ii = OpVariable %_ptr_Input_int Input -;CHECK: %uint = OpTypeInt 32 0 -;CHECK: %bool = OpTypeBool ;CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kOutputGlobals + R"( +)" + 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 -;CHECK: OpBranch %28 -;CHECK: %28 = OpLabel -;CHECK: OpBranch %27 -;CHECK: %27 = OpLabel -;CHECK: OpBranch %26 -;CHECK: %26 = OpLabel %13 = OpLoad %10 %tBuf %17 = OpLoad %14 %s %19 = OpSampledImage %18 %13 %17 @@ -5460,32 +5057,33 @@ TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { OpStore %x %25 ;CHECK-NOT: %25 = OpImageFetch %v4float %24 %23 ;CHECK-NOT: OpStore %x %25 -;CHECK: %30 = OpBitcast %uint %23 -;CHECK: %32 = OpImageQuerySize %uint %24 -;CHECK: %34 = OpULessThan %bool %30 %32 -;CHECK: OpSelectionMerge %36 None -;CHECK: OpBranchConditional %34 %37 %38 -;CHECK: %37 = OpLabel -;CHECK: %39 = OpLoad %10 %tBuf -;CHECK: %40 = OpSampledImage %18 %39 %17 -;CHECK: %41 = OpImage %10 %40 -;CHECK: %42 = OpImageFetch %v4float %41 %23 -;CHECK: OpBranch %36 -;CHECK: %38 = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_42 %uint_6 %uint_3 %uint_7 %uint_0 %30 %32 -;CHECK: OpBranch %36 -;CHECK: %36 = OpLabel -;CHECK: [[phi_result:%\w+]] = OpPhi %v4float %42 %37 [[null_v4float]] %38 -;CHECK: OpStore %x [[phi_result]] +;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: OpSelectionMerge {{%\w+}} None +;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} +;CHECK: {{%\w+}} = OpLabel +;CHECK: {{%\w+}} = OpLoad %10 %tBuf +;CHECK: {{%\w+}} = OpSampledImage %18 {{%\w+}} %17 +;CHECK: {{%\w+}} = OpImage %10 {{%\w+}} +;CHECK: {{%\w+}} = OpImageFetch %v4float {{%\w+}} %23 +;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 %x [[phi_result]] OpReturn OpFunctionEnd - )" + kStreamWrite7Frag; + )" + kStreamWrite6 + kCheckDesc; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u, false, - false, true, true, true); + SinglePassRunAndMatch(text, true, 7u, 23u); } TEST_F(InstBindlessTest, DeviceBufferAddressOOB) { @@ -5557,13 +5155,6 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer R"(%main = OpFunction %void None %3 %5 = OpLabel %i = OpVariable %_ptr_Function_int Function -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: [[desc_state:%\w+]] = OpFunctionCall %uint %inst_bindless_read_desc_init %uint_0 %uint_0 %uint_0 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel OpStore %i %int_0 OpBranch %10 %10 = OpLabel @@ -5572,37 +5163,41 @@ OpBranch %14 %14 = OpLabel %15 = OpLoad %int %i %26 = OpAccessChain %_ptr_Uniform_int %u_info %int_1 -%27 = OpLoad %int %26 -%29 = OpSLessThan %bool %15 %27 -;CHECK-NOT: %27 = OpLoad %int %26 -;CHECK-NOT: %29 = OpSLessThan %bool %15 %27 ;CHECK: {{%\w+}} = OpIAdd %uint %uint_8 %uint_3 -;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\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 %bool %inst_bindless_desc_check %uint_23 %uint_55 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[load_result:%\w+]] = OpLoad %int %26 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_54 %uint_4 %uint_0 %uint_0 %uint_0 {{%\w+}} {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[phi_result:%\w+]] = OpPhi %int [[load_result]] {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpSLessThan %bool %15 [[phi_result]] +%27 = OpLoad %int %26 +%29 = OpSLessThan %bool %15 %27 +;CHECK-NOT: %27 = OpLoad %int %26 +;CHECK-NOT: %29 = OpSLessThan %bool %15 %27 +;CHECK: %29 = OpSLessThan %bool %15 [[phi_result]] OpBranchConditional %29 %11 %12 %11 = OpLabel %31 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 %32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 ;CHECK-NOT: %32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 ;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 %uint_7 -;CHECK: {{%\w+}} = OpULessThan %bool {{%\w+}} {{%\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 %bool %inst_bindless_desc_check %uint_23 %uint_60 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} ;CHECK: OpSelectionMerge {{%\w+}} None ;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpLabel ;CHECK: [[load_result_2:%\w+]] = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_7 %uint_59 %uint_4 %uint_0 %uint_0 %uint_0 {{%\w+}} {{%\w+}} ;CHECK: {{%\w+}} = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_bufStruct {{%\w+}} ;CHECK: OpBranch {{%\w+}} ;CHECK: {{%\w+}} = OpLabel @@ -5621,13 +5216,12 @@ OpBranch %10 %12 = OpLabel OpReturn OpFunctionEnd)" - + kReadDescInit + kStreamWrite7Vert; + + kStreamWrite6 + kCheckDesc; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 7u, 23u, false, true, - true, true, true); + SinglePassRunAndMatch(text, true, 7u, 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 8c8635fdf6..9484b5a204 100644 --- a/test/opt/inst_buff_addr_check_test.cpp +++ b/test/opt/inst_buff_addr_check_test.cpp @@ -40,12 +40,14 @@ static const std::string kOutputGlobals = R"( ; CHECK: [[output_buffer_var]] = OpVariable [[output_ptr_type]] StorageBuffer )"; -static const std::string kStreamWrite4Begin = R"( -; CHECK: {{%\w+}} = OpFunction %void None {{%\w+}} -; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint +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 @@ -60,80 +62,40 @@ static const std::string kStreamWrite4Begin = R"( ; 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+}} %uint_23 +; 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+}} [[param_1]] -)"; - -static const std::string kStreamWrite4End = R"( -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[param_2]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_8 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[param_3]] -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_9 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[param_4]] -; CHECK: OpBranch {{%\w+}} -; CHECK: {{%\w+}} = OpLabel -; CHECK: OpReturn -; CHECK: OpFunctionEnd -)"; - -// clang-format off -static const std::string kStreamWrite4Frag = kStreamWrite4Begin + R"( +; 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+}} %uint_4 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -; 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 {{%\w+}} 1 -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}} -)" + kStreamWrite4End; - -static const std::string kStreamWrite4Compute = kStreamWrite4Begin + R"( -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} %uint_5 -; 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+}} = 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+}} -)" + kStreamWrite4End; -// clang-format on - -// clang-format off -static const std::string kStreamWrite4Vert = kStreamWrite4Begin + R"( -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 +; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_7 ; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} %uint_0 -; CHECK: {{%\w+}} = OpLoad %uint %gl_VertexIndex -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_4 +; 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+}} {{%\w+}} -; CHECK: {{%\w+}} = OpLoad %uint %gl_InstanceIndex -; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 +; 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+}} {{%\w+}} -)" + kStreamWrite4End; -// clang-format on +; 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 @@ -242,9 +204,9 @@ 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"( -; CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId )"; const std::string globals = R"( @@ -267,17 +229,15 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int ; CHECK: %ulong = OpTypeInt 64 0 ; CHECK: %bool = OpTypeBool -; CHECK: %28 = OpTypeFunction %bool %ulong %uint ; CHECK: %_runtimearr_ulong = OpTypeRuntimeArray %ulong )" + kInputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_ulong = OpTypePointer StorageBuffer %ulong -; CHECK: {{%\w+}} = OpTypeFunction %void %uint %uint %uint %uint -; CHECK: %_runtimearr_uint = OpTypeRuntimeArray %uint -)" + kOutputGlobals + R"( -; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; 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 )"; // clang-format off @@ -293,26 +253,31 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer ; 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: %24 = OpConvertPtrToU %ulong %22 -; CHECK: %61 = OpFunctionCall %bool %inst_buff_addr_search_and_test %24 %uint_4 -; CHECK: OpSelectionMerge %62 None -; CHECK: OpBranchConditional %61 %63 %64 -; CHECK: %63 = OpLabel +; 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 OpStore %22 %int_3239 Aligned 16 ; CHECK: OpStore %22 %int_3239 Aligned 16 -; CHECK: OpBranch %62 -; CHECK: %64 = OpLabel -; CHECK: %65 = OpUConvert %uint %24 -; CHECK: %67 = OpShiftRightLogical %ulong %24 %uint_32 -; CHECK: %68 = OpUConvert %uint %67 -; CHECK: %124 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_48 %uint_2 %65 %68 -; CHECK: OpBranch %62 -; CHECK: %62 = OpLabel +; 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 OpReturn OpFunctionEnd )"; - const std::string output_funcs = kSearchAndTest + kStreamWrite4Compute; + const std::string output_funcs = kSearchAndTest + kStreamWrite3; // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch( @@ -376,10 +341,9 @@ OpDecorate %r DescriptorSet 0 OpDecorate %r Binding 0 ; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8 )" + kInputDecorations + R"( -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId -)"; +; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 +)" + kOutputDecorations; // clang-format on const std::string globals = R"( @@ -422,31 +386,41 @@ OpStore %26 %int_531 Aligned 16 ; CHECK: %72 = OpUConvert %uint %30 ; CHECK: %74 = OpShiftRightLogical %ulong %30 %uint_32 ; CHECK: %75 = OpUConvert %uint %74 -; CHECK: %131 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_44 %uint_2 %72 %75 -; CHECK: %133 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_blockType %132 +; 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: %134 = OpPhi %_ptr_PhysicalStorageBuffer_blockType %71 %69 %133 %70 -; CHECK: %26 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %134 %int_0 -; CHECK: %135 = OpConvertPtrToU %ulong %26 -; CHECK: %136 = OpFunctionCall %bool %inst_buff_addr_search_and_test %135 %uint_4 -; CHECK: OpSelectionMerge %137 None -; CHECK: OpBranchConditional %136 %138 %139 -; CHECK: %138 = 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 %137 -; CHECK: %139 = OpLabel -; CHECK: %140 = OpUConvert %uint %135 -; CHECK: %141 = OpShiftRightLogical %ulong %135 %uint_32 -; CHECK: %142 = OpUConvert %uint %141 -; CHECK: %144 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_46 %uint_2 %140 %142 -; CHECK: OpBranch %137 -; CHECK: %137 = OpLabel +; 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 OpReturn OpFunctionEnd )"; - const std::string output_funcs = kSearchAndTest + kStreamWrite4Compute; + const std::string output_funcs = kSearchAndTest + kStreamWrite3; SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); SinglePassRunAndMatch( @@ -481,7 +455,7 @@ OpCapability PhysicalStorageBufferAddresses %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel PhysicalStorageBuffer64 GLSL450 OpEntryPoint Fragment %main "main" -; CHECK: OpEntryPoint Fragment %main "main" %inst_buff_addr_input_buffer %inst_buff_addr_output_buffer %gl_FragCoord +; CHECK: OpEntryPoint Fragment %main "main" %inst_buff_addr_input_buffer %gl_FragCoord %inst_buff_addr_output_buffer OpExecutionMode %main OriginUpperLeft OpSource GLSL 450 OpSourceExtension "GL_ARB_gpu_shader_int64" @@ -502,10 +476,9 @@ OpMemberDecorate %TestBuffer 0 Offset 0 OpDecorate %TestBuffer Block ; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8 )" + kInputDecorations + R"( -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -)"; +; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 +)" + kOutputDecorations; const std::string globals = R"( %void = OpTypeVoid @@ -522,9 +495,7 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffe %_ptr_PhysicalStorageBuffer_Test_0 = OpTypePointer PhysicalStorageBuffer %Test_0 %ulong_18446744073172680704 = OpConstant %ulong 18446744073172680704 ; CHECK: %47 = OpTypeFunction %bool %ulong %uint -)" + kInputGlobals + R"( -; CHECK: {{%\w+}} = OpTypeFunction %void %uint %uint %uint %uint -)" + kOutputGlobals + R"( +)" + kInputGlobals + kOutputGlobals + R"( ; CHECK: {{%\w+}} = OpConstantNull %Test_0 )"; // clang-format on @@ -537,29 +508,34 @@ OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffe %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: %43 = OpConvertPtrToU %ulong %38 -; CHECK: %80 = OpFunctionCall %bool %inst_buff_addr_search_and_test %43 %uint_4 -; CHECK: OpSelectionMerge %81 None -; CHECK: OpBranchConditional %80 %82 %83 -; CHECK: %82 = OpLabel -; CHECK: %84 = OpLoad %Test_0 %38 Aligned 16 -; CHECK: OpBranch %81 -; CHECK: %83 = OpLabel -; CHECK: %85 = OpUConvert %uint %43 -; CHECK: %87 = OpShiftRightLogical %ulong %43 %uint_32 -; CHECK: %88 = OpUConvert %uint %87 -; CHECK: %142 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_37 %uint_2 %85 %88 -; CHECK: OpBranch %81 -; CHECK: %81 = OpLabel -; CHECK: %144 = OpPhi %Test_0 %84 %82 %143 %83 +; 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+}} %40 = OpCopyLogical %Test %39 ; CHECK-NOT: %40 = OpCopyLogical %Test %39 -; CHECK: %40 = OpCopyLogical %Test %144 +; CHECK: %40 = OpCopyLogical %Test [[phi_result]] OpReturn OpFunctionEnd )"; - const std::string output_funcs = kSearchAndTest + kStreamWrite4Frag; + const std::string output_funcs = kSearchAndTest + kStreamWrite3; SetTargetEnv(SPV_ENV_VULKAN_1_2); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); @@ -625,10 +601,10 @@ OpMemberDecorate %Test_0 2 Offset 24 OpMemberDecorate %TestBuffer 0 Offset 0 ; CHECK: OpDecorate %_runtimearr_ulong ArrayStride 8 )" + kInputDecorations + R"( -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex ; CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex +; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 +)" + kOutputDecorations + R"( )"; const std::string globals = R"( @@ -688,7 +664,10 @@ OpFunctionEnd ; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}} ; CHECK: {{%\w+}} = OpShiftRightLogical %ulong {{%\w+}} %uint_32 ; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_62 {{%\w+}} {{%\w+}} {{%\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+}} @@ -699,7 +678,7 @@ OpReturnValue %30 OpFunctionEnd )"; - const std::string output_funcs = kSearchAndTest + kStreamWrite4Vert; + const std::string output_funcs = kSearchAndTest + kStreamWrite3; SetTargetEnv(SPV_ENV_VULKAN_1_2); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); @@ -731,7 +710,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 %inst_buff_addr_output_buffer %gl_VertexIndex %gl_InstanceIndex +;CHECK: OpEntryPoint Vertex %main "main" %u_info %inst_buff_addr_input_buffer %gl_VertexIndex %gl_InstanceIndex %inst_buff_addr_output_buffer OpSource GLSL 450 OpSourceExtension "GL_EXT_buffer_reference" OpName %main "main" @@ -798,13 +777,16 @@ OpBranchConditional %29 %11 %12 ;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: 134 = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_62 %uint_2 %80 %83 -;CHECK: OpBranch %77 -;CHECK: 77 = OpLabel +;CHECK: %79 = OpLabel +;CHECK: %80 = OpUConvert %uint %41 +;CHECK: %82 = OpShiftRightLogical %ulong %41 %uint_32 +;CHECK: %83 = OpUConvert %uint %82 +;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 OpBranch %13 %13 = OpLabel %37 = OpLoad %int %i @@ -813,7 +795,7 @@ OpStore %i %38 OpBranch %10 %12 = OpLabel OpReturn -OpFunctionEnd)" + kSearchAndTest + kStreamWrite4Vert; +OpFunctionEnd)" + kSearchAndTest + kStreamWrite3; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); @@ -924,7 +906,10 @@ OpStore %readvec %38 ; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}} ; CHECK: {{%\w+}} = OpShiftRightLogical %ulong {{%\w+}} %uint_32 ; CHECK: {{%\w+}} = OpUConvert %uint {{%\w+}} -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_buff_addr_stream_write_4 %uint_66 %uint_2 {{%\w+}} {{%\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+}} @@ -938,7 +923,7 @@ OpBranch %10 %12 = OpLabel OpReturn OpFunctionEnd -)" + kSearchAndTest + kStreamWrite4Vert; +)" + kSearchAndTest + kStreamWrite3; // clang-format on SetTargetEnv(SPV_ENV_VULKAN_1_2); diff --git a/test/opt/inst_debug_printf_test.cpp b/test/opt/inst_debug_printf_test.cpp index 7dd10d8fad..e9774debf6 100644 --- a/test/opt/inst_debug_printf_test.cpp +++ b/test/opt/inst_debug_printf_test.cpp @@ -87,10 +87,9 @@ OpDecorate %7 DescriptorSet 0 OpDecorate %7 Binding 0 OpDecorate %3 Location 0 OpDecorate %4 Location 0 -; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 -)" + kOutputDecorations + R"( ; CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -)"; +; CHECK: OpDecorate %_runtimearr_uint ArrayStride 4 +)" + kOutputDecorations; const std::string globals = R"(%void = OpTypeVoid @@ -110,14 +109,14 @@ OpDecorate %4 Location 0 %_ptr_Output_v4float = OpTypePointer Output %v4float %4 = OpVariable %_ptr_Output_v4float Output ; CHECK: %uint = OpTypeInt 32 0 -; CHECK: [[func_type:%\w+]] = OpTypeFunction %void %uint %uint %uint %uint %uint %uint +; 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: %_runtimearr_uint = OpTypeRuntimeArray %uint )" + kOutputGlobals + R"( ; CHECK: %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint ; CHECK: %bool = OpTypeBool -; CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -; CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -; CHECK: %v4uint = OpTypeVector %uint 4 )"; // clang-format on @@ -131,76 +130,86 @@ OpDecorate %4 Location 0 %25 = OpImageSampleImplicitLod %v4float %24 %21 %26 = OpExtInst %void %1 1 %5 %25 ; CHECK-NOT: %26 = OpExtInst %void %1 1 %5 %25 -; CHECK: %29 = OpCompositeExtract %float %25 0 -; CHECK: %30 = OpBitcast %uint %29 -; CHECK: %31 = OpCompositeExtract %float %25 1 -; CHECK: %32 = OpBitcast %uint %31 -; CHECK: %33 = OpCompositeExtract %float %25 2 -; CHECK: %34 = OpBitcast %uint %33 -; CHECK: %35 = OpCompositeExtract %float %25 3 -; CHECK: %36 = OpBitcast %uint %35 -; CHECK: %101 = OpFunctionCall %void %inst_printf_stream_write_6 %uint_36 %uint_5 %30 %32 %34 %36 -; CHECK: OpBranch %102 -; CHECK: %102 = OpLabel +; CHECK: {{%\w+}} = OpCompositeExtract %float %25 0 +; CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}} +; CHECK: {{%\w+}} = OpCompositeExtract %float %25 1 +; CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}} +; CHECK: {{%\w+}} = OpCompositeExtract %float %25 2 +; 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: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel OpStore %4 %25 OpReturn OpFunctionEnd )"; const std::string output_func = R"( -; CHECK: %inst_printf_stream_write_6 = OpFunction %void None [[func_type]] -; CHECK: [[param_1:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_2:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_3:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_4:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_5:%\w+]] = OpFunctionParameter %uint -; CHECK: [[param_6:%\w+]] = OpFunctionParameter %uint +; 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 +; CHECK: [[sw_param_4:%\w+]] = OpFunctionParameter %uint +; CHECK: [[sw_param_5:%\w+]] = OpFunctionParameter %uint ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_1 +; 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+}} = OpArrayLength %uint %inst_printf_output_buffer 2 +; 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 %inst_printf_output_buffer %uint_2 {{%\w+}} +; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} %uint_12 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_1 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} %uint_23 +; 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 %inst_printf_output_buffer %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[param_1]] +; 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 %inst_printf_output_buffer %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} %uint_4 -; CHECK: {{%\w+}} = OpLoad %v4float %gl_FragCoord -; CHECK: {{%\w+}} = OpBitcast %v4uint {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 +; 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 %inst_printf_output_buffer %uint_2 {{%\w+}} +; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} ; CHECK: OpStore {{%\w+}} {{%\w+}} -; CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 +; CHECK: {{%\w+}} = OpCompositeExtract %uint [[sw_stage_info]] 2 ; CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_5 -; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint %inst_printf_output_buffer %uint_2 {{%\w+}} +; 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 %inst_printf_output_buffer %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[param_2]] +; 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 %inst_printf_output_buffer %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[param_3]] +; 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 %inst_printf_output_buffer %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[param_4]] +; 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 %inst_printf_output_buffer %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[param_5]] +; 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 %inst_printf_output_buffer %uint_2 {{%\w+}} -; CHECK: OpStore {{%\w+}} [[param_6]] +; CHECK: {{%\w+}} = OpAccessChain %_ptr_StorageBuffer_uint [[output_buffer_var]] %uint_2 {{%\w+}} +; CHECK: OpStore {{%\w+}} [[sw_param_5]] ; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel ; CHECK: OpReturn From 16098b3c1096f990f08ff2cf6a74252e483c7c18 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 22 Jun 2023 15:15:53 -0700 Subject: [PATCH 190/523] Have effcee add abseil subdirectory (#5281) We currently add the abseil in the external/CMakeLists.txt. However, it is not needed by spirv-tools directly. Instead we set effcee's variable with the abseil source directory, and let effcee add it. This will mean that abseil will be checked out only if effcee is used. We currently get a few reports from people that use to only checkout spirv-headers, and now get errors because abseil is missing. --- external/CMakeLists.txt | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index d036db0895..5d8a3dab09 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -91,18 +91,21 @@ if (NOT ${SPIRV_SKIP_TESTS}) # Find Effcee and RE2, for testing. + # RE2 depends on Abseil. We set absl_SOURCE_DIR if it is not already set, so + # that effcee can find abseil. + if(NOT TARGET absl::base) + if (NOT absl_SOURCE_DIR) + if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/abseil_cpp) + set(absl_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/abseil_cpp" CACHE STRING "Abseil source dir" ) + endif() + endif() + endif() + # First find RE2, since Effcee depends on it. # If already configured, then use that. Otherwise, prefer to find it under 're2' # in this directory. if (NOT TARGET re2) - # RE2 depends on Abseil, so we need to add it. - if(NOT TARGET absl::base) - set(ABSL_INTERNAL_AT_LEAST_CXX17 ON) - set(ABSL_PROPAGATE_CXX_STD ON) - set(ABSL_ENABLE_INSTALL ON) - add_subdirectory(abseil_cpp EXCLUDE_FROM_ALL) - endif() # If we are configuring RE2, then turn off its testing. It takes a long time and # does not add much value for us. If an enclosing project configured RE2, then it From 04cdb2d344706052c7a2d359294e830ebac63e74 Mon Sep 17 00:00:00 2001 From: archimedus <10398515+archimedus@users.noreply.github.com> Date: Fri, 23 Jun 2023 00:33:36 +0200 Subject: [PATCH 191/523] SPV_KHR_cooperative_matrix (#5286) * SPV_KHR_cooperative_matrix * Update DEPS with headers * Update according to review recommendations * Bugfix and formatting * Formatting missed or damaged by VS2022 --- DEPS | 2 +- include/spirv-tools/libspirv.h | 7 + source/assembly_grammar.cpp | 5 +- source/binary.cpp | 6 +- source/opcode.cpp | 2 + source/operand.cpp | 11 ++ source/opt/type_manager.cpp | 31 +++++ source/opt/types.cpp | 42 ++++++ source/opt/types.h | 35 +++++ source/text.cpp | 3 +- source/val/validate_arithmetics.cpp | 153 +++++++++++++++++++-- source/val/validate_composites.cpp | 20 +++ source/val/validate_constants.cpp | 2 + source/val/validate_conversion.cpp | 18 ++- source/val/validate_id.cpp | 14 +- source/val/validate_memory.cpp | 127 +++++++++++++++++- source/val/validate_type.cpp | 27 +++- source/val/validation_state.cpp | 73 +++++++++- source/val/validation_state.h | 5 + test/opt/type_manager_test.cpp | 12 ++ test/val/val_arithmetics_test.cpp | 148 +++++++++++++++++++- test/val/val_composites_test.cpp | 86 +++++++++++- test/val/val_conversion_test.cpp | 176 +++++++++++++++++++++++- test/val/val_memory_test.cpp | 200 ++++++++++++++++++++++++++-- utils/generate_grammar_tables.py | 2 +- 25 files changed, 1152 insertions(+), 55 deletions(-) diff --git a/DEPS b/DEPS index 284797f9b0..5727bad142 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': '7c5e396af825562ec8321fdbf2f1cf276b26e3ae', - 'spirv_headers_revision': '10db9d4e194246a020a4148e220837ac7c68cfd9', + 'spirv_headers_revision': '3469b164e25cee24435029a569933cb42578db5d', } deps = { diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index 542b745327..8ecaf0a4c7 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -285,6 +285,13 @@ typedef enum spv_operand_type_t { // An optional packed vector format SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT, + // Concrete operand types for cooperative matrix. + SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS, + // An optional cooperative matrix operands + SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS, + SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_LAYOUT, + SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_USE, + // 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/assembly_grammar.cpp b/source/assembly_grammar.cpp index 6df823e307..56c7964d8c 100644 --- a/source/assembly_grammar.cpp +++ b/source/assembly_grammar.cpp @@ -154,11 +154,12 @@ const SpecConstantOpcodeEntry kOpSpecConstantOpcodes[] = { CASE(InBoundsAccessChain), CASE(PtrAccessChain), CASE(InBoundsPtrAccessChain), - CASE(CooperativeMatrixLengthNV) + CASE(CooperativeMatrixLengthNV), + CASE(CooperativeMatrixLengthKHR) }; // The 60 is determined by counting the opcodes listed in the spec. -static_assert(60 == sizeof(kOpSpecConstantOpcodes)/sizeof(kOpSpecConstantOpcodes[0]), +static_assert(61 == sizeof(kOpSpecConstantOpcodes)/sizeof(kOpSpecConstantOpcodes[0]), "OpSpecConstantOp opcode table is incomplete"); #undef CASE // clang-format on diff --git a/source/binary.cpp b/source/binary.cpp index beb56be7b5..207d4a9b37 100644 --- a/source/binary.cpp +++ b/source/binary.cpp @@ -691,7 +691,9 @@ spv_result_t Parser::parseOperand(size_t inst_offset, case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: case SPV_OPERAND_TYPE_SELECTION_CONTROL: case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: - case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: { + case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: + case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS: + case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS: { // This operand is a mask. // Map an optional operand type to its corresponding concrete type. @@ -699,6 +701,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset, parsed_operand.type = SPV_OPERAND_TYPE_IMAGE; else if (type == SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS) parsed_operand.type = SPV_OPERAND_TYPE_MEMORY_ACCESS; + if (type == SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS) + parsed_operand.type = SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS; // Check validity of set mask bits. Also prepare for operands for those // masks if they have any. To get operand order correct, scan from diff --git a/source/opcode.cpp b/source/opcode.cpp index d26024abb4..ffbb2e8bae 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -274,6 +274,7 @@ int32_t spvOpcodeIsComposite(const spv::Op opcode) { case spv::Op::OpTypeArray: case spv::Op::OpTypeStruct: case spv::Op::OpTypeCooperativeMatrixNV: + case spv::Op::OpTypeCooperativeMatrixKHR: return true; default: return false; @@ -340,6 +341,7 @@ int32_t spvOpcodeGeneratesType(spv::Op op) { case spv::Op::OpTypeNamedBarrier: case spv::Op::OpTypeAccelerationStructureNV: case spv::Op::OpTypeCooperativeMatrixNV: + case spv::Op::OpTypeCooperativeMatrixKHR: // case spv::Op::OpTypeAccelerationStructureKHR: covered by // spv::Op::OpTypeAccelerationStructureNV case spv::Op::OpTypeRayQueryKHR: diff --git a/source/operand.cpp b/source/operand.cpp index 31a6c5965d..a78191b942 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -236,6 +236,13 @@ const char* spvOperandTypeStr(spv_operand_type_t type) { case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT: case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT: return "packed vector format"; + case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS: + case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS: + return "cooperative matrix operands"; + case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_LAYOUT: + return "cooperative matrix layout"; + case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_USE: + return "cooperative matrix use"; case SPV_OPERAND_TYPE_IMAGE: case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: return "image"; @@ -369,6 +376,8 @@ bool spvOperandIsConcrete(spv_operand_type_t type) { case SPV_OPERAND_TYPE_QUANTIZATION_MODES: case SPV_OPERAND_TYPE_OVERFLOW_MODES: case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT: + case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_LAYOUT: + case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_USE: return true; default: break; @@ -387,6 +396,7 @@ bool spvOperandIsConcreteMask(spv_operand_type_t type) { case SPV_OPERAND_TYPE_FRAGMENT_SHADING_RATE: case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: + case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS: return true; default: break; @@ -405,6 +415,7 @@ bool spvOperandIsOptional(spv_operand_type_t type) { case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: case SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER: case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT: + case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS: case SPV_OPERAND_TYPE_OPTIONAL_CIV: return true; default: diff --git a/source/opt/type_manager.cpp b/source/opt/type_manager.cpp index 1b1aeadc8a..2dcc25940c 100644 --- a/source/opt/type_manager.cpp +++ b/source/opt/type_manager.cpp @@ -423,6 +423,23 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { {SPV_OPERAND_TYPE_ID, {coop_mat->columns_id()}}}); break; } + case Type::kCooperativeMatrixKHR: { + auto coop_mat = type->AsCooperativeMatrixKHR(); + uint32_t const component_type = + GetTypeInstruction(coop_mat->component_type()); + if (component_type == 0) { + return 0; + } + typeInst = MakeUnique( + context(), spv::Op::OpTypeCooperativeMatrixKHR, 0, id, + std::initializer_list{ + {SPV_OPERAND_TYPE_ID, {component_type}}, + {SPV_OPERAND_TYPE_SCOPE_ID, {coop_mat->scope_id()}}, + {SPV_OPERAND_TYPE_ID, {coop_mat->rows_id()}}, + {SPV_OPERAND_TYPE_ID, {coop_mat->columns_id()}}, + {SPV_OPERAND_TYPE_ID, {coop_mat->use_id()}}}); + break; + } default: assert(false && "Unexpected type"); break; @@ -628,6 +645,14 @@ Type* TypeManager::RebuildType(const Type& type) { cm_type->columns_id()); break; } + case Type::kCooperativeMatrixKHR: { + const CooperativeMatrixKHR* cm_type = type.AsCooperativeMatrixKHR(); + const Type* component_type = cm_type->component_type(); + rebuilt_ty = MakeUnique( + RebuildType(*component_type), cm_type->scope_id(), cm_type->rows_id(), + cm_type->columns_id(), cm_type->use_id()); + break; + } default: assert(false && "Unhandled type"); return nullptr; @@ -863,6 +888,12 @@ Type* TypeManager::RecordIfTypeDefinition(const Instruction& inst) { inst.GetSingleWordInOperand(2), inst.GetSingleWordInOperand(3)); break; + case spv::Op::OpTypeCooperativeMatrixKHR: + type = new CooperativeMatrixKHR( + GetType(inst.GetSingleWordInOperand(0)), + inst.GetSingleWordInOperand(1), inst.GetSingleWordInOperand(2), + inst.GetSingleWordInOperand(3), inst.GetSingleWordInOperand(4)); + break; case spv::Op::OpTypeRayQueryKHR: type = new RayQueryKHR(); break; diff --git a/source/opt/types.cpp b/source/opt/types.cpp index 49eec9b743..b18b8cb1ae 100644 --- a/source/opt/types.cpp +++ b/source/opt/types.cpp @@ -128,6 +128,7 @@ std::unique_ptr Type::Clone() const { DeclareKindCase(NamedBarrier); DeclareKindCase(AccelerationStructureNV); DeclareKindCase(CooperativeMatrixNV); + DeclareKindCase(CooperativeMatrixKHR); DeclareKindCase(RayQueryKHR); DeclareKindCase(HitObjectNV); #undef DeclareKindCase @@ -175,6 +176,7 @@ bool Type::operator==(const Type& other) const { DeclareKindCase(NamedBarrier); DeclareKindCase(AccelerationStructureNV); DeclareKindCase(CooperativeMatrixNV); + DeclareKindCase(CooperativeMatrixKHR); DeclareKindCase(RayQueryKHR); DeclareKindCase(HitObjectNV); #undef DeclareKindCase @@ -230,6 +232,7 @@ size_t Type::ComputeHashValue(size_t hash, SeenTypes* seen) const { DeclareKindCase(NamedBarrier); DeclareKindCase(AccelerationStructureNV); DeclareKindCase(CooperativeMatrixNV); + DeclareKindCase(CooperativeMatrixKHR); DeclareKindCase(RayQueryKHR); DeclareKindCase(HitObjectNV); #undef DeclareKindCase @@ -708,6 +711,45 @@ bool CooperativeMatrixNV::IsSameImpl(const Type* that, columns_id_ == mt->columns_id_ && HasSameDecorations(that); } +CooperativeMatrixKHR::CooperativeMatrixKHR(const Type* type, + const uint32_t scope, + const uint32_t rows, + const uint32_t columns, + const uint32_t use) + : Type(kCooperativeMatrixKHR), + component_type_(type), + scope_id_(scope), + rows_id_(rows), + columns_id_(columns), + use_id_(use) { + assert(type != nullptr); + assert(scope != 0); + assert(rows != 0); + assert(columns != 0); +} + +std::string CooperativeMatrixKHR::str() const { + std::ostringstream oss; + oss << "<" << component_type_->str() << ", " << scope_id_ << ", " << rows_id_ + << ", " << columns_id_ << ", " << use_id_ << ">"; + return oss.str(); +} + +size_t CooperativeMatrixKHR::ComputeExtraStateHash(size_t hash, + SeenTypes* seen) const { + hash = hash_combine(hash, scope_id_, rows_id_, columns_id_, use_id_); + return component_type_->ComputeHashValue(hash, seen); +} + +bool CooperativeMatrixKHR::IsSameImpl(const Type* that, + IsSameCache* seen) const { + const CooperativeMatrixKHR* mt = that->AsCooperativeMatrixKHR(); + if (!mt) return false; + return component_type_->IsSameImpl(mt->component_type_, seen) && + scope_id_ == mt->scope_id_ && rows_id_ == mt->rows_id_ && + columns_id_ == mt->columns_id_ && HasSameDecorations(that); +} + } // namespace analysis } // namespace opt } // namespace spvtools diff --git a/source/opt/types.h b/source/opt/types.h index 26c058c6f8..16a948cec5 100644 --- a/source/opt/types.h +++ b/source/opt/types.h @@ -60,6 +60,7 @@ class PipeStorage; class NamedBarrier; class AccelerationStructureNV; class CooperativeMatrixNV; +class CooperativeMatrixKHR; class RayQueryKHR; class HitObjectNV; @@ -100,6 +101,7 @@ class Type { kNamedBarrier, kAccelerationStructureNV, kCooperativeMatrixNV, + kCooperativeMatrixKHR, kRayQueryKHR, kHitObjectNV, kLast @@ -201,6 +203,7 @@ class Type { DeclareCastMethod(NamedBarrier) DeclareCastMethod(AccelerationStructureNV) DeclareCastMethod(CooperativeMatrixNV) + DeclareCastMethod(CooperativeMatrixKHR) DeclareCastMethod(RayQueryKHR) DeclareCastMethod(HitObjectNV) #undef DeclareCastMethod @@ -624,6 +627,38 @@ class CooperativeMatrixNV : public Type { const uint32_t columns_id_; }; +class CooperativeMatrixKHR : public Type { + public: + CooperativeMatrixKHR(const Type* type, const uint32_t scope, + const uint32_t rows, const uint32_t columns, + const uint32_t use); + CooperativeMatrixKHR(const CooperativeMatrixKHR&) = default; + + std::string str() const override; + + CooperativeMatrixKHR* AsCooperativeMatrixKHR() override { return this; } + const CooperativeMatrixKHR* AsCooperativeMatrixKHR() const override { + return this; + } + + size_t ComputeExtraStateHash(size_t hash, SeenTypes* seen) const override; + + const Type* component_type() const { return component_type_; } + uint32_t scope_id() const { return scope_id_; } + uint32_t rows_id() const { return rows_id_; } + uint32_t columns_id() const { return columns_id_; } + uint32_t use_id() const { return use_id_; } + + private: + bool IsSameImpl(const Type* that, IsSameCache*) const override; + + const Type* component_type_; + const uint32_t scope_id_; + const uint32_t rows_id_; + const uint32_t columns_id_; + const uint32_t use_id_; +}; + #define DefineParameterlessType(type, name) \ class type : public Type { \ public: \ diff --git a/source/text.cpp b/source/text.cpp index 9c77422f33..eb7f96b93f 100644 --- a/source/text.cpp +++ b/source/text.cpp @@ -402,7 +402,8 @@ spv_result_t spvTextEncodeOperand(const spvtools::AssemblyGrammar& grammar, case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: case SPV_OPERAND_TYPE_SELECTION_CONTROL: case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: - case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: { + case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: + case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS: { uint32_t value; if (auto error = grammar.parseMaskOperand(type, textValue, &value)) { return context->diagnostic(error) diff --git a/source/val/validate_arithmetics.cpp b/source/val/validate_arithmetics.cpp index 4e7dd5e884..b608a85952 100644 --- a/source/val/validate_arithmetics.cpp +++ b/source/val/validate_arithmetics.cpp @@ -42,14 +42,29 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) { opcode != spv::Op::OpFMod); if (!_.IsFloatScalarType(result_type) && !_.IsFloatVectorType(result_type) && - !(supportsCoopMat && _.IsFloatCooperativeMatrixType(result_type))) + !(supportsCoopMat && _.IsFloatCooperativeMatrixType(result_type)) && + !(opcode == spv::Op::OpFMul && + _.IsCooperativeMatrixKHRType(result_type) && + _.IsFloatCooperativeMatrixType(result_type))) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected floating scalar or vector type as Result Type: " << spvOpcodeString(opcode); for (size_t operand_index = 2; operand_index < inst->operands().size(); ++operand_index) { - if (_.GetOperandTypeId(inst, operand_index) != result_type) + if (supportsCoopMat && _.IsCooperativeMatrixKHRType(result_type)) { + const uint32_t type_id = _.GetOperandTypeId(inst, operand_index); + if (!_.IsCooperativeMatrixKHRType(type_id) || + !_.IsFloatCooperativeMatrixType(type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected arithmetic operands to be of Result Type: " + << spvOpcodeString(opcode) << " operand index " + << operand_index; + } + spv_result_t ret = + _.CooperativeMatrixShapesMatch(inst, type_id, result_type); + if (ret != SPV_SUCCESS) return ret; + } else if (_.GetOperandTypeId(inst, operand_index) != result_type) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected arithmetic operands to be of Result Type: " << spvOpcodeString(opcode) << " operand index " @@ -71,7 +86,19 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) { for (size_t operand_index = 2; operand_index < inst->operands().size(); ++operand_index) { - if (_.GetOperandTypeId(inst, operand_index) != result_type) + if (supportsCoopMat && _.IsCooperativeMatrixKHRType(result_type)) { + const uint32_t type_id = _.GetOperandTypeId(inst, operand_index); + if (!_.IsCooperativeMatrixKHRType(type_id) || + !_.IsUnsignedIntCooperativeMatrixType(type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected arithmetic operands to be of Result Type: " + << spvOpcodeString(opcode) << " operand index " + << operand_index; + } + spv_result_t ret = + _.CooperativeMatrixShapesMatch(inst, type_id, result_type); + if (ret != SPV_SUCCESS) return ret; + } else if (_.GetOperandTypeId(inst, operand_index) != result_type) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected arithmetic operands to be of Result Type: " << spvOpcodeString(opcode) << " operand index " @@ -91,7 +118,10 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) { (opcode != spv::Op::OpIMul && opcode != spv::Op::OpSRem && opcode != spv::Op::OpSMod); if (!_.IsIntScalarType(result_type) && !_.IsIntVectorType(result_type) && - !(supportsCoopMat && _.IsIntCooperativeMatrixType(result_type))) + !(supportsCoopMat && _.IsIntCooperativeMatrixType(result_type)) && + !(opcode == spv::Op::OpIMul && + _.IsCooperativeMatrixKHRType(result_type) && + _.IsIntCooperativeMatrixType(result_type))) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected int scalar or vector type as Result Type: " << spvOpcodeString(opcode); @@ -102,9 +132,26 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) { for (size_t operand_index = 2; operand_index < inst->operands().size(); ++operand_index) { const uint32_t type_id = _.GetOperandTypeId(inst, operand_index); + + if (supportsCoopMat && _.IsCooperativeMatrixKHRType(result_type)) { + if (!_.IsCooperativeMatrixKHRType(type_id) || + !_.IsIntCooperativeMatrixType(type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected arithmetic operands to be of Result Type: " + << spvOpcodeString(opcode) << " operand index " + << operand_index; + } + spv_result_t ret = + _.CooperativeMatrixShapesMatch(inst, type_id, result_type); + if (ret != SPV_SUCCESS) return ret; + } + if (!type_id || (!_.IsIntScalarType(type_id) && !_.IsIntVectorType(type_id) && - !(supportsCoopMat && _.IsIntCooperativeMatrixType(result_type)))) + !(supportsCoopMat && _.IsIntCooperativeMatrixType(result_type)) && + !(opcode == spv::Op::OpIMul && + _.IsCooperativeMatrixKHRType(result_type) && + _.IsIntCooperativeMatrixType(result_type)))) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected int scalar or vector type as operand: " << spvOpcodeString(opcode) << " operand index " @@ -187,7 +234,7 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) { case spv::Op::OpMatrixTimesScalar: { if (!_.IsFloatMatrixType(result_type) && - !_.IsCooperativeMatrixType(result_type)) + !(_.IsCooperativeMatrixType(result_type))) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected float matrix type as Result Type: " << spvOpcodeString(opcode); @@ -459,22 +506,108 @@ spv_result_t ArithmeticsPass(ValidationState_t& _, const Instruction* inst) { const uint32_t B_type_id = _.GetOperandTypeId(inst, 3); const uint32_t C_type_id = _.GetOperandTypeId(inst, 4); - if (!_.IsCooperativeMatrixType(A_type_id)) { + if (!_.IsCooperativeMatrixNVType(A_type_id)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected cooperative matrix type as A Type: " << spvOpcodeString(opcode); } - if (!_.IsCooperativeMatrixType(B_type_id)) { + if (!_.IsCooperativeMatrixNVType(B_type_id)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected cooperative matrix type as B Type: " << spvOpcodeString(opcode); } - if (!_.IsCooperativeMatrixType(C_type_id)) { + if (!_.IsCooperativeMatrixNVType(C_type_id)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected cooperative matrix type as C Type: " << spvOpcodeString(opcode); } - if (!_.IsCooperativeMatrixType(D_type_id)) { + if (!_.IsCooperativeMatrixNVType(D_type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected cooperative matrix type as Result Type: " + << spvOpcodeString(opcode); + } + + const auto A = _.FindDef(A_type_id); + const auto B = _.FindDef(B_type_id); + const auto C = _.FindDef(C_type_id); + const auto D = _.FindDef(D_type_id); + + std::tuple A_scope, B_scope, C_scope, D_scope, + A_rows, B_rows, C_rows, D_rows, A_cols, B_cols, C_cols, D_cols; + + A_scope = _.EvalInt32IfConst(A->GetOperandAs(2)); + B_scope = _.EvalInt32IfConst(B->GetOperandAs(2)); + C_scope = _.EvalInt32IfConst(C->GetOperandAs(2)); + D_scope = _.EvalInt32IfConst(D->GetOperandAs(2)); + + A_rows = _.EvalInt32IfConst(A->GetOperandAs(3)); + B_rows = _.EvalInt32IfConst(B->GetOperandAs(3)); + C_rows = _.EvalInt32IfConst(C->GetOperandAs(3)); + D_rows = _.EvalInt32IfConst(D->GetOperandAs(3)); + + A_cols = _.EvalInt32IfConst(A->GetOperandAs(4)); + B_cols = _.EvalInt32IfConst(B->GetOperandAs(4)); + C_cols = _.EvalInt32IfConst(C->GetOperandAs(4)); + D_cols = _.EvalInt32IfConst(D->GetOperandAs(4)); + + const auto notEqual = [](std::tuple X, + std::tuple Y) { + return (std::get<1>(X) && std::get<1>(Y) && + std::get<2>(X) != std::get<2>(Y)); + }; + + if (notEqual(A_scope, B_scope) || notEqual(A_scope, C_scope) || + notEqual(A_scope, D_scope) || notEqual(B_scope, C_scope) || + notEqual(B_scope, D_scope) || notEqual(C_scope, D_scope)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cooperative matrix scopes must match: " + << spvOpcodeString(opcode); + } + + if (notEqual(A_rows, C_rows) || notEqual(A_rows, D_rows) || + notEqual(C_rows, D_rows)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cooperative matrix 'M' mismatch: " + << spvOpcodeString(opcode); + } + + if (notEqual(B_cols, C_cols) || notEqual(B_cols, D_cols) || + notEqual(C_cols, D_cols)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cooperative matrix 'N' mismatch: " + << spvOpcodeString(opcode); + } + + if (notEqual(A_cols, B_rows)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cooperative matrix 'K' mismatch: " + << spvOpcodeString(opcode); + } + break; + } + + case spv::Op::OpCooperativeMatrixMulAddKHR: { + const uint32_t D_type_id = _.GetOperandTypeId(inst, 1); + const uint32_t A_type_id = _.GetOperandTypeId(inst, 2); + const uint32_t B_type_id = _.GetOperandTypeId(inst, 3); + const uint32_t C_type_id = _.GetOperandTypeId(inst, 4); + + if (!_.IsCooperativeMatrixAType(A_type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cooperative matrix type must be A Type: " + << spvOpcodeString(opcode); + } + if (!_.IsCooperativeMatrixBType(B_type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cooperative matrix type must be B Type: " + << spvOpcodeString(opcode); + } + if (!_.IsCooperativeMatrixAccType(C_type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cooperative matrix type must be Accumulator Type: " + << spvOpcodeString(opcode); + } + if (!_.IsCooperativeMatrixKHRType(D_type_id)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected cooperative matrix type as Result Type: " << spvOpcodeString(opcode); diff --git a/source/val/validate_composites.cpp b/source/val/validate_composites.cpp index 2b83c63dd2..ed043b688a 100644 --- a/source/val/validate_composites.cpp +++ b/source/val/validate_composites.cpp @@ -122,6 +122,7 @@ spv_result_t GetExtractInsertValueType(ValidationState_t& _, *member_type = type_inst->word(component_index + 2); break; } + case spv::Op::OpTypeCooperativeMatrixKHR: case spv::Op::OpTypeCooperativeMatrixNV: { *member_type = type_inst->word(2); break; @@ -335,6 +336,25 @@ spv_result_t ValidateCompositeConstruct(ValidationState_t& _, break; } + case spv::Op::OpTypeCooperativeMatrixKHR: { + const auto result_type_inst = _.FindDef(result_type); + assert(result_type_inst); + const auto component_type_id = + result_type_inst->GetOperandAs(1); + + if (3 != num_operands) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Must be only one constituent"; + } + + const uint32_t operand_type_id = _.GetOperandTypeId(inst, 2); + + if (operand_type_id != component_type_id) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Constituent type to be equal to the component type"; + } + break; + } case spv::Op::OpTypeCooperativeMatrixNV: { const auto result_type_inst = _.FindDef(result_type); assert(result_type_inst); diff --git a/source/val/validate_constants.cpp b/source/val/validate_constants.cpp index 006e504c0c..4deaa49688 100644 --- a/source/val/validate_constants.cpp +++ b/source/val/validate_constants.cpp @@ -243,6 +243,7 @@ spv_result_t ValidateConstantComposite(ValidationState_t& _, } } } break; + case spv::Op::OpTypeCooperativeMatrixKHR: case spv::Op::OpTypeCooperativeMatrixNV: { if (1 != constituent_count) { return _.diag(SPV_ERROR_INVALID_ID, inst) @@ -310,6 +311,7 @@ bool IsTypeNullable(const std::vector& instruction, case spv::Op::OpTypeArray: case spv::Op::OpTypeMatrix: case spv::Op::OpTypeCooperativeMatrixNV: + case spv::Op::OpTypeCooperativeMatrixKHR: case spv::Op::OpTypeVector: { auto base_type = _.FindDef(instruction[2]); return base_type && IsTypeNullable(base_type->words(), _); diff --git a/source/val/validate_conversion.cpp b/source/val/validate_conversion.cpp index 476c1fe8b1..b2892a8630 100644 --- a/source/val/validate_conversion.cpp +++ b/source/val/validate_conversion.cpp @@ -473,7 +473,10 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) { const bool input_is_pointer = _.IsPointerType(input_type); const bool input_is_int_scalar = _.IsIntScalarType(input_type); - if (!result_is_pointer && !result_is_int_scalar && + const bool result_is_coopmat = _.IsCooperativeMatrixType(result_type); + const bool input_is_coopmat = _.IsCooperativeMatrixType(input_type); + + if (!result_is_pointer && !result_is_int_scalar && !result_is_coopmat && !_.IsIntVectorType(result_type) && !_.IsFloatScalarType(result_type) && !_.IsFloatVectorType(result_type)) @@ -481,13 +484,24 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) { << "Expected Result Type to be a pointer or int or float vector " << "or scalar type: " << spvOpcodeString(opcode); - if (!input_is_pointer && !input_is_int_scalar && + if (!input_is_pointer && !input_is_int_scalar && !input_is_coopmat && !_.IsIntVectorType(input_type) && !_.IsFloatScalarType(input_type) && !_.IsFloatVectorType(input_type)) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected input to be a pointer or int or float vector " << "or scalar: " << spvOpcodeString(opcode); + if (result_is_coopmat != input_is_coopmat) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Cooperative matrix can only be cast to another cooperative " + << "matrix: " << spvOpcodeString(opcode); + + if (result_is_coopmat) { + spv_result_t ret = + _.CooperativeMatrixShapesMatch(inst, result_type, input_type); + if (ret != SPV_SUCCESS) return ret; + } + if (_.version() >= SPV_SPIRV_VERSION_WORD(1, 5) || _.HasExtension(kSPV_KHR_physical_storage_buffer)) { const bool result_is_int_vector = _.IsIntVectorType(result_type); diff --git a/source/val/validate_id.cpp b/source/val/validate_id.cpp index 92a4e8e33d..bcfeb5915e 100644 --- a/source/val/validate_id.cpp +++ b/source/val/validate_id.cpp @@ -163,9 +163,12 @@ spv_result_t IdPass(ValidationState_t& _, Instruction* inst) { !inst->IsDebugInfo() && !inst->IsNonSemantic() && !spvOpcodeIsDecoration(opcode) && opcode != spv::Op::OpFunction && opcode != spv::Op::OpCooperativeMatrixLengthNV && + opcode != spv::Op::OpCooperativeMatrixLengthKHR && !(opcode == spv::Op::OpSpecConstantOp && - spv::Op(inst->word(3)) == - spv::Op::OpCooperativeMatrixLengthNV)) { + (spv::Op(inst->word(3)) == + spv::Op::OpCooperativeMatrixLengthNV || + spv::Op(inst->word(3)) == + spv::Op::OpCooperativeMatrixLengthKHR))) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Operand " << _.getIdName(operand_word) << " cannot be a type"; @@ -179,9 +182,12 @@ spv_result_t IdPass(ValidationState_t& _, Instruction* inst) { opcode != spv::Op::OpLoopMerge && opcode != spv::Op::OpFunction && opcode != spv::Op::OpCooperativeMatrixLengthNV && + opcode != spv::Op::OpCooperativeMatrixLengthKHR && !(opcode == spv::Op::OpSpecConstantOp && - spv::Op(inst->word(3)) == - spv::Op::OpCooperativeMatrixLengthNV)) { + (spv::Op(inst->word(3)) == + spv::Op::OpCooperativeMatrixLengthNV || + spv::Op(inst->word(3)) == + spv::Op::OpCooperativeMatrixLengthKHR))) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Operand " << _.getIdName(operand_word) << " requires a type"; diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index 975a55cc1b..f039496b39 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -204,6 +204,7 @@ bool ContainsCooperativeMatrix(ValidationState_t& _, switch (storage->opcode()) { case spv::Op::OpTypeCooperativeMatrixNV: + case spv::Op::OpTypeCooperativeMatrixKHR: return true; case spv::Op::OpTypeArray: case spv::Op::OpTypeRuntimeArray: @@ -232,6 +233,7 @@ std::pair GetStorageClass( spv::StorageClass src_sc = spv::StorageClass::Max; switch (inst->opcode()) { case spv::Op::OpCooperativeMatrixLoadNV: + case spv::Op::OpCooperativeMatrixLoadKHR: case spv::Op::OpLoad: { auto load_pointer = _.FindDef(inst->GetOperandAs(2)); auto load_pointer_type = _.FindDef(load_pointer->type_id()); @@ -239,6 +241,7 @@ std::pair GetStorageClass( break; } case spv::Op::OpCooperativeMatrixStoreNV: + case spv::Op::OpCooperativeMatrixStoreKHR: case spv::Op::OpStore: { auto store_pointer = _.FindDef(inst->GetOperandAs(0)); auto store_pointer_type = _.FindDef(store_pointer->type_id()); @@ -326,7 +329,8 @@ spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst, const uint32_t mask = inst->GetOperandAs(index); if (mask & uint32_t(spv::MemoryAccessMask::MakePointerAvailableKHR)) { if (inst->opcode() == spv::Op::OpLoad || - inst->opcode() == spv::Op::OpCooperativeMatrixLoadNV) { + inst->opcode() == spv::Op::OpCooperativeMatrixLoadNV || + inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "MakePointerAvailableKHR cannot be used with OpLoad."; } @@ -1357,6 +1361,7 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, case spv::Op::OpTypeMatrix: case spv::Op::OpTypeVector: case spv::Op::OpTypeCooperativeMatrixNV: + case spv::Op::OpTypeCooperativeMatrixKHR: case spv::Op::OpTypeArray: case spv::Op::OpTypeRuntimeArray: { // In OpTypeMatrix, OpTypeVector, spv::Op::OpTypeCooperativeMatrixNV, @@ -1554,9 +1559,15 @@ spv_result_t ValidateCooperativeMatrixLengthNV(ValidationState_t& state, << " must be OpTypeInt with width 32 and signedness 0."; } + bool isKhr = inst->opcode() == spv::Op::OpCooperativeMatrixLengthKHR; auto type_id = inst->GetOperandAs(2); auto type = state.FindDef(type_id); - if (type->opcode() != spv::Op::OpTypeCooperativeMatrixNV) { + if (isKhr && type->opcode() != spv::Op::OpTypeCooperativeMatrixKHR) { + return state.diag(SPV_ERROR_INVALID_ID, inst) + << "The type in " << instr_name << " " + << state.getIdName(type_id) + << " must be OpTypeCooperativeMatrixKHR."; + } else if (!isKhr && type->opcode() != spv::Op::OpTypeCooperativeMatrixNV) { return state.diag(SPV_ERROR_INVALID_ID, inst) << "The type in " << instr_name << " " << state.getIdName(type_id) << " must be OpTypeCooperativeMatrixNV."; @@ -1668,6 +1679,112 @@ spv_result_t ValidateCooperativeMatrixLoadStoreNV(ValidationState_t& _, return SPV_SUCCESS; } +spv_result_t ValidateCooperativeMatrixLoadStoreKHR(ValidationState_t& _, + const Instruction* inst) { + uint32_t type_id; + const char* opname; + if (inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) { + type_id = inst->type_id(); + opname = "spv::Op::OpCooperativeMatrixLoadKHR"; + } else { + // get Object operand's type + type_id = _.FindDef(inst->GetOperandAs(1))->type_id(); + opname = "spv::Op::OpCooperativeMatrixStoreKHR"; + } + + auto matrix_type = _.FindDef(type_id); + + if (matrix_type->opcode() != spv::Op::OpTypeCooperativeMatrixKHR) { + if (inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "spv::Op::OpCooperativeMatrixLoadKHR Result Type " + << _.getIdName(type_id) << " is not a cooperative matrix type."; + } else { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "spv::Op::OpCooperativeMatrixStoreKHR Object type " + << _.getIdName(type_id) << " is not a cooperative matrix type."; + } + } + + const auto pointer_index = + (inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) ? 2u : 0u; + const auto pointer_id = inst->GetOperandAs(pointer_index); + const auto pointer = _.FindDef(pointer_id); + if (!pointer || + ((_.addressing_model() == spv::AddressingModel::Logical) && + ((!_.features().variable_pointers && + !spvOpcodeReturnsLogicalPointer(pointer->opcode())) || + (_.features().variable_pointers && + !spvOpcodeReturnsLogicalVariablePointer(pointer->opcode()))))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << opname << " Pointer " << _.getIdName(pointer_id) + << " is not a logical pointer."; + } + + const auto pointer_type_id = pointer->type_id(); + const auto pointer_type = _.FindDef(pointer_type_id); + if (!pointer_type || pointer_type->opcode() != spv::Op::OpTypePointer) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << opname << " type for pointer " << _.getIdName(pointer_id) + << " is not a pointer type."; + } + + const auto storage_class_index = 1u; + const auto storage_class = + pointer_type->GetOperandAs(storage_class_index); + + if (storage_class != spv::StorageClass::Workgroup && + storage_class != spv::StorageClass::StorageBuffer && + storage_class != spv::StorageClass::PhysicalStorageBuffer) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << opname << " storage class for pointer type " + << _.getIdName(pointer_type_id) + << " is not Workgroup or StorageBuffer."; + } + + const auto pointee_id = pointer_type->GetOperandAs(2); + const auto pointee_type = _.FindDef(pointee_id); + if (!pointee_type || !(_.IsIntScalarOrVectorType(pointee_id) || + _.IsFloatScalarOrVectorType(pointee_id))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << opname << " Pointer " << _.getIdName(pointer->id()) + << "s Type must be a scalar or vector type."; + } + + const auto layout_index = + (inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) ? 3u : 2u; + const auto colmajor_id = inst->GetOperandAs(layout_index); + const auto colmajor = _.FindDef(colmajor_id); + if (!colmajor || !_.IsIntScalarType(colmajor->type_id()) || + !(spvOpcodeIsConstant(colmajor->opcode()) || + spvOpcodeIsSpecConstant(colmajor->opcode()))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "MemoryLayout operand " << _.getIdName(colmajor_id) + << " must be a 32-bit integer constant instruction."; + } + + const auto stride_index = + (inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) ? 4u : 3u; + if (inst->operands().size() > stride_index) { + const auto stride_id = inst->GetOperandAs(stride_index); + const auto stride = _.FindDef(stride_id); + if (!stride || !_.IsIntScalarType(stride->type_id())) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Stride operand " << _.getIdName(stride_id) + << " must be a scalar integer type."; + } + } + + const auto memory_access_index = + (inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) ? 5u : 4u; + if (inst->operands().size() > memory_access_index) { + if (auto error = CheckMemoryAccess(_, inst, memory_access_index)) + return error; + } + + return SPV_SUCCESS; +} + spv_result_t ValidatePtrComparison(ValidationState_t& _, const Instruction* inst) { if (_.addressing_model() == spv::AddressingModel::Logical && @@ -1757,9 +1874,15 @@ spv_result_t MemoryPass(ValidationState_t& _, const Instruction* inst) { if (auto error = ValidateCooperativeMatrixLoadStoreNV(_, inst)) return error; break; + case spv::Op::OpCooperativeMatrixLengthKHR: case spv::Op::OpCooperativeMatrixLengthNV: if (auto error = ValidateCooperativeMatrixLengthNV(_, inst)) return error; break; + case spv::Op::OpCooperativeMatrixLoadKHR: + case spv::Op::OpCooperativeMatrixStoreKHR: + if (auto error = ValidateCooperativeMatrixLoadStoreKHR(_, inst)) + return error; + break; case spv::Op::OpPtrEqual: case spv::Op::OpPtrNotEqual: case spv::Op::OpPtrDiff: diff --git a/source/val/validate_type.cpp b/source/val/validate_type.cpp index 430d819084..7edd12ffaf 100644 --- a/source/val/validate_type.cpp +++ b/source/val/validate_type.cpp @@ -552,8 +552,8 @@ spv_result_t ValidateTypeForwardPointer(ValidationState_t& _, return SPV_SUCCESS; } -spv_result_t ValidateTypeCooperativeMatrixNV(ValidationState_t& _, - const Instruction* inst) { +spv_result_t ValidateTypeCooperativeMatrix(ValidationState_t& _, + const Instruction* inst) { const auto component_type_index = 1; const auto component_type_id = inst->GetOperandAs(component_type_index); @@ -561,7 +561,7 @@ spv_result_t ValidateTypeCooperativeMatrixNV(ValidationState_t& _, if (!component_type || (spv::Op::OpTypeFloat != component_type->opcode() && spv::Op::OpTypeInt != component_type->opcode())) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpTypeCooperativeMatrixNV Component Type " + << "OpTypeCooperativeMatrix Component Type " << _.getIdName(component_type_id) << " is not a scalar numerical type."; } @@ -572,7 +572,7 @@ spv_result_t ValidateTypeCooperativeMatrixNV(ValidationState_t& _, if (!scope || !_.IsIntScalarType(scope->type_id()) || !spvOpcodeIsConstant(scope->opcode())) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpTypeCooperativeMatrixNV Scope " << _.getIdName(scope_id) + << "OpTypeCooperativeMatrix Scope " << _.getIdName(scope_id) << " is not a constant instruction with scalar integer type."; } @@ -582,7 +582,7 @@ spv_result_t ValidateTypeCooperativeMatrixNV(ValidationState_t& _, if (!rows || !_.IsIntScalarType(rows->type_id()) || !spvOpcodeIsConstant(rows->opcode())) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpTypeCooperativeMatrixNV Rows " << _.getIdName(rows_id) + << "OpTypeCooperativeMatrix Rows " << _.getIdName(rows_id) << " is not a constant instruction with scalar integer type."; } @@ -592,10 +592,22 @@ spv_result_t ValidateTypeCooperativeMatrixNV(ValidationState_t& _, if (!cols || !_.IsIntScalarType(cols->type_id()) || !spvOpcodeIsConstant(cols->opcode())) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpTypeCooperativeMatrixNV Cols " << _.getIdName(cols_id) + << "OpTypeCooperativeMatrix Cols " << _.getIdName(cols_id) << " is not a constant instruction with scalar integer type."; } + if (inst->opcode() == spv::Op::OpTypeCooperativeMatrixKHR) { + const auto use_index = 5; + const auto use_id = inst->GetOperandAs(use_index); + const auto use = _.FindDef(use_id); + if (!use || !_.IsIntScalarType(use->type_id()) || + !spvOpcodeIsConstant(use->opcode())) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpTypeCooperativeMatrixKHR Use " << _.getIdName(use_id) + << " is not a constant instruction with scalar integer type."; + } + } + return SPV_SUCCESS; } } // namespace @@ -640,7 +652,8 @@ spv_result_t TypePass(ValidationState_t& _, const Instruction* inst) { if (auto error = ValidateTypeForwardPointer(_, inst)) return error; break; case spv::Op::OpTypeCooperativeMatrixNV: - if (auto error = ValidateTypeCooperativeMatrixNV(_, inst)) return error; + case spv::Op::OpTypeCooperativeMatrixKHR: + if (auto error = ValidateTypeCooperativeMatrix(_, inst)) return error; break; default: break; diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 5a138d95dc..cde8aaadaf 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -859,6 +859,7 @@ uint32_t ValidationState_t::GetComponentType(uint32_t id) const { return GetComponentType(inst->word(2)); case spv::Op::OpTypeCooperativeMatrixNV: + case spv::Op::OpTypeCooperativeMatrixKHR: return inst->word(2); default: @@ -886,6 +887,7 @@ uint32_t ValidationState_t::GetDimension(uint32_t id) const { return inst->word(3); case spv::Op::OpTypeCooperativeMatrixNV: + case spv::Op::OpTypeCooperativeMatrixKHR: // Actual dimension isn't known, return 0 return 0; @@ -1142,22 +1144,68 @@ bool ValidationState_t::IsAccelerationStructureType(uint32_t id) const { } bool ValidationState_t::IsCooperativeMatrixType(uint32_t id) const { + const Instruction* inst = FindDef(id); + return inst && (inst->opcode() == spv::Op::OpTypeCooperativeMatrixNV || + inst->opcode() == spv::Op::OpTypeCooperativeMatrixKHR); +} + +bool ValidationState_t::IsCooperativeMatrixNVType(uint32_t id) const { const Instruction* inst = FindDef(id); return inst && inst->opcode() == spv::Op::OpTypeCooperativeMatrixNV; } +bool ValidationState_t::IsCooperativeMatrixKHRType(uint32_t id) const { + const Instruction* inst = FindDef(id); + return inst && inst->opcode() == spv::Op::OpTypeCooperativeMatrixKHR; +} + +bool ValidationState_t::IsCooperativeMatrixAType(uint32_t id) const { + if (!IsCooperativeMatrixKHRType(id)) return false; + const Instruction* inst = FindDef(id); + uint64_t matrixUse = 0; + if (GetConstantValUint64(inst->word(6), &matrixUse)) { + return matrixUse == + static_cast(spv::CooperativeMatrixUse::MatrixAKHR); + } + return false; +} + +bool ValidationState_t::IsCooperativeMatrixBType(uint32_t id) const { + if (!IsCooperativeMatrixKHRType(id)) return false; + const Instruction* inst = FindDef(id); + uint64_t matrixUse = 0; + if (GetConstantValUint64(inst->word(6), &matrixUse)) { + return matrixUse == + static_cast(spv::CooperativeMatrixUse::MatrixBKHR); + } + return false; +} +bool ValidationState_t::IsCooperativeMatrixAccType(uint32_t id) const { + if (!IsCooperativeMatrixKHRType(id)) return false; + const Instruction* inst = FindDef(id); + uint64_t matrixUse = 0; + if (GetConstantValUint64(inst->word(6), &matrixUse)) { + return matrixUse == static_cast( + spv::CooperativeMatrixUse::MatrixAccumulatorKHR); + } + return false; +} + bool ValidationState_t::IsFloatCooperativeMatrixType(uint32_t id) const { - if (!IsCooperativeMatrixType(id)) return false; + if (!IsCooperativeMatrixNVType(id) && !IsCooperativeMatrixKHRType(id)) + return false; return IsFloatScalarType(FindDef(id)->word(2)); } bool ValidationState_t::IsIntCooperativeMatrixType(uint32_t id) const { - if (!IsCooperativeMatrixType(id)) return false; + if (!IsCooperativeMatrixNVType(id) && !IsCooperativeMatrixKHRType(id)) + return false; return IsIntScalarType(FindDef(id)->word(2)); } bool ValidationState_t::IsUnsignedIntCooperativeMatrixType(uint32_t id) const { - if (!IsCooperativeMatrixType(id)) return false; + if (!IsCooperativeMatrixNVType(id) && !IsCooperativeMatrixKHRType(id)) + return false; return IsUnsignedIntScalarType(FindDef(id)->word(2)); } @@ -1173,8 +1221,7 @@ spv_result_t ValidationState_t::CooperativeMatrixShapesMatch( const auto m1_type = FindDef(m1); const auto m2_type = FindDef(m2); - if (m1_type->opcode() != spv::Op::OpTypeCooperativeMatrixNV || - m2_type->opcode() != spv::Op::OpTypeCooperativeMatrixNV) { + if (m1_type->opcode() != m2_type->opcode()) { return diag(SPV_ERROR_INVALID_DATA, inst) << "Expected cooperative matrix types"; } @@ -1224,6 +1271,21 @@ spv_result_t ValidationState_t::CooperativeMatrixShapesMatch( << "identical"; } + if (m1_type->opcode() == spv::Op::OpTypeCooperativeMatrixKHR) { + uint32_t m1_use_id = m1_type->GetOperandAs(5); + uint32_t m2_use_id = m2_type->GetOperandAs(5); + std::tie(m1_is_int32, m1_is_const_int32, m1_value) = + EvalInt32IfConst(m1_use_id); + std::tie(m2_is_int32, m2_is_const_int32, m2_value) = + EvalInt32IfConst(m2_use_id); + + if (m1_is_const_int32 && m2_is_const_int32 && m1_value != m2_value) { + return diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Use of Matrix type and Result Type to be " + << "identical"; + } + } + return SPV_SUCCESS; } @@ -1489,6 +1551,7 @@ bool ValidationState_t::ContainsType( case spv::Op::OpTypeImage: case spv::Op::OpTypeSampledImage: case spv::Op::OpTypeCooperativeMatrixNV: + case spv::Op::OpTypeCooperativeMatrixKHR: return ContainsType(inst->GetOperandAs(1u), f, traverse_all_types); case spv::Op::OpTypePointer: diff --git a/source/val/validation_state.h b/source/val/validation_state.h index 4d5ac00618..bfae821478 100644 --- a/source/val/validation_state.h +++ b/source/val/validation_state.h @@ -610,6 +610,11 @@ class ValidationState_t { bool IsPointerType(uint32_t id) const; bool IsAccelerationStructureType(uint32_t id) const; bool IsCooperativeMatrixType(uint32_t id) const; + bool IsCooperativeMatrixNVType(uint32_t id) const; + bool IsCooperativeMatrixKHRType(uint32_t id) const; + bool IsCooperativeMatrixAType(uint32_t id) const; + bool IsCooperativeMatrixBType(uint32_t id) const; + bool IsCooperativeMatrixAccType(uint32_t id) const; bool IsFloatCooperativeMatrixType(uint32_t id) const; bool IsIntCooperativeMatrixType(uint32_t id) const; bool IsUnsignedIntCooperativeMatrixType(uint32_t id) const; diff --git a/test/opt/type_manager_test.cpp b/test/opt/type_manager_test.cpp index 563eb74012..cb30171158 100644 --- a/test/opt/type_manager_test.cpp +++ b/test/opt/type_manager_test.cpp @@ -171,6 +171,7 @@ std::vector> GenerateAllTypes() { types.emplace_back(new NamedBarrier()); types.emplace_back(new AccelerationStructureNV()); types.emplace_back(new CooperativeMatrixNV(f32, 24, 24, 24)); + types.emplace_back(new CooperativeMatrixKHR(f32, 8, 8, 8, 1002)); types.emplace_back(new RayQueryKHR()); types.emplace_back(new HitObjectNV()); @@ -237,6 +238,8 @@ TEST(TypeManager, TypeStrings) { %arr_long_constant = OpTypeArray %s32 %long_constant %arr_spec_const_op = OpTypeArray %s32 %spec_const_op %cm = OpTypeCooperativeMatrixNV %f64 %id4 %id4 %id4 + %id2 = OpConstant %u32 2 + %cmkhr = OpTypeCooperativeMatrixKHR %f64 %id4 %id4 %id4 %id2 )"; std::vector> type_id_strs = { @@ -275,6 +278,7 @@ TEST(TypeManager, TypeStrings) { {37, "[sint32, id(33), words(0,705032704,1)]"}, {38, "[sint32, id(34), words(2,34)]"}, {39, ""}, + {41, ""}, }; std::unique_ptr context = @@ -940,12 +944,15 @@ OpMemoryModel Logical GLSL450 std::vector> types = GenerateAllTypes(); uint32_t id = 1u; for (auto& t : types) { + std::cout << ". id " << id << std::endl; context->get_type_mgr()->RegisterType(id, *t); EXPECT_EQ(*t, *context->get_type_mgr()->GetType(id)); } + std::cout << "clear" << id << std::endl; types.clear(); for (; id > 0; --id) { + std::cout << ". remove id " << id << std::endl; context->get_type_mgr()->RemoveId(id); EXPECT_EQ(nullptr, context->get_type_mgr()->GetType(id)); } @@ -1030,6 +1037,8 @@ TEST(TypeManager, GetTypeInstructionAllTypes) { ; CHECK: [[uint:%\w+]] = OpTypeInt 32 0 ; CHECK: [[input_ptr:%\w+]] = OpTypePointer Input [[uint]] ; CHECK: [[uniform_ptr:%\w+]] = OpTypePointer Uniform [[uint]] +; CHECK: [[uint2:%\w+]] = OpConstant [[uint]] 2 +; CHECK: [[uint8:%\w+]] = OpConstant [[uint]] 8 ; CHECK: [[uint24:%\w+]] = OpConstant [[uint]] 24 ; CHECK: [[uint42:%\w+]] = OpConstant [[uint]] 42 ; CHECK: [[uint100:%\w+]] = OpConstant [[uint]] 100 @@ -1085,6 +1094,7 @@ TEST(TypeManager, GetTypeInstructionAllTypes) { ; CHECK: OpTypeNamedBarrier ; CHECK: OpTypeAccelerationStructureKHR ; CHECK: OpTypeCooperativeMatrixNV [[f32]] [[uint24]] [[uint24]] [[uint24]] +; CHECK: OpTypeCooperativeMatrixKHR [[f32]] [[uint8]] [[uint8]] [[uint8]] [[uint2]] ; CHECK: OpTypeRayQueryKHR ; CHECK: OpTypeHitObjectNV OpCapability Shader @@ -1094,6 +1104,8 @@ OpMemoryModel Logical GLSL450 %uint = OpTypeInt 32 0 %1 = OpTypePointer Input %uint %2 = OpTypePointer Uniform %uint +%1002 = OpConstant %uint 2 +%8 = OpConstant %uint 8 %24 = OpConstant %uint 24 %42 = OpConstant %uint 42 %100 = OpConstant %uint 100 diff --git a/test/val/val_arithmetics_test.cpp b/test/val/val_arithmetics_test.cpp index 631375efb6..06c4e3984a 100644 --- a/test/val/val_arithmetics_test.cpp +++ b/test/val/val_arithmetics_test.cpp @@ -1318,7 +1318,7 @@ TEST_F(ValidateArithmetics, CoopMatComponentTypeNotScalarNumeric) { CompileSuccessfully(GenerateCoopMatCode(types, "").c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpTypeCooperativeMatrixNV Component Type " + HasSubstr("OpTypeCooperativeMatrix Component Type " "'4[%bool]' is not a scalar numerical type.")); } @@ -1331,7 +1331,7 @@ TEST_F(ValidateArithmetics, CoopMatScopeNotConstantInt) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpTypeCooperativeMatrixNV Scope '17[%float_1]' is not a " + HasSubstr("OpTypeCooperativeMatrix Scope '17[%float_1]' is not a " "constant instruction with scalar integer type.")); } @@ -1344,7 +1344,7 @@ TEST_F(ValidateArithmetics, CoopMatRowsNotConstantInt) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpTypeCooperativeMatrixNV Rows '17[%float_1]' is not a " + HasSubstr("OpTypeCooperativeMatrix Rows '17[%float_1]' is not a " "constant instruction with scalar integer type.")); } @@ -1357,7 +1357,7 @@ TEST_F(ValidateArithmetics, CoopMatColumnsNotConstantInt) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("OpTypeCooperativeMatrixNV Cols '17[%float_1]' is not a " + HasSubstr("OpTypeCooperativeMatrix Cols '17[%float_1]' is not a " "constant instruction with scalar integer type.")); } @@ -1469,6 +1469,146 @@ TEST_F(ValidateArithmetics, SMulExtendedResultTypeMembersNotIdentical) { "SMulExtended")); } +std::string GenerateCoopMatKHRCode(const std::string& extra_types, + const std::string& main_body) { + const std::string prefix = R"( +OpCapability Shader +OpCapability Float16 +OpCapability CooperativeMatrixKHR +OpExtension "SPV_KHR_cooperative_matrix" +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f16 = OpTypeFloat 16 +%f32 = OpTypeFloat 32 +%u32 = OpTypeInt 32 0 +%s32 = OpTypeInt 32 1 + +%u32_16 = OpConstant %u32 16 +%u32_4 = OpConstant %u32 4 +%subgroup = OpConstant %u32 3 +%useA = OpConstant %u32 0 +%useB = OpConstant %u32 1 +%useC = OpConstant %u32 2 + +%f16matA = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_16 %u32_16 %useA +%u32matA = OpTypeCooperativeMatrixKHR %u32 %subgroup %u32_16 %u32_16 %useA +%s32matA = OpTypeCooperativeMatrixKHR %s32 %subgroup %u32_16 %u32_16 %useA + +%f16matB = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_16 %u32_16 %useB +%u32matB = OpTypeCooperativeMatrixKHR %u32 %subgroup %u32_16 %u32_16 %useB +%s32matB = OpTypeCooperativeMatrixKHR %s32 %subgroup %u32_16 %u32_16 %useB + +%f16matC = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_16 %u32_16 %useC +%f32matC = OpTypeCooperativeMatrixKHR %f32 %subgroup %u32_16 %u32_16 %useC +%u32matC = OpTypeCooperativeMatrixKHR %u32 %subgroup %u32_16 %u32_16 %useC +%s32matC = OpTypeCooperativeMatrixKHR %s32 %subgroup %u32_16 %u32_16 %useC + +%f16_1 = OpConstant %f16 1 +%f32_1 = OpConstant %f32 1 +%u32_1 = OpConstant %u32 1 +%s32_1 = OpConstant %s32 1 + +%f16mat_A_1 = OpConstantComposite %f16matA %f16_1 +%u32mat_A_1 = OpConstantComposite %u32matA %u32_1 +%s32mat_A_1 = OpConstantComposite %s32matA %s32_1 + +%f16mat_B_1 = OpConstantComposite %f16matB %f16_1 +%u32mat_B_1 = OpConstantComposite %u32matB %u32_1 +%s32mat_B_1 = OpConstantComposite %s32matB %s32_1 + +%f16mat_C_1 = OpConstantComposite %f16matC %f16_1 +%u32mat_C_1 = OpConstantComposite %u32matC %u32_1 +%s32mat_C_1 = OpConstantComposite %s32matC %s32_1 + +)"; + + const std::string func_begin = R"( +%main = OpFunction %void None %func +%main_entry = OpLabel)"; + + const std::string suffix = R"( +OpReturn +OpFunctionEnd)"; + + return prefix + extra_types + func_begin + main_body + suffix; +} + +TEST_F(ValidateArithmetics, CoopMatKHRSuccess) { + const std::string body = R"( +%val1 = OpFAdd %f16matA %f16mat_A_1 %f16mat_A_1 +%val2 = OpFSub %f16matA %f16mat_A_1 %f16mat_A_1 +%val3 = OpFMul %f16matA %f16mat_A_1 %f16mat_A_1 +%val4 = OpFDiv %f16matA %f16mat_A_1 %f16mat_A_1 +%val5 = OpFNegate %f16matA %f16mat_A_1 +%val6 = OpIAdd %u32matA %u32mat_A_1 %u32mat_A_1 +%val7 = OpISub %u32matA %u32mat_A_1 %u32mat_A_1 +%val8 = OpUDiv %u32matA %u32mat_A_1 %u32mat_A_1 +%val9 = OpIAdd %s32matA %s32mat_A_1 %s32mat_A_1 +%val10 = OpISub %s32matA %s32mat_A_1 %s32mat_A_1 +%val11 = OpSDiv %s32matA %s32mat_A_1 %s32mat_A_1 +%val12 = OpSNegate %s32matA %s32mat_A_1 +%val13 = OpMatrixTimesScalar %f16matA %f16mat_A_1 %f16_1 +%val14 = OpMatrixTimesScalar %u32matA %u32mat_A_1 %u32_1 +%val15 = OpMatrixTimesScalar %s32matA %s32mat_A_1 %s32_1 +%val16 = OpCooperativeMatrixMulAddKHR %f32matC %f16mat_A_1 %f16mat_B_1 %f16mat_C_1 +%val17 = OpCooperativeMatrixMulAddKHR %s32matC %s32mat_A_1 %s32mat_B_1 %s32mat_C_1)"; + + CompileSuccessfully(GenerateCoopMatKHRCode("", body).c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateArithmetics, CoopMatMatrixKHRTimesScalarMismatchFail) { + const std::string body = R"( +%val1 = OpMatrixTimesScalar %f16matA %f16mat_A_1 %f32_1 +)"; + + CompileSuccessfully(GenerateCoopMatKHRCode("", body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Expected scalar operand type to be equal to the component " + "type of the matrix operand: MatrixTimesScalar")); +} + +TEST_F(ValidateArithmetics, CoopMatKHRScopeFail) { + const std::string types = R"( +%workgroup = OpConstant %u32 2 +%mat16x16_wg = OpTypeCooperativeMatrixKHR %f16 %workgroup %u32_16 %u32_16 %useC +%f16matwg_16x16_1 = OpConstantComposite %mat16x16_wg %f16_1 +)"; + + const std::string body = R"( +%val1 = OpFAdd %f16matA %f16matwg_16x16_1 %f16mat_A_1 +)"; + + CompileSuccessfully(GenerateCoopMatKHRCode(types, body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Expected scopes of Matrix and Result Type to be identical")); +} + +TEST_F(ValidateArithmetics, CoopMatKHRDimFail) { + const std::string types = R"( +%mat16x4 = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_16 %u32_4 %useC +%mat16x4_C_1 = OpConstantComposite %mat16x4 %f16_1 +)"; + + const std::string body = R"( +%val1 = OpCooperativeMatrixMulAddKHR %mat16x4 %f16mat_A_1 %f16mat_B_1 %mat16x4_C_1 +)"; + + CompileSuccessfully(GenerateCoopMatKHRCode(types, body).c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Cooperative matrix 'N' mismatch: CooperativeMatrixMulAddKHR")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/test/val/val_composites_test.cpp b/test/val/val_composites_test.cpp index 0fd1ed6527..6e0d7c03c7 100644 --- a/test/val/val_composites_test.cpp +++ b/test/val/val_composites_test.cpp @@ -1486,8 +1486,7 @@ OpFunctionEnd } TEST_F(ValidateComposites, CoopMatConstantCompositeMismatchFail) { - const std::string body = - R"( + const std::string body = R"( OpCapability Shader OpCapability Float16 OpCapability CooperativeMatrixNV @@ -1525,8 +1524,7 @@ OpFunctionEnd)"; } TEST_F(ValidateComposites, CoopMatCompositeConstructMismatchFail) { - const std::string body = - R"( + const std::string body = R"( OpCapability Shader OpCapability Float16 OpCapability CooperativeMatrixNV @@ -1562,6 +1560,86 @@ OpFunctionEnd)"; HasSubstr("Expected Constituent type to be equal to the component type")); } +TEST_F(ValidateComposites, CoopMatKHRConstantCompositeMismatchFail) { + const std::string body = R"( +OpCapability Shader +OpCapability Float16 +OpCapability CooperativeMatrixKHR +OpExtension "SPV_KHR_cooperative_matrix" +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f16 = OpTypeFloat 16 +%f32 = OpTypeFloat 32 +%u32 = OpTypeInt 32 0 + +%u32_16 = OpConstant %u32 16 +%useA = OpConstant %u32 0 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_16 %u32_16 %useA + +%f32_1 = OpConstant %f32 1 + +%f16mat_1 = OpConstantComposite %f16mat %f32_1 + +%main = OpFunction %void None %func +%main_entry = OpLabel + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpConstantComposite Constituent '12[%float_1]' type " + "does not match the Result Type '11[%11]'s component type.")); +} + +TEST_F(ValidateComposites, CoopMatKHRCompositeConstructMismatchFail) { + const std::string body = R"( +OpCapability Shader +OpCapability Float16 +OpCapability CooperativeMatrixKHR +OpExtension "SPV_KHR_cooperative_matrix" +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f16 = OpTypeFloat 16 +%f32 = OpTypeFloat 32 +%u32 = OpTypeInt 32 0 + +%u32_16 = OpConstant %u32 16 +%useA = OpConstant %u32 0 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_16 %u32_16 %useA + +%f32_1 = OpConstant %f32 1 + +%main = OpFunction %void None %func +%main_entry = OpLabel + +%f16mat_1 = OpCompositeConstruct %f16mat %f32_1 + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Expected Constituent type to be equal to the component type")); +} + TEST_F(ValidateComposites, ExtractDynamicLabelIndex) { const std::string spirv = R"( OpCapability Shader diff --git a/test/val/val_conversion_test.cpp b/test/val/val_conversion_test.cpp index 1f8c4265b2..0128aa1f22 100644 --- a/test/val/val_conversion_test.cpp +++ b/test/val/val_conversion_test.cpp @@ -1149,8 +1149,7 @@ OpFunctionEnd)"; } TEST_F(ValidateConversion, CoopMatConversionShapesMismatchPass) { - const std::string body = - R"( + const std::string body = R"( OpCapability Shader OpCapability Float16 OpCapability Int16 @@ -1191,6 +1190,179 @@ OpFunctionEnd)"; ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateConversion, CoopMatKHRConversionSuccess) { + const std::string body = R"( +OpCapability Shader +OpCapability Float16 +OpCapability Int16 +OpCapability CooperativeMatrixKHR +OpExtension "SPV_KHR_cooperative_matrix" +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f16 = OpTypeFloat 16 +%f32 = OpTypeFloat 32 +%u16 = OpTypeInt 16 0 +%u32 = OpTypeInt 32 0 +%s16 = OpTypeInt 16 1 +%s32 = OpTypeInt 32 1 + +%u32_8 = OpConstant %u32 8 +%use_A = OpConstant %u32 0 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_8 %u32_8 %use_A +%f32mat = OpTypeCooperativeMatrixKHR %f32 %subgroup %u32_8 %u32_8 %use_A +%u16mat = OpTypeCooperativeMatrixKHR %u16 %subgroup %u32_8 %u32_8 %use_A +%u32mat = OpTypeCooperativeMatrixKHR %u32 %subgroup %u32_8 %u32_8 %use_A +%s16mat = OpTypeCooperativeMatrixKHR %s16 %subgroup %u32_8 %u32_8 %use_A +%s32mat = OpTypeCooperativeMatrixKHR %s32 %subgroup %u32_8 %u32_8 %use_A + +%f16_1 = OpConstant %f16 1 +%f32_1 = OpConstant %f32 1 +%u16_1 = OpConstant %u16 1 +%u32_1 = OpConstant %u32 1 +%s16_1 = OpConstant %s16 1 +%s32_1 = OpConstant %s32 1 + +%f16mat_1 = OpConstantComposite %f16mat %f16_1 +%f32mat_1 = OpConstantComposite %f32mat %f32_1 +%u16mat_1 = OpConstantComposite %u16mat %u16_1 +%u32mat_1 = OpConstantComposite %u32mat %u32_1 +%s16mat_1 = OpConstantComposite %s16mat %s16_1 +%s32mat_1 = OpConstantComposite %s32mat %s32_1 + +%main = OpFunction %void None %func +%main_entry = OpLabel + +%val11 = OpConvertFToU %u16mat %f16mat_1 +%val12 = OpConvertFToU %u32mat %f16mat_1 +%val13 = OpConvertFToS %s16mat %f16mat_1 +%val14 = OpConvertFToS %s32mat %f16mat_1 +%val15 = OpFConvert %f32mat %f16mat_1 + +%val21 = OpConvertFToU %u16mat %f32mat_1 +%val22 = OpConvertFToU %u32mat %f32mat_1 +%val23 = OpConvertFToS %s16mat %f32mat_1 +%val24 = OpConvertFToS %s32mat %f32mat_1 +%val25 = OpFConvert %f16mat %f32mat_1 + +%val31 = OpConvertUToF %f16mat %u16mat_1 +%val32 = OpConvertUToF %f32mat %u16mat_1 +%val33 = OpUConvert %u32mat %u16mat_1 +%val34 = OpSConvert %s32mat %u16mat_1 + +%val41 = OpConvertSToF %f16mat %s16mat_1 +%val42 = OpConvertSToF %f32mat %s16mat_1 +%val43 = OpUConvert %u32mat %s16mat_1 +%val44 = OpSConvert %s32mat %s16mat_1 + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateConversion, CoopMatKHRConversionUseMismatchFail) { + const std::string body = R"( +OpCapability Shader +OpCapability Float16 +OpCapability Int16 +OpCapability CooperativeMatrixKHR +OpExtension "SPV_KHR_cooperative_matrix" +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f16 = OpTypeFloat 16 +%f32 = OpTypeFloat 32 +%u16 = OpTypeInt 16 0 +%u32 = OpTypeInt 32 0 +%s16 = OpTypeInt 16 1 +%s32 = OpTypeInt 32 1 + +%u32_8 = OpConstant %u32 8 +%u32_4 = OpConstant %u32 4 +%subgroup = OpConstant %u32 3 +%use_A = OpConstant %u32 0 +%use_B = OpConstant %u32 1 + +%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_8 %u32_8 %use_A +%f32mat = OpTypeCooperativeMatrixKHR %f32 %subgroup %u32_8 %u32_8 %use_B + +%f16_1 = OpConstant %f16 1 + +%f16mat_1 = OpConstantComposite %f16mat %f16_1 + +%main = OpFunction %void None %func +%main_entry = OpLabel + +%val1 = OpFConvert %f32mat %f16mat_1 + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Expected Use of Matrix type and Result Type to be identical")); +} + +TEST_F(ValidateConversion, CoopMatKHRConversionScopeMismatchFail) { + const std::string body = R"( +OpCapability Shader +OpCapability Float16 +OpCapability Int16 +OpCapability CooperativeMatrixKHR +OpExtension "SPV_KHR_cooperative_matrix" +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%f16 = OpTypeFloat 16 +%f32 = OpTypeFloat 32 +%u16 = OpTypeInt 16 0 +%u32 = OpTypeInt 32 0 +%s16 = OpTypeInt 16 1 +%s32 = OpTypeInt 32 1 + +%u32_8 = OpConstant %u32 8 +%u32_4 = OpConstant %u32 4 +%subgroup = OpConstant %u32 3 +%workgroup = OpConstant %u32 2 +%use_A = OpConstant %u32 0 + +%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_8 %u32_8 %use_A +%f32mat = OpTypeCooperativeMatrixKHR %f32 %workgroup %u32_8 %u32_8 %use_A + +%f16_1 = OpConstant %f16 1 + +%f16mat_1 = OpConstantComposite %f16mat %f16_1 + +%main = OpFunction %void None %func +%main_entry = OpLabel + +%val1 = OpFConvert %f32mat %f16mat_1 + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Expected scopes of Matrix and Result Type to be identical")); +} + TEST_F(ValidateConversion, BitcastSuccess) { const std::string body = R"( %ptr = OpVariable %f32ptr_func Function diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp index d575318953..8d0a94d2b0 100644 --- a/test/val/val_memory_test.cpp +++ b/test/val/val_memory_test.cpp @@ -23,12 +23,14 @@ #include "test/val/val_fixtures.h" // For pretty-printing tuples with spv_target_env. -std::ostream& operator<<(std::ostream& stream, spv_target_env target) -{ +std::ostream& operator<<(std::ostream& stream, spv_target_env target) { switch (target) { - case SPV_ENV_UNIVERSAL_1_3: return stream << "SPV_ENV_UNIVERSAL_1_3"; - case SPV_ENV_UNIVERSAL_1_4: return stream << "SPV_ENV_UNIVERSAL_1_4"; - default: return stream << (unsigned)target; + case SPV_ENV_UNIVERSAL_1_3: + return stream << "SPV_ENV_UNIVERSAL_1_3"; + case SPV_ENV_UNIVERSAL_1_4: + return stream << "SPV_ENV_UNIVERSAL_1_4"; + default: + return stream << (unsigned)target; } } @@ -2346,6 +2348,186 @@ OpFunctionEnd)"; EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateMemory, CoopMatKHRLoadStoreSuccess) { + std::string spirv = + GenCoopMatLoadStoreShader("MakePointerAvailableKHR|NonPrivatePointerKHR", + "MakePointerVisibleKHR|NonPrivatePointerKHR"); + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, CoopMatKHRStoreMemoryAccessFail) { + std::string spirv = + GenCoopMatLoadStoreShader("MakePointerVisibleKHR|NonPrivatePointerKHR", + "MakePointerVisibleKHR|NonPrivatePointerKHR"); + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("MakePointerVisibleKHR cannot be used with OpStore")); +} + +TEST_F(ValidateMemory, CoopMatKHRLoadMemoryAccessFail) { + std::string spirv = + GenCoopMatLoadStoreShader("MakePointerAvailableKHR|NonPrivatePointerKHR", + "MakePointerAvailableKHR|NonPrivatePointerKHR"); + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("MakePointerAvailableKHR cannot be used with OpLoad")); +} + +TEST_F(ValidateMemory, CoopMatKHRInvalidStorageClassFail) { + const std::string body = R"( +OpCapability Shader +OpCapability Float16 +OpCapability CooperativeMatrixKHR +OpExtension "SPV_KHR_cooperative_matrix" +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%f16 = OpTypeFloat 16 +%u32 = OpTypeInt 32 0 + +%u32_8 = OpConstant %u32 8 +%use_A = OpConstant %u32 0 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_8 %u32_8 %use_A + +%str = OpTypeStruct %f16mat +%str_ptr = OpTypePointer Workgroup %str +%sh = OpVariable %str_ptr Workgroup + +%main = OpFunction %void None %func +%main_entry = OpLabel + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Cooperative matrix types (or types containing them) can only be " + "allocated in Function or Private storage classes or as function " + "parameters")); +} + +TEST_F(ValidateMemory, CoopMatMatrixKHRLengthResultTypeBad) { + const std::string body = R"( +OpCapability Shader +OpCapability Float16 +OpCapability CooperativeMatrixKHR +OpExtension "SPV_KHR_cooperative_matrix" +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%f16 = OpTypeFloat 16 +%u32 = OpTypeInt 32 0 +%i32 = OpTypeInt 32 1 + +%u32_8 = OpConstant %u32 8 +%use_A = OpConstant %u32 0 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_8 %u32_8 %use_A + +%main = OpFunction %void None %func +%main_entry = OpLabel + +%1 = OpCooperativeMatrixLengthKHR %i32 %f16mat + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("The Result Type of OpCooperativeMatrixLengthKHR " + "'12[%12]' must be OpTypeInt with width 32 and signedness 0")); +} + +TEST_F(ValidateMemory, CoopMatMatrixKHRLengthOperandTypeBad) { + const std::string body = + R"( +OpCapability Shader +OpCapability Float16 +OpCapability CooperativeMatrixKHR +OpExtension "SPV_KHR_cooperative_matrix" +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%f16 = OpTypeFloat 16 +%u32 = OpTypeInt 32 0 +%i32 = OpTypeInt 32 1 + +%u32_8 = OpConstant %u32 8 +%use_A = OpConstant %u32 0 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_8 %u32_8 %use_A + +%main = OpFunction %void None %func +%main_entry = OpLabel + +%1 = OpCooperativeMatrixLengthKHR %u32 %u32 + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("The type in OpCooperativeMatrixLengthKHR '5[%uint]' " + "must be OpTypeCooperativeMatrixKHR")); +} + +TEST_F(ValidateMemory, CoopMatMatrixKHRLengthGood) { + const std::string body = + R"( +OpCapability Shader +OpCapability Float16 +OpCapability CooperativeMatrixKHR +OpExtension "SPV_KHR_cooperative_matrix" +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%f16 = OpTypeFloat 16 +%u32 = OpTypeInt 32 0 +%i32 = OpTypeInt 32 1 + +%u32_8 = OpConstant %u32 8 +%use_A = OpConstant %u32 0 +%subgroup = OpConstant %u32 3 + +%f16mat = OpTypeCooperativeMatrixKHR %f16 %subgroup %u32_8 %u32_8 %use_A + +%main = OpFunction %void None %func +%main_entry = OpLabel + +%1 = OpCooperativeMatrixLengthKHR %u32 %f16mat + +OpReturn +OpFunctionEnd)"; + + CompileSuccessfully(body.c_str()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + TEST_F(ValidateMemory, VulkanRTAOutsideOfStructBad) { std::string spirv = R"( OpCapability Shader @@ -3765,9 +3947,8 @@ OpFunctionEnd HasSubstr("In the Vulkan environment, cannot store to Uniform Blocks")); } -using ValidateSizedVariable = - spvtest::ValidateBase>; +using ValidateSizedVariable = spvtest::ValidateBase< + std::tuple>; CodeGenerator GetSizedVariableCodeGenerator(bool is_8bit, bool buffer_block) { CodeGenerator generator; @@ -3777,7 +3958,8 @@ CodeGenerator GetSizedVariableCodeGenerator(bool is_8bit, bool buffer_block) { "\"SPV_KHR_8bit_storage\"\n"; generator.memory_model_ = "OpMemoryModel Logical GLSL450\n"; if (is_8bit) { - generator.before_types_ = "OpMemberDecorate %char_buffer_block 0 Offset 0\n"; + generator.before_types_ = + "OpMemberDecorate %char_buffer_block 0 Offset 0\n"; if (buffer_block) generator.before_types_ += "OpDecorate %char_buffer_block BufferBlock\n"; diff --git a/utils/generate_grammar_tables.py b/utils/generate_grammar_tables.py index 6b7167b86a..e6a145583f 100755 --- a/utils/generate_grammar_tables.py +++ b/utils/generate_grammar_tables.py @@ -540,7 +540,7 @@ def generate_operand_kind_table(enums): # We have a few operand kinds that require their optional counterpart to # exist in the operand info table. - optional_enums = ['ImageOperands', 'AccessQualifier', 'MemoryAccess', 'PackedVectorFormat'] + optional_enums = ['ImageOperands', 'AccessQualifier', 'MemoryAccess', 'PackedVectorFormat', 'CooperativeMatrixOperands'] optional_enums = [e for e in enums if e[0] in optional_enums] enums.extend(optional_enums) From cfb99efd7d82f9031c7645e18c8d5b1facd0a9f2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 23 Jun 2023 10:13:38 -0400 Subject: [PATCH 192/523] Roll external/googletest/ af39146b4..ec4fed932 (1 commit) (#5287) https://github.com/google/googletest/compare/af39146b4561...ec4fed93217b $ git log af39146b4..ec4fed932 --date=short --no-merges --format='%ad %ae %s' 2023-06-22 absl-team Update code examples in the gMock Cookbook following C++ best practices. 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 5727bad142..9591f4f74b 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': 'af39146b45619b7b0d98d1c85138bdb571975598', + 'googletest_revision': 'ec4fed93217bc2830959bb8e86798c1d86956949', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From c640b1934b176a78f1f95627277e78785efcabd0 Mon Sep 17 00:00:00 2001 From: Volodymyr B <50796908+3d4m-volodymyr@users.noreply.github.com> Date: Fri, 23 Jun 2023 15:31:10 +0100 Subject: [PATCH 193/523] Update CMakeLists.txt (#5288) add xrOS --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b854a43a6..7c00efbfd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,8 @@ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "iOS") add_definitions(-DSPIRV_IOS) elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "tvOS") add_definitions(-DSPIRV_TVOS) +elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "xrOS") + add_definitions(-DSPIRV_XROS) elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Android") add_definitions(-DSPIRV_ANDROID) set(SPIRV_TIMER_ENABLED ${SPIRV_ALLOW_TIMERS}) From 310a67020a7d67be4fdf1b4bfa9bb85f985c6fd7 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Fri, 23 Jun 2023 15:17:55 -0400 Subject: [PATCH 194/523] Validate layouts for PhysicalStorageBuffer pointers (#5291) * Validate layouts for PhysicalStorageBuffer pointers Fixes #5282 * These pointers may not orginate from a variable so standard layout validation misses them * Now checks every instructions that results in a physical storage buffer pointer * May not start from a Block-decorated struct so that part is fudged with a valid layout * formatting --- source/val/validate_decorations.cpp | 81 ++++++++++++----- test/opt/inst_buff_addr_check_test.cpp | 1 + test/val/val_decoration_test.cpp | 118 +++++++++++++++++++++++++ 3 files changed, 177 insertions(+), 23 deletions(-) diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp index c1fca45f99..605b79ebff 100644 --- a/source/val/validate_decorations.cpp +++ b/source/val/validate_decorations.cpp @@ -452,7 +452,16 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, return ds; }; - const auto& members = getStructMembers(struct_id, vstate); + // If we are checking physical storage buffer pointers, we may not actually + // have a struct here. Instead, pretend we have a struct with a single member + // at offset 0. + const auto& struct_type = vstate.FindDef(struct_id); + std::vector members; + if (struct_type->opcode() == spv::Op::OpTypeStruct) { + members = getStructMembers(struct_id, vstate); + } else { + members.push_back(struct_id); + } // To check for member overlaps, we want to traverse the members in // offset order. @@ -461,31 +470,38 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, uint32_t offset; }; std::vector member_offsets; - member_offsets.reserve(members.size()); - for (uint32_t memberIdx = 0, numMembers = uint32_t(members.size()); - memberIdx < numMembers; memberIdx++) { - uint32_t offset = 0xffffffff; - auto member_decorations = - vstate.id_member_decorations(struct_id, memberIdx); - for (auto decoration = member_decorations.begin; - decoration != member_decorations.end; ++decoration) { - assert(decoration->struct_member_index() == (int)memberIdx); - switch (decoration->dec_type()) { - case spv::Decoration::Offset: - offset = decoration->params()[0]; - break; - default: - break; + + // With physical storage buffers, we might be checking layouts that do not + // originate from a structure. + if (struct_type->opcode() == spv::Op::OpTypeStruct) { + member_offsets.reserve(members.size()); + for (uint32_t memberIdx = 0, numMembers = uint32_t(members.size()); + memberIdx < numMembers; memberIdx++) { + uint32_t offset = 0xffffffff; + auto member_decorations = + vstate.id_member_decorations(struct_id, memberIdx); + for (auto decoration = member_decorations.begin; + decoration != member_decorations.end; ++decoration) { + assert(decoration->struct_member_index() == (int)memberIdx); + switch (decoration->dec_type()) { + case spv::Decoration::Offset: + offset = decoration->params()[0]; + break; + default: + break; + } } + member_offsets.push_back( + MemberOffsetPair{memberIdx, incoming_offset + offset}); } - member_offsets.push_back( - MemberOffsetPair{memberIdx, incoming_offset + offset}); + std::stable_sort( + member_offsets.begin(), member_offsets.end(), + [](const MemberOffsetPair& lhs, const MemberOffsetPair& rhs) { + return lhs.offset < rhs.offset; + }); + } else { + member_offsets.push_back({0, 0}); } - std::stable_sort( - member_offsets.begin(), member_offsets.end(), - [](const MemberOffsetPair& lhs, const MemberOffsetPair& rhs) { - return lhs.offset < rhs.offset; - }); // Now scan from lowest offset to highest offset. uint32_t nextValidOffset = 0; @@ -1023,6 +1039,8 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { std::unordered_set uses_push_constant; for (const auto& inst : vstate.ordered_instructions()) { const auto& words = inst.words(); + auto type_id = inst.type_id(); + const Instruction* type_inst = vstate.FindDef(type_id); if (spv::Op::OpVariable == inst.opcode()) { const auto var_id = inst.id(); // For storage class / decoration combinations, see Vulkan 14.5.4 "Offset @@ -1276,6 +1294,23 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { } } } + } else if (type_inst && type_inst->opcode() == spv::Op::OpTypePointer && + type_inst->GetOperandAs(1u) == + spv::StorageClass::PhysicalStorageBuffer) { + const bool scalar_block_layout = vstate.options()->scalar_block_layout; + MemberConstraints constraints; + const bool buffer = true; + const auto data_type_id = type_inst->GetOperandAs(2u); + const auto* data_type_inst = vstate.FindDef(data_type_id); + if (data_type_inst->opcode() == spv::Op::OpTypeStruct) { + ComputeMemberConstraintsForStruct(&constraints, data_type_id, + LayoutConstraints(), vstate); + } + if (auto res = checkLayout(data_type_id, "PhysicalStorageBuffer", "Block", + !buffer, scalar_block_layout, 0, constraints, + vstate)) { + return res; + } } } return SPV_SUCCESS; diff --git a/test/opt/inst_buff_addr_check_test.cpp b/test/opt/inst_buff_addr_check_test.cpp index 9484b5a204..99f88f44c4 100644 --- a/test/opt/inst_buff_addr_check_test.cpp +++ b/test/opt/inst_buff_addr_check_test.cpp @@ -928,6 +928,7 @@ OpFunctionEnd SetTargetEnv(SPV_ENV_VULKAN_1_2); SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ValidatorOptions()->scalar_block_layout = true; SinglePassRunAndMatch(text, true, 7, 23); } diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp index be16abae90..7febb69749 100644 --- a/test/val/val_decoration_test.cpp +++ b/test/val/val_decoration_test.cpp @@ -9252,6 +9252,124 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); } +TEST_F(ValidateDecorations, PhysicalStorageBufferWithOffset) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Int64 +OpCapability PhysicalStorageBufferAddresses +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint GLCompute %main "main" %pc +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %pc_block Block +OpMemberDecorate %pc_block 0 Offset 0 +OpMemberDecorate %pssbo_struct 0 Offset 0 +%void = OpTypeVoid +%long = OpTypeInt 64 0 +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%pc_block = OpTypeStruct %long +%pc_block_ptr = OpTypePointer PushConstant %pc_block +%pc_long_ptr = OpTypePointer PushConstant %long +%pc = OpVariable %pc_block_ptr PushConstant +%pssbo_struct = OpTypeStruct %float +%pssbo_ptr = OpTypePointer PhysicalStorageBuffer %pssbo_struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%pc_gep = OpAccessChain %pc_long_ptr %pc %int_0 +%addr = OpLoad %long %pc_gep +%ptr = OpConvertUToPtr %pssbo_ptr %addr +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3)); +} + +TEST_F(ValidateDecorations, PhysicalStorageBufferMissingOffset) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Int64 +OpCapability PhysicalStorageBufferAddresses +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint GLCompute %main "main" %pc +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %pc_block Block +OpMemberDecorate %pc_block 0 Offset 0 +%void = OpTypeVoid +%long = OpTypeInt 64 0 +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%pc_block = OpTypeStruct %long +%pc_block_ptr = OpTypePointer PushConstant %pc_block +%pc_long_ptr = OpTypePointer PushConstant %long +%pc = OpVariable %pc_block_ptr PushConstant +%pssbo_struct = OpTypeStruct %float +%pssbo_ptr = OpTypePointer PhysicalStorageBuffer %pssbo_struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%pc_gep = OpAccessChain %pc_long_ptr %pc %int_0 +%addr = OpLoad %long %pc_gep +%ptr = OpConvertUToPtr %pssbo_ptr %addr +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("decorated as Block for variable in PhysicalStorageBuffer " + "storage class must follow relaxed storage buffer layout " + "rules: member 0 is missing an Offset decoration")); +} + +TEST_F(ValidateDecorations, PhysicalStorageBufferMissingArrayStride) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Int64 +OpCapability PhysicalStorageBufferAddresses +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint GLCompute %main "main" %pc +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %pc_block Block +OpMemberDecorate %pc_block 0 Offset 0 +%void = OpTypeVoid +%long = OpTypeInt 64 0 +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_4 = OpConstant %int 4 +%pc_block = OpTypeStruct %long +%pc_block_ptr = OpTypePointer PushConstant %pc_block +%pc_long_ptr = OpTypePointer PushConstant %long +%pc = OpVariable %pc_block_ptr PushConstant +%pssbo_array = OpTypeArray %float %int_4 +%pssbo_ptr = OpTypePointer PhysicalStorageBuffer %pssbo_array +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%pc_gep = OpAccessChain %pc_long_ptr %pc %int_0 +%addr = OpLoad %long %pc_gep +%ptr = OpConvertUToPtr %pssbo_ptr %addr +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "decorated as Block for variable in PhysicalStorageBuffer storage " + "class must follow relaxed storage buffer layout rules: member 0 " + "contains an array with stride 0, but with an element size of 4")); +} + } // namespace } // namespace val } // namespace spvtools From bfb40a240531d57e776e955d10d0bf03c6b0a82c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 26 Jun 2023 14:11:29 +0200 Subject: [PATCH 195/523] fix ndk build standard to c++17 (#5290) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nathan Gauër --- android_test/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android_test/Android.mk b/android_test/Android.mk index dbaf93ba98..b9a0014158 100644 --- a/android_test/Android.mk +++ b/android_test/Android.mk @@ -5,7 +5,7 @@ LOCAL_CPP_EXTENSION := .cc .cpp .cxx LOCAL_SRC_FILES:=test.cpp LOCAL_MODULE:=spirvtools_test LOCAL_LDLIBS:=-landroid -LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti -Werror +LOCAL_CXXFLAGS:=-std=c++17 -fno-exceptions -fno-rtti -Werror LOCAL_STATIC_LIBRARIES=SPIRV-Tools SPIRV-Tools-opt include $(BUILD_SHARED_LIBRARY) From e090ce9c40fb484b24a8f0e5735eb7629661c06c Mon Sep 17 00:00:00 2001 From: Volodymyr B <50796908+3d4m-volodymyr@users.noreply.github.com> Date: Mon, 26 Jun 2023 19:54:31 +0100 Subject: [PATCH 196/523] Update CMakeLists.txt (#5293) --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c00efbfd2..ea869f88cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,8 +53,8 @@ elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "iOS") add_definitions(-DSPIRV_IOS) elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "tvOS") add_definitions(-DSPIRV_TVOS) -elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "xrOS") - add_definitions(-DSPIRV_XROS) +elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "visionOS") + add_definitions(-DSPIRV_VISIONOS) elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Android") add_definitions(-DSPIRV_ANDROID) set(SPIRV_TIMER_ENABLED ${SPIRV_ALLOW_TIMERS}) From 7520bfa6b18495f85d0747deb6be5cb1236fdfa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Wed, 28 Jun 2023 14:37:55 +0200 Subject: [PATCH 197/523] build: remove last references of c++11 (#5295) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Figured I forgot some references. Naive sed this time, so we should be done. Signed-off-by: Nathan Gauër --- Android.mk | 4 ++-- source/wasm/build.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Android.mk b/Android.mk index a4e7615fad..d2a8de5954 100644 --- a/Android.mk +++ b/Android.mk @@ -340,7 +340,7 @@ LOCAL_C_INCLUDES := \ $(SPVTOOLS_OUT_PATH) LOCAL_EXPORT_C_INCLUDES := \ $(LOCAL_PATH)/include -LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti -Werror +LOCAL_CXXFLAGS:=-std=c++17 -fno-exceptions -fno-rtti -Werror LOCAL_SRC_FILES:= $(SPVTOOLS_SRC_FILES) include $(BUILD_STATIC_LIBRARY) @@ -351,7 +351,7 @@ LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/source \ $(SPVHEADERS_LOCAL_PATH)/include \ $(SPVTOOLS_OUT_PATH) -LOCAL_CXXFLAGS:=-std=c++11 -fno-exceptions -fno-rtti -Werror +LOCAL_CXXFLAGS:=-std=c++17 -fno-exceptions -fno-rtti -Werror LOCAL_STATIC_LIBRARIES:=SPIRV-Tools LOCAL_SRC_FILES:= $(SPVTOOLS_OPT_SRC_FILES) include $(BUILD_STATIC_LIBRARY) diff --git a/source/wasm/build.sh b/source/wasm/build.sh index 4f7b701c8a..69468c9ceb 100755 --- a/source/wasm/build.sh +++ b/source/wasm/build.sh @@ -45,7 +45,7 @@ build() { emcc \ --bind \ -I../../include \ - -std=c++11 \ + -std=c++17 \ ../../source/wasm/spirv-tools.cpp \ source/libSPIRV-Tools.a \ -o spirv-tools.js \ From f83f50d23ad576ffe3b89d4713601703950a7b7e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 28 Jun 2023 15:17:55 +0000 Subject: [PATCH 198/523] Roll external/googletest/ ec4fed932..8e32de89c (2 commits) (#5294) * Roll external/googletest/ ec4fed932..f269e15c5 (3 commits) https://github.com/google/googletest/compare/ec4fed93217b...f269e15c5caf $ git log ec4fed932..f269e15c5 --date=short --no-merges --format='%ad %ae %s' 2023-06-27 absl-team Resolve an issue where the resolution of `operator<<` overloads would attempt to instantiate the incomplete `testing::internal::Secret` type. 2023-06-22 chrisjohnsonmail add support for nxp qn9090 mcu 2023-06-23 eltociear Fix typo in googletest-catch-exceptions-test.py Created with: roll-dep external/googletest * Roll external/re2/ 7c5e396af..9ea3effad (1 commit) https://github.com/google/re2/compare/7c5e396af825...9ea3effadfe6 $ git log 7c5e396af..9ea3effad --date=short --no-merges --format='%ad %ae %s' 2023-06-27 junyer Move linker flags out of `$(MAKE_SHARED_LIBRARY)`. 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 9591f4f74b..41ad19f82c 100644 --- a/DEPS +++ b/DEPS @@ -7,12 +7,12 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': 'ec4fed93217bc2830959bb8e86798c1d86956949', + 'googletest_revision': 'f269e15c5cafa4ba7f4b543e0c395646bbbbd32d', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '7c5e396af825562ec8321fdbf2f1cf276b26e3ae', + 're2_revision': '9ea3effadfe6e73f7f40be40e3bbff2d82043a05', 'spirv_headers_revision': '3469b164e25cee24435029a569933cb42578db5d', } From ea5af2fb5fb2b0f6da9e5bd50e0b3d0616d5be2c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 29 Jun 2023 12:50:09 +0000 Subject: [PATCH 199/523] roll deps (#5297) * Roll external/googletest/ f269e15c5..687c58994 (2 commits) https://github.com/google/googletest/compare/f269e15c5caf...687c589949ea $ git log f269e15c5..687c58994 --date=short --no-merges --format='%ad %ae %s' 2023-06-28 absl-team Print stack traces on SEH exceptions on Windows 2023-06-27 dmauro On platforms without a file system, don't log an error when no alternative output format is requested. Created with: roll-dep external/googletest * Roll external/re2/ 9ea3effad..231c11764 (1 commit) https://github.com/google/re2/compare/9ea3effadfe6...231c1176482a $ git log 9ea3effad..231c11764 --date=short --no-merges --format='%ad %ae %s' 2023-06-28 junyer Print command lines for build commands. 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 41ad19f82c..77f3515a25 100644 --- a/DEPS +++ b/DEPS @@ -7,12 +7,12 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': 'f269e15c5cafa4ba7f4b543e0c395646bbbbd32d', + 'googletest_revision': '687c589949eaf8734484491a6882a7fc56aebc12', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '9ea3effadfe6e73f7f40be40e3bbff2d82043a05', + 're2_revision': '231c1176482a72331db6c488490b1d8d1cc5b820', 'spirv_headers_revision': '3469b164e25cee24435029a569933cb42578db5d', } From d3b0a522cec6cec4f241a6d1a7650096768cc43a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 30 Jun 2023 14:36:52 +0000 Subject: [PATCH 200/523] Roll external/googletest/ 687c58994..251e72039 (1 commit) (#5299) https://github.com/google/googletest/compare/687c589949ea...251e720391e9 $ git log 687c58994..251e72039 --date=short --no-merges --format='%ad %ae %s' 2023-06-29 absl-team Change `::testing` to `testing` in Testing Reference doc 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 77f3515a25..016dd6f0c0 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '687c589949eaf8734484491a6882a7fc56aebc12', + 'googletest_revision': '251e720391e92ab1aec845c7fd8ecdda35737f39', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From 58459c2b1adb43c9e8705823b78a12e95e8c430f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 30 Jun 2023 23:23:06 -0400 Subject: [PATCH 201/523] roll deps (#5300) * Roll external/googletest/ 251e72039..be03d00f5 (2 commits) https://github.com/google/googletest/compare/251e720391e9...be03d00f5f0c $ git log 251e72039..be03d00f5 --date=short --no-merges --format='%ad %ae %s' 2023-06-30 mkruskal Fix C++20 compatibility bug. 2023-06-30 absl-team Make GoogleTest handle SEH exceptions before stack unwinding rather than afterward Created with: roll-dep external/googletest * Roll external/re2/ 231c11764..2d39b703d (3 commits) https://github.com/google/re2/compare/231c1176482a...2d39b703d026 $ git log 231c11764..2d39b703d --date=short --no-merges --format='%ad %ae %s' 2023-06-30 junyer Clean up some StringPiece-related cruft. 2023-06-30 junyer Tidy up the Python build a little. 2023-06-30 junyer Simplify the app build a little. 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 016dd6f0c0..6ae283f5d5 100644 --- a/DEPS +++ b/DEPS @@ -7,12 +7,12 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '251e720391e92ab1aec845c7fd8ecdda35737f39', + 'googletest_revision': 'be03d00f5f0cc3a997d1a368bee8a1fe93651f48', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '231c1176482a72331db6c488490b1d8d1cc5b820', + 're2_revision': '2d39b703d02645076fead8fa409a1711f0e84381', 'spirv_headers_revision': '3469b164e25cee24435029a569933cb42578db5d', } From a1e8fff144af1edecf5c3ba7bab2a697dec00f0f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 4 Jul 2023 12:44:01 +0000 Subject: [PATCH 202/523] Roll external/re2/ 2d39b703d..1c1ffbe3c (1 commit) (#5304) https://github.com/google/re2/compare/2d39b703d026...1c1ffbe3c6b2 $ git log 2d39b703d..1c1ffbe3c --date=short --no-merges --format='%ad %ae %s' 2023-07-03 junyer Make the fuzzer exercise `ToString()`. 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 6ae283f5d5..969c760949 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': '2d39b703d02645076fead8fa409a1711f0e84381', + 're2_revision': '1c1ffbe3c6b2bd26f65b1c1b7bc71d16ba162cf1', 'spirv_headers_revision': '3469b164e25cee24435029a569933cb42578db5d', } From 870fd1e17aff8ede9aa12e647754780067306fe6 Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Tue, 4 Jul 2023 22:01:04 +0900 Subject: [PATCH 203/523] spirv-val: Label SPV_KHR_cooperative_matrix VUID (#5301) --- source/val/validate_memory.cpp | 5 +++-- source/val/validation_state.cpp | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index f039496b39..ea6d084233 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -1737,9 +1737,10 @@ spv_result_t ValidateCooperativeMatrixLoadStoreKHR(ValidationState_t& _, storage_class != spv::StorageClass::StorageBuffer && storage_class != spv::StorageClass::PhysicalStorageBuffer) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << opname << " storage class for pointer type " + << _.VkErrorID(8973) << opname + << " storage class for pointer type " << _.getIdName(pointer_type_id) - << " is not Workgroup or StorageBuffer."; + << " is not Workgroup, StorageBuffer, or PhysicalStorageBuffer."; } const auto pointee_id = pointer_type->GetOperandAs(2); diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index cde8aaadaf..14e205162a 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -2245,6 +2245,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-08721); case 8722: return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-08722); + case 8973: + return VUID_WRAP(VUID-StandaloneSpirv-Pointer-08973); default: return ""; // unknown id } From 0f3bea06ef2f1f232da22ef8339b92230f446742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Fri, 7 Jul 2023 16:41:52 +0200 Subject: [PATCH 204/523] NFC: rewrite EnumSet to handle larger enums. (#5289) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current EnumSet implementation is only efficient for enums with values < than 64. The reason is the first 63 values are stored as a bitmask in a 64 bit unsigned integer, and the other values are stored in a std::set. For small enums, this is fine (most SPIR-V enums have IDs < than 64), but performance starts to drop with larger enums (Capabilities, opcodes). Design considerations: ---------------------- This PR changes the internal behavior of the EnumSet to handle enums with arbitrary values while staying performant. The idea is to extend the 64-bits buckets sparsely: - each bucket can store 64 value, starting from a multiplier of 64. This could be considered as a hashset with linear probing. - For small enums, there is a slight memory overhead due to the bucket storage, but lookup is still constant. - For linearly distributed values, lookup is constant. - Worse case for storage are for enums with values which are multiples of 64. But lookup is constant. - Worse case for lookup are enums with a lot of small ranges scattered in the space (requires linear probing). For enums like capabilities/opcodes, this bucketing is useful as values are usually scatters in distinct, but almost contiguous blocks. (vendors usually have allocated ranges, like [5000;5500], while [1000;5000] is mostly unused). Benchmarking: ------------- Benchmarking was done in 2 ways: - a benchmark built for the occasion, which only measure the EnumSet performance. - SPIRV-Tools tests, to measure a more realist scenario. Running SPIR-V tests with both implementations shows the same performance (delta < noise). So seems like we have no regressions. This method is noisy by nature (I/O, etc), but the most representative of a real-life scenario. Protocol: - run spirv-tests with no stdout using perf, multiple times. Result: - measure noise is larger than the observed difference. The custom benchmark was testing EnumSet interfaces using SPIRV enums. Doing thousand of insertion/deletion/lookup, with 2 kind of scenarios: - add once, lookup many times. - add/delete/loopkup many time. For small enums, results are similar (delta < noise). Seems relevant with the previously observed results as most SPIRV enums are small, and SPIRV-Tools is not doing that many intensive operations on EnumSets. Performance on large enums (opcode/capabilities) shows an improvement: +-----------------------------+---------+---------+---------+ | Metric | Old | New | Delta % | +-----------------------------+---------+---------+---------+ | Execution time | 27s | 7s | -72% | | Instruction count | 174b | 129b | -25% | | Branch count | 28b | 33b | +17% | | Branch miss | 490m | 26m | -94% | | Cache-misses | 149k | 26k | -82% | +-----------------------------+---------+---------+---------+ Future work ----------- This was by-design an NFC change to compare apples-to-apples. The next PR aims to add STL-like iterators to the EnumSet to allow using it with STL algorithms, and range-based for loops. Signed-off-by: Nathan Gauër --- source/enum_set.h | 368 +++++++++++++++--------- source/extensions.h | 3 +- source/val/validation_state.cpp | 1 + test/enum_set_test.cpp | 490 +++++++++++++++++++++++++++----- 4 files changed, 656 insertions(+), 206 deletions(-) diff --git a/source/enum_set.h b/source/enum_set.h index 28ee5fee8d..9b0bb5b4e3 100644 --- a/source/enum_set.h +++ b/source/enum_set.h @@ -1,4 +1,4 @@ -// Copyright (c) 2016 Google Inc. +// 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. @@ -12,195 +12,289 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef SOURCE_ENUM_SET_H_ -#define SOURCE_ENUM_SET_H_ - +#include #include #include -#include -#include -#include +#include +#include +#include +#include + +#ifndef SOURCE_ENUM_SET_H_ +#define SOURCE_ENUM_SET_H_ #include "source/latest_version_spirv_header.h" -#include "source/util/make_unique.h" namespace spvtools { -// A set of values of a 32-bit enum type. -// It is fast and compact for the common case, where enum values -// are at most 63. But it can represent enums with larger values, -// as may appear in extensions. -template +// This container is optimized to store and retrieve unsigned enum values. +// The base model for this implementation is an open-addressing hashtable with +// linear probing. For small enums (max index < 64), all operations are O(1). +// +// - Enums are stored in buckets (64 contiguous values max per bucket) +// - Buckets ranges don't overlap, but don't have to be contiguous. +// - Enums are packed into 64-bits buckets, using 1 bit per enum value. +// +// Example: +// - MyEnum { A = 0, B = 1, C = 64, D = 65 } +// - 2 buckets are required: +// - bucket 0, storing values in the range [ 0; 64[ +// - bucket 1, storing values in the range [64; 128[ +// +// - Buckets are stored in a sorted vector (sorted by bucket range). +// - Retrieval is done by computing the theoretical bucket index using the enum +// value, and +// doing a linear scan from this position. +// - Insertion is done by retrieving the bucket and either: +// - inserting a new bucket in the sorted vector when no buckets has a +// compatible range. +// - setting the corresponding bit in the bucket. +// This means insertion in the middle/beginning can cause a memmove when no +// bucket is available. In our case, this happens at most 23 times for the +// largest enum we have (Opcodes). +template class EnumSet { private: - // The ForEach method will call the functor on enum values in - // enum value order (lowest to highest). To make that easier, use - // an ordered set for the overflow values. - using OverflowSetType = std::set; + using BucketType = uint64_t; + using ElementType = std::underlying_type_t; + static_assert(std::is_enum_v, "EnumSets only works with enums."); + static_assert(std::is_signed_v == false, + "EnumSet doesn't supports signed enums."); + + // Each bucket can hold up to `kBucketSize` distinct, contiguous enum values. + // The first value a bucket can hold must be aligned on `kBucketSize`. + struct Bucket { + // bit mask to store `kBucketSize` enums. + BucketType data; + // 1st enum this bucket can represent. + T start; + + friend bool operator==(const Bucket& lhs, const Bucket& rhs) { + return lhs.start == rhs.start && lhs.data == rhs.data; + } + }; + + // How many distinct values can a bucket hold? 1 bit per value. + static constexpr size_t kBucketSize = sizeof(BucketType) * 8ULL; public: - // Construct an empty set. - EnumSet() {} - // Construct an set with just the given enum value. - explicit EnumSet(EnumType c) { Add(c); } - // Construct an set from an initializer list of enum values. - EnumSet(std::initializer_list cs) { - for (auto c : cs) Add(c); - } - EnumSet(uint32_t count, const EnumType* ptr) { - for (uint32_t i = 0; i < count; ++i) Add(ptr[i]); - } - // Copy constructor. - EnumSet(const EnumSet& other) { *this = other; } - // Move constructor. The moved-from set is emptied. - EnumSet(EnumSet&& other) { - mask_ = other.mask_; - overflow_ = std::move(other.overflow_); - other.mask_ = 0; - other.overflow_.reset(nullptr); - } - // Assignment operator. - EnumSet& operator=(const EnumSet& other) { - if (&other != this) { - mask_ = other.mask_; - overflow_.reset(other.overflow_ ? new OverflowSetType(*other.overflow_) - : nullptr); + // Creates an empty set. + EnumSet() : buckets_(0) {} + + // Creates a set and store `value` in it. + EnumSet(T value) : EnumSet() { Add(value); } + + // Creates a set and stores each `values` in it. + EnumSet(std::initializer_list values) : EnumSet() { + for (auto item : values) { + Add(item); } + } + + // Creates a set, and insert `count` enum values pointed by `array` in it. + EnumSet(ElementType count, const T* array) : EnumSet() { + for (ElementType i = 0; i < count; i++) { + Add(array[i]); + } + } + + // Copies the EnumSet `other` into a new EnumSet. + EnumSet(const EnumSet& other) : buckets_(other.buckets_) {} + + // Moves the EnumSet `other` into a new EnumSet. + EnumSet(EnumSet&& other) : buckets_(std::move(other.buckets_)) {} + + // Deep-copies the EnumSet `other` into this EnumSet. + EnumSet& operator=(const EnumSet& other) { + buckets_ = other.buckets_; return *this; } - friend bool operator==(const EnumSet& a, const EnumSet& b) { - if (a.mask_ != b.mask_) { - return false; + // Add the enum value `value` into the set. + // The set is unchanged if the value already exists. + void Add(T value) { + const size_t index = FindBucketForValue(value); + if (index >= buckets_.size() || + buckets_[index].start != ComputeBucketStart(value)) { + InsertBucketFor(index, value); + return; } + auto& bucket = buckets_[index]; + bucket.data |= ComputeMaskForValue(value); + } - if (a.overflow_ == nullptr && b.overflow_ == nullptr) { - return true; + // Removes the value `value` into the set. + // The set is unchanged if the value is not in the set. + void Remove(T value) { + const size_t index = FindBucketForValue(value); + if (index >= buckets_.size() || + buckets_[index].start != ComputeBucketStart(value)) { + return; } + auto& bucket = buckets_[index]; + bucket.data &= ~ComputeMaskForValue(value); + if (bucket.data == 0) { + buckets_.erase(buckets_.cbegin() + index); + } + } - if (a.overflow_ == nullptr || b.overflow_ == nullptr) { + // Returns true if `value` is present in the set. + bool Contains(T value) const { + const size_t index = FindBucketForValue(value); + if (index >= buckets_.size() || + buckets_[index].start != ComputeBucketStart(value)) { return false; } - - return *a.overflow_ == *b.overflow_; + auto& bucket = buckets_[index]; + return bucket.data & ComputeMaskForValue(value); } - friend bool operator!=(const EnumSet& a, const EnumSet& b) { - return !(a == b); + // Calls `unaryFunction` once for each value in the set. + // Values are sorted in increasing order using their numerical values. + void ForEach(std::function unaryFunction) const { + for (const auto& bucket : buckets_) { + for (uint8_t i = 0; i < kBucketSize; i++) { + if (bucket.data & (1ULL << i)) { + unaryFunction(GetValueFromBucket(bucket, i)); + } + } + } } - // Adds the given enum value to the set. This has no effect if the - // enum value is already in the set. - void Add(EnumType c) { AddWord(ToWord(c)); } + // Returns true if the set is holds no values. + bool IsEmpty() const { return buckets_.size() == 0; } - // Removes the given enum value from the set. This has no effect if the - // enum value is not in the set. - void Remove(EnumType c) { RemoveWord(ToWord(c)); } - - // Returns true if this enum value is in the set. - bool Contains(EnumType c) const { return ContainsWord(ToWord(c)); } - - // Applies f to each enum in the set, in order from smallest enum - // value to largest. - void ForEach(std::function f) const { - for (uint32_t i = 0; i < 64; ++i) { - if (mask_ & AsMask(i)) f(static_cast(i)); - } - if (overflow_) { - for (uint32_t c : *overflow_) f(static_cast(c)); + // Returns true if this set contains at least one value contained in `in_set`. + // Note: If `in_set` is empty, this function returns true. + bool HasAnyOf(const EnumSet& in_set) const { + if (in_set.IsEmpty()) { + return true; } - } - // Returns true if the set is empty. - bool IsEmpty() const { - if (mask_) return false; - if (overflow_ && !overflow_->empty()) return false; - return true; - } + auto lhs = buckets_.cbegin(); + auto rhs = in_set.buckets_.cbegin(); - // Returns true if the set contains ANY of the elements of |in_set|, - // or if |in_set| is empty. - bool HasAnyOf(const EnumSet& in_set) const { - if (in_set.IsEmpty()) return true; + while (lhs != buckets_.cend() && rhs != in_set.buckets_.cend()) { + if (lhs->start == rhs->start) { + if (lhs->data & rhs->data) { + // At least 1 bit is shared. Early return. + return true; + } - if (mask_ & in_set.mask_) return true; + lhs++; + rhs++; + continue; + } - if (!overflow_ || !in_set.overflow_) return false; + // LHS bucket is smaller than the current RHS bucket. Catching up on RHS. + if (lhs->start < rhs->start) { + lhs++; + continue; + } - for (uint32_t item : *in_set.overflow_) { - if (overflow_->find(item) != overflow_->end()) return true; + // Otherwise, RHS needs to catch up on LHS. + rhs++; } return false; } private: - // Adds the given enum value (as a 32-bit word) to the set. This has no - // effect if the enum value is already in the set. - void AddWord(uint32_t word) { - if (auto new_bits = AsMask(word)) { - mask_ |= new_bits; - } else { - Overflow().insert(word); - } + // Returns the index of the last bucket in which `value` could be stored. + static constexpr inline size_t ComputeLargestPossibleBucketIndexFor(T value) { + return static_cast(value) / kBucketSize; } - // Removes the given enum value (as a 32-bit word) from the set. This has no - // effect if the enum value is not in the set. - void RemoveWord(uint32_t word) { - if (auto new_bits = AsMask(word)) { - mask_ &= ~new_bits; - } else { - auto itr = Overflow().find(word); - if (itr != Overflow().end()) Overflow().erase(itr); - } + // Returns the smallest enum value that could be contained in the same bucket + // as `value`. + static constexpr inline T ComputeBucketStart(T value) { + return static_cast(kBucketSize * + ComputeLargestPossibleBucketIndexFor(value)); } - // Returns true if the enum represented as a 32-bit word is in the set. - bool ContainsWord(uint32_t word) const { - // We shouldn't call Overflow() since this is a const method. - if (auto bits = AsMask(word)) { - return (mask_ & bits) != 0; - } else if (auto overflow = overflow_.get()) { - return overflow->find(word) != overflow->end(); - } - // The word is large, but the set doesn't have large members, so - // it doesn't have an overflow set. - return false; + // Returns the index of the bit that corresponds to `value` in the bucket. + static constexpr inline size_t ComputeBucketOffset(T value) { + return static_cast(value) % kBucketSize; } - // Returns the enum value as a uint32_t. - uint32_t ToWord(EnumType value) const { - static_assert(sizeof(EnumType) <= sizeof(uint32_t), - "EnumType must statically castable to uint32_t"); - return static_cast(value); + // Returns the bitmask used to represent the enum `value` in its bucket. + static constexpr inline BucketType ComputeMaskForValue(T value) { + return 1ULL << ComputeBucketOffset(value); } - // Determines whether the given enum value can be represented - // as a bit in a uint64_t mask. If so, then returns that mask bit. - // Otherwise, returns 0. - uint64_t AsMask(uint32_t word) const { - if (word > 63) return 0; - return uint64_t(1) << word; + // Returns the `enum` stored in `bucket` at `offset`. + // `offset` is the bit-offset in the bucket storage. + static constexpr inline T GetValueFromBucket(const Bucket& bucket, + ElementType offset) { + return static_cast(static_cast(bucket.start) + offset); } - // Ensures that overflow_set_ references a set. A new empty set is - // allocated if one doesn't exist yet. Returns overflow_set_. - OverflowSetType& Overflow() { - if (overflow_.get() == nullptr) { - overflow_ = MakeUnique(); + // For a given enum `value`, finds the bucket index that could contain this + // value. If no such bucket is found, the index at which the new bucket should + // be inserted is returned. + size_t FindBucketForValue(T value) const { + // Set is empty, insert at 0. + if (buckets_.size() == 0) { + return 0; + } + + const T wanted_start = ComputeBucketStart(value); + assert(buckets_.size() > 0 && + "Size must not be 0 here. Has the code above changed?"); + size_t index = std::min(buckets_.size() - 1, + ComputeLargestPossibleBucketIndexFor(value)); + + // This loops behaves like std::upper_bound with a reverse iterator. + // Buckets are sorted. 3 main cases: + // - The bucket matches + // => returns the bucket index. + // - The found bucket is larger + // => scans left until it finds the correct bucket, or insertion point. + // - The found bucket is smaller + // => We are at the end, so we return past-end index for insertion. + for (; buckets_[index].start >= wanted_start; index--) { + if (index == 0) { + return 0; + } } - return *overflow_; + + return index + 1; + } + + // Creates a new bucket to store `value` and inserts it at `index`. + // If the `index` is past the end, the bucket is inserted at the end of the + // vector. + void InsertBucketFor(size_t index, T value) { + const T bucket_start = ComputeBucketStart(value); + Bucket bucket = {1ULL << ComputeBucketOffset(value), bucket_start}; + auto it = buckets_.emplace(buckets_.begin() + index, std::move(bucket)); +#if defined(NDEBUG) + (void)it; // Silencing unused variable warning. +#else + assert(std::next(it) == buckets_.end() || + std::next(it)->start > bucket_start); + assert(it == buckets_.begin() || std::prev(it)->start < bucket_start); +#endif + } + + // Returns true if `lhs` and `rhs` hold the exact same values. + friend bool operator==(const EnumSet& lhs, const EnumSet& rhs) { + if (lhs.buckets_.size() != rhs.buckets_.size()) { + return false; + } + return lhs.buckets_ == rhs.buckets_; + } + + // Returns true if `lhs` and `rhs` hold at least 1 different value. + friend bool operator!=(const EnumSet& lhs, const EnumSet& rhs) { + return !(lhs == rhs); } - // Enums with values up to 63 are stored as bits in this mask. - uint64_t mask_ = 0; - // Enums with values larger than 63 are stored in this set. - // This set should normally be empty or very small. - std::unique_ptr overflow_ = {}; + // Storage for the buckets. + std::vector buckets_; }; -// A set of spv::Capability, optimized for small capability values. +// A set of spv::Capability. using CapabilitySet = EnumSet; } // namespace spvtools diff --git a/source/extensions.h b/source/extensions.h index 8023444c31..cda4924a47 100644 --- a/source/extensions.h +++ b/source/extensions.h @@ -15,6 +15,7 @@ #ifndef SOURCE_EXTENSIONS_H_ #define SOURCE_EXTENSIONS_H_ +#include #include #include "source/enum_set.h" @@ -23,7 +24,7 @@ namespace spvtools { // The known SPIR-V extensions. -enum Extension { +enum Extension : uint32_t { #include "extension_enum.inc" }; diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 14e205162a..d1572591ec 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -21,6 +21,7 @@ #include "source/opcode.h" #include "source/spirv_constant.h" #include "source/spirv_target_env.h" +#include "source/util/make_unique.h" #include "source/val/basic_block.h" #include "source/val/construct.h" #include "source/val/function.h" diff --git a/test/enum_set_test.cpp b/test/enum_set_test.cpp index 1f727158ee..bf9e4432b0 100644 --- a/test/enum_set_test.cpp +++ b/test/enum_set_test.cpp @@ -12,12 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "source/enum_set.h" + #include +#include +#include #include #include #include "gmock/gmock.h" -#include "source/enum_set.h" #include "test/unit_spirv.h" namespace spvtools { @@ -25,157 +28,437 @@ namespace { using spvtest::ElementsIn; using ::testing::Eq; +using ::testing::Values; using ::testing::ValuesIn; +enum class TestEnum : uint32_t { + ZERO = 0, + ONE = 1, + TWO = 2, + THREE = 3, + FOUR = 4, + FIVE = 5, + EIGHT = 8, + TWENTY = 20, + TWENTY_FOUR = 24, + THIRTY = 30, + ONE_HUNDRED = 100, + ONE_HUNDRED_FIFTY = 150, + TWO_HUNDRED = 200, + THREE_HUNDRED = 300, + FOUR_HUNDRED = 400, + FIVE_HUNDRED = 500, + SIX_HUNDRED = 600, +}; + +constexpr std::array kCapabilities{ + spv::Capability::Matrix, + spv::Capability::Shader, + spv::Capability::Geometry, + spv::Capability::Tessellation, + spv::Capability::Addresses, + spv::Capability::Linkage, + spv::Capability::Kernel, + spv::Capability::Vector16, + spv::Capability::Float16Buffer, + spv::Capability::Float16, + spv::Capability::Float64, + spv::Capability::Int64, + spv::Capability::Int64Atomics, + spv::Capability::ImageBasic, + spv::Capability::ImageReadWrite, + spv::Capability::ImageMipmap, + spv::Capability::Pipes, + spv::Capability::Groups, + spv::Capability::DeviceEnqueue, + spv::Capability::LiteralSampler, + spv::Capability::AtomicStorage, + spv::Capability::Int16, + spv::Capability::TessellationPointSize, + spv::Capability::GeometryPointSize, + spv::Capability::ImageGatherExtended, + spv::Capability::StorageImageMultisample, + spv::Capability::UniformBufferArrayDynamicIndexing, + spv::Capability::SampledImageArrayDynamicIndexing, + spv::Capability::StorageBufferArrayDynamicIndexing, + spv::Capability::StorageImageArrayDynamicIndexing, + spv::Capability::ClipDistance, + spv::Capability::CullDistance, + spv::Capability::ImageCubeArray, + spv::Capability::SampleRateShading, + spv::Capability::ImageRect, + spv::Capability::SampledRect, + spv::Capability::GenericPointer, + spv::Capability::Int8, + spv::Capability::InputAttachment, + spv::Capability::SparseResidency, + spv::Capability::MinLod, + spv::Capability::Sampled1D, + spv::Capability::Image1D, + spv::Capability::SampledCubeArray, + spv::Capability::SampledBuffer, + spv::Capability::ImageBuffer, + spv::Capability::ImageMSArray, + spv::Capability::StorageImageExtendedFormats, + spv::Capability::ImageQuery, + spv::Capability::DerivativeControl, + spv::Capability::InterpolationFunction, + spv::Capability::TransformFeedback, + spv::Capability::GeometryStreams, + spv::Capability::StorageImageReadWithoutFormat, + spv::Capability::StorageImageWriteWithoutFormat, + spv::Capability::MultiViewport, + spv::Capability::SubgroupDispatch, + spv::Capability::NamedBarrier, + spv::Capability::PipeStorage, + spv::Capability::GroupNonUniform, + spv::Capability::GroupNonUniformVote, + spv::Capability::GroupNonUniformArithmetic, + spv::Capability::GroupNonUniformBallot, + spv::Capability::GroupNonUniformShuffle, + spv::Capability::GroupNonUniformShuffleRelative, + spv::Capability::GroupNonUniformClustered, + spv::Capability::GroupNonUniformQuad, + spv::Capability::ShaderLayer, + spv::Capability::ShaderViewportIndex, + spv::Capability::UniformDecoration, + spv::Capability::CoreBuiltinsARM, + spv::Capability::FragmentShadingRateKHR, + spv::Capability::SubgroupBallotKHR, + spv::Capability::DrawParameters, + spv::Capability::WorkgroupMemoryExplicitLayoutKHR, + spv::Capability::WorkgroupMemoryExplicitLayout8BitAccessKHR, + spv::Capability::WorkgroupMemoryExplicitLayout16BitAccessKHR, + spv::Capability::SubgroupVoteKHR, + spv::Capability::StorageBuffer16BitAccess, + spv::Capability::StorageUniformBufferBlock16, + spv::Capability::StorageUniform16, + spv::Capability::UniformAndStorageBuffer16BitAccess, + spv::Capability::StoragePushConstant16, + spv::Capability::StorageInputOutput16, + spv::Capability::DeviceGroup, + spv::Capability::MultiView, + spv::Capability::VariablePointersStorageBuffer, + spv::Capability::VariablePointers, + spv::Capability::AtomicStorageOps, + spv::Capability::SampleMaskPostDepthCoverage, + spv::Capability::StorageBuffer8BitAccess, + spv::Capability::UniformAndStorageBuffer8BitAccess, + spv::Capability::StoragePushConstant8, + spv::Capability::DenormPreserve, + spv::Capability::DenormFlushToZero, + spv::Capability::SignedZeroInfNanPreserve, + spv::Capability::RoundingModeRTE, + spv::Capability::RoundingModeRTZ, + spv::Capability::RayQueryProvisionalKHR, + spv::Capability::RayQueryKHR, + spv::Capability::RayTraversalPrimitiveCullingKHR, + spv::Capability::RayTracingKHR, + spv::Capability::Float16ImageAMD, + spv::Capability::ImageGatherBiasLodAMD, + spv::Capability::FragmentMaskAMD, + spv::Capability::StencilExportEXT, + spv::Capability::ImageReadWriteLodAMD, + spv::Capability::Int64ImageEXT, + spv::Capability::ShaderClockKHR, + spv::Capability::SampleMaskOverrideCoverageNV, + spv::Capability::GeometryShaderPassthroughNV, + spv::Capability::ShaderViewportIndexLayerEXT, + spv::Capability::ShaderViewportIndexLayerNV, + spv::Capability::ShaderViewportMaskNV, + spv::Capability::ShaderStereoViewNV, + spv::Capability::PerViewAttributesNV, + spv::Capability::FragmentFullyCoveredEXT, + spv::Capability::MeshShadingNV, + spv::Capability::ImageFootprintNV, + spv::Capability::MeshShadingEXT, + spv::Capability::FragmentBarycentricKHR, + spv::Capability::FragmentBarycentricNV, + spv::Capability::ComputeDerivativeGroupQuadsNV, + spv::Capability::FragmentDensityEXT, + spv::Capability::ShadingRateNV, + spv::Capability::GroupNonUniformPartitionedNV, + spv::Capability::ShaderNonUniform, + spv::Capability::ShaderNonUniformEXT, + spv::Capability::RuntimeDescriptorArray, + spv::Capability::RuntimeDescriptorArrayEXT, + spv::Capability::InputAttachmentArrayDynamicIndexing, + spv::Capability::InputAttachmentArrayDynamicIndexingEXT, + spv::Capability::UniformTexelBufferArrayDynamicIndexing, + spv::Capability::UniformTexelBufferArrayDynamicIndexingEXT, + spv::Capability::StorageTexelBufferArrayDynamicIndexing, + spv::Capability::StorageTexelBufferArrayDynamicIndexingEXT, + spv::Capability::UniformBufferArrayNonUniformIndexing, + spv::Capability::UniformBufferArrayNonUniformIndexingEXT, + spv::Capability::SampledImageArrayNonUniformIndexing, + spv::Capability::SampledImageArrayNonUniformIndexingEXT, + spv::Capability::StorageBufferArrayNonUniformIndexing, + spv::Capability::StorageBufferArrayNonUniformIndexingEXT, + spv::Capability::StorageImageArrayNonUniformIndexing, + spv::Capability::StorageImageArrayNonUniformIndexingEXT, + spv::Capability::InputAttachmentArrayNonUniformIndexing, + spv::Capability::InputAttachmentArrayNonUniformIndexingEXT, + spv::Capability::UniformTexelBufferArrayNonUniformIndexing, + spv::Capability::UniformTexelBufferArrayNonUniformIndexingEXT, + spv::Capability::StorageTexelBufferArrayNonUniformIndexing, + spv::Capability::StorageTexelBufferArrayNonUniformIndexingEXT, + spv::Capability::RayTracingNV, + spv::Capability::RayTracingMotionBlurNV, + spv::Capability::VulkanMemoryModel, + spv::Capability::VulkanMemoryModelKHR, + spv::Capability::VulkanMemoryModelDeviceScope, + spv::Capability::VulkanMemoryModelDeviceScopeKHR, + spv::Capability::PhysicalStorageBufferAddresses, + spv::Capability::PhysicalStorageBufferAddressesEXT, + spv::Capability::ComputeDerivativeGroupLinearNV, + spv::Capability::RayTracingProvisionalKHR, + spv::Capability::CooperativeMatrixNV, + spv::Capability::FragmentShaderSampleInterlockEXT, + spv::Capability::FragmentShaderShadingRateInterlockEXT, + spv::Capability::ShaderSMBuiltinsNV, + spv::Capability::FragmentShaderPixelInterlockEXT, + spv::Capability::DemoteToHelperInvocation, + spv::Capability::DemoteToHelperInvocationEXT, + spv::Capability::RayTracingOpacityMicromapEXT, + spv::Capability::ShaderInvocationReorderNV, + spv::Capability::BindlessTextureNV, + spv::Capability::SubgroupShuffleINTEL, + spv::Capability::SubgroupBufferBlockIOINTEL, + spv::Capability::SubgroupImageBlockIOINTEL, + spv::Capability::SubgroupImageMediaBlockIOINTEL, + spv::Capability::RoundToInfinityINTEL, + spv::Capability::FloatingPointModeINTEL, + spv::Capability::IntegerFunctions2INTEL, + spv::Capability::FunctionPointersINTEL, + spv::Capability::IndirectReferencesINTEL, + spv::Capability::AsmINTEL, + spv::Capability::AtomicFloat32MinMaxEXT, + spv::Capability::AtomicFloat64MinMaxEXT, + spv::Capability::AtomicFloat16MinMaxEXT, + spv::Capability::VectorComputeINTEL, + spv::Capability::VectorAnyINTEL, + spv::Capability::ExpectAssumeKHR, + spv::Capability::SubgroupAvcMotionEstimationINTEL, + spv::Capability::SubgroupAvcMotionEstimationIntraINTEL, + spv::Capability::SubgroupAvcMotionEstimationChromaINTEL, + spv::Capability::VariableLengthArrayINTEL, + spv::Capability::FunctionFloatControlINTEL, + spv::Capability::FPGAMemoryAttributesINTEL, + spv::Capability::FPFastMathModeINTEL, + spv::Capability::ArbitraryPrecisionIntegersINTEL, + spv::Capability::ArbitraryPrecisionFloatingPointINTEL, + spv::Capability::UnstructuredLoopControlsINTEL, + spv::Capability::FPGALoopControlsINTEL, + spv::Capability::KernelAttributesINTEL, + spv::Capability::FPGAKernelAttributesINTEL, + spv::Capability::FPGAMemoryAccessesINTEL, + spv::Capability::FPGAClusterAttributesINTEL, + spv::Capability::LoopFuseINTEL, + spv::Capability::FPGADSPControlINTEL, + spv::Capability::MemoryAccessAliasingINTEL, + spv::Capability::FPGAInvocationPipeliningAttributesINTEL, + spv::Capability::FPGABufferLocationINTEL, + spv::Capability::ArbitraryPrecisionFixedPointINTEL, + spv::Capability::USMStorageClassesINTEL, + spv::Capability::RuntimeAlignedAttributeINTEL, + spv::Capability::IOPipesINTEL, + spv::Capability::BlockingPipesINTEL, + spv::Capability::FPGARegINTEL, + spv::Capability::DotProductInputAll, + spv::Capability::DotProductInputAllKHR, + spv::Capability::DotProductInput4x8Bit, + spv::Capability::DotProductInput4x8BitKHR, + spv::Capability::DotProductInput4x8BitPacked, + spv::Capability::DotProductInput4x8BitPackedKHR, + spv::Capability::DotProduct, + spv::Capability::DotProductKHR, + spv::Capability::RayCullMaskKHR, + spv::Capability::BitInstructions, + spv::Capability::GroupNonUniformRotateKHR, + spv::Capability::AtomicFloat32AddEXT, + spv::Capability::AtomicFloat64AddEXT, + spv::Capability::LongConstantCompositeINTEL, + spv::Capability::OptNoneINTEL, + spv::Capability::AtomicFloat16AddEXT, + spv::Capability::DebugInfoModuleINTEL, + spv::Capability::SplitBarrierINTEL, + spv::Capability::GroupUniformArithmeticKHR, + spv::Capability::Max, +}; + TEST(EnumSet, IsEmpty1) { - EnumSet set; + EnumSet set; EXPECT_TRUE(set.IsEmpty()); - set.Add(0); + set.Add(TestEnum::ZERO); EXPECT_FALSE(set.IsEmpty()); } TEST(EnumSet, IsEmpty2) { - EnumSet set; + EnumSet set; EXPECT_TRUE(set.IsEmpty()); - set.Add(150); + set.Add(TestEnum::ONE_HUNDRED_FIFTY); EXPECT_FALSE(set.IsEmpty()); } TEST(EnumSet, IsEmpty3) { - EnumSet set(4); + EnumSet set(TestEnum::FOUR); EXPECT_FALSE(set.IsEmpty()); } TEST(EnumSet, IsEmpty4) { - EnumSet set(300); + EnumSet set(TestEnum::THREE_HUNDRED); EXPECT_FALSE(set.IsEmpty()); } TEST(EnumSetHasAnyOf, EmptySetEmptyQuery) { - const EnumSet set; - const EnumSet empty; + const EnumSet set; + const EnumSet empty; EXPECT_TRUE(set.HasAnyOf(empty)); - EXPECT_TRUE(EnumSet().HasAnyOf(EnumSet())); + EXPECT_TRUE(EnumSet().HasAnyOf(EnumSet())); } TEST(EnumSetHasAnyOf, MaskSetEmptyQuery) { - EnumSet set; - const EnumSet empty; - set.Add(5); - set.Add(8); + EnumSet set; + const EnumSet empty; + set.Add(TestEnum::FIVE); + set.Add(TestEnum::EIGHT); EXPECT_TRUE(set.HasAnyOf(empty)); } TEST(EnumSetHasAnyOf, OverflowSetEmptyQuery) { - EnumSet set; - const EnumSet empty; - set.Add(200); - set.Add(300); + EnumSet set; + const EnumSet empty; + set.Add(TestEnum::TWO_HUNDRED); + set.Add(TestEnum::THREE_HUNDRED); EXPECT_TRUE(set.HasAnyOf(empty)); } TEST(EnumSetHasAnyOf, EmptyQuery) { - EnumSet set; - const EnumSet empty; - set.Add(5); - set.Add(8); - set.Add(200); - set.Add(300); + EnumSet set; + const EnumSet empty; + set.Add(TestEnum::FIVE); + set.Add(TestEnum::EIGHT); + set.Add(TestEnum::TWO_HUNDRED); + set.Add(TestEnum::THREE_HUNDRED); EXPECT_TRUE(set.HasAnyOf(empty)); } TEST(EnumSetHasAnyOf, EmptyQueryAlwaysTrue) { - EnumSet set; - const EnumSet empty; + EnumSet set; + const EnumSet empty; EXPECT_TRUE(set.HasAnyOf(empty)); - set.Add(5); + set.Add(TestEnum::FIVE); EXPECT_TRUE(set.HasAnyOf(empty)); - EXPECT_TRUE(EnumSet(100).HasAnyOf(EnumSet())); + EXPECT_TRUE( + EnumSet(TestEnum::ONE_HUNDRED).HasAnyOf(EnumSet())); } TEST(EnumSetHasAnyOf, ReflexiveMask) { - EnumSet set(3); - set.Add(24); - set.Add(30); + EnumSet set(TestEnum::THREE); + set.Add(TestEnum::TWENTY_FOUR); + set.Add(TestEnum::THIRTY); EXPECT_TRUE(set.HasAnyOf(set)); } TEST(EnumSetHasAnyOf, ReflexiveOverflow) { - EnumSet set(200); - set.Add(300); - set.Add(400); + EnumSet set(TestEnum::TWO_HUNDRED); + set.Add(TestEnum::TWO_HUNDRED); + set.Add(TestEnum::FOUR_HUNDRED); EXPECT_TRUE(set.HasAnyOf(set)); } TEST(EnumSetHasAnyOf, Reflexive) { - EnumSet set(3); - set.Add(24); - set.Add(300); - set.Add(400); + EnumSet set(TestEnum::THREE); + set.Add(TestEnum::TWENTY_FOUR); + set.Add(TestEnum::THREE_HUNDRED); + set.Add(TestEnum::FOUR_HUNDRED); EXPECT_TRUE(set.HasAnyOf(set)); } TEST(EnumSetHasAnyOf, EmptySetHasNone) { - EnumSet set; - EnumSet items; + EnumSet set; + EnumSet items; for (uint32_t i = 0; i < 200; ++i) { - items.Add(i); + TestEnum enumValue = static_cast(i); + items.Add(enumValue); EXPECT_FALSE(set.HasAnyOf(items)); - EXPECT_FALSE(set.HasAnyOf(EnumSet(i))); + EXPECT_FALSE(set.HasAnyOf(EnumSet(enumValue))); } } TEST(EnumSetHasAnyOf, MaskSetMaskQuery) { - EnumSet set(0); - EnumSet items(1); + EnumSet set(TestEnum::ZERO); + EnumSet items(TestEnum::ONE); EXPECT_FALSE(set.HasAnyOf(items)); - set.Add(2); - items.Add(3); + set.Add(TestEnum::TWO); + items.Add(TestEnum::THREE); EXPECT_FALSE(set.HasAnyOf(items)); - set.Add(3); + set.Add(TestEnum::THREE); EXPECT_TRUE(set.HasAnyOf(items)); - set.Add(4); + set.Add(TestEnum::FOUR); EXPECT_TRUE(set.HasAnyOf(items)); } TEST(EnumSetHasAnyOf, OverflowSetOverflowQuery) { - EnumSet set(100); - EnumSet items(200); + EnumSet set(TestEnum::ONE_HUNDRED); + EnumSet items(TestEnum::TWO_HUNDRED); EXPECT_FALSE(set.HasAnyOf(items)); - set.Add(300); - items.Add(400); + set.Add(TestEnum::THREE_HUNDRED); + items.Add(TestEnum::FOUR_HUNDRED); EXPECT_FALSE(set.HasAnyOf(items)); - set.Add(200); + set.Add(TestEnum::TWO_HUNDRED); EXPECT_TRUE(set.HasAnyOf(items)); - set.Add(500); + set.Add(TestEnum::FIVE_HUNDRED); EXPECT_TRUE(set.HasAnyOf(items)); } TEST(EnumSetHasAnyOf, GeneralCase) { - EnumSet set(0); - EnumSet items(100); + EnumSet set(TestEnum::ZERO); + EnumSet items(TestEnum::ONE_HUNDRED); EXPECT_FALSE(set.HasAnyOf(items)); - set.Add(300); - items.Add(4); + set.Add(TestEnum::THREE_HUNDRED); + items.Add(TestEnum::FOUR); EXPECT_FALSE(set.HasAnyOf(items)); - set.Add(5); - items.Add(500); + set.Add(TestEnum::FIVE); + items.Add(TestEnum::FIVE_HUNDRED); EXPECT_FALSE(set.HasAnyOf(items)); - set.Add(500); + set.Add(TestEnum::FIVE_HUNDRED); EXPECT_TRUE(set.HasAnyOf(items)); - EXPECT_FALSE(set.HasAnyOf(EnumSet(20))); - EXPECT_FALSE(set.HasAnyOf(EnumSet(600))); - EXPECT_TRUE(set.HasAnyOf(EnumSet(5))); - EXPECT_TRUE(set.HasAnyOf(EnumSet(300))); - EXPECT_TRUE(set.HasAnyOf(EnumSet(0))); + EXPECT_FALSE(set.HasAnyOf(EnumSet(TestEnum::TWENTY))); + EXPECT_FALSE(set.HasAnyOf(EnumSet(TestEnum::SIX_HUNDRED))); + EXPECT_TRUE(set.HasAnyOf(EnumSet(TestEnum::FIVE))); + EXPECT_TRUE(set.HasAnyOf(EnumSet(TestEnum::THREE_HUNDRED))); + EXPECT_TRUE(set.HasAnyOf(EnumSet(TestEnum::ZERO))); } TEST(EnumSet, DefaultIsEmpty) { - EnumSet set; + EnumSet set; for (uint32_t i = 0; i < 1000; ++i) { - EXPECT_FALSE(set.Contains(i)); + EXPECT_FALSE(set.Contains(static_cast(i))); + } +} + +TEST(CapabilitySet, ForEachOrderIsEnumOrder) { + constexpr size_t kValueCount = 500; + std::vector orderedValues(kValueCount); + for (size_t i = 0; i < kValueCount; i++) { + orderedValues[i] = static_cast(i); } + std::vector shuffledValues(orderedValues.cbegin(), orderedValues.cend()); + std::mt19937 rng(0); + std::shuffle(shuffledValues.begin(), shuffledValues.end(), rng); + + EnumSet set; + for (auto value : shuffledValues) { + set.Add(value); + } + + size_t index = 0; + set.ForEach([&orderedValues, &index](auto value) { + EXPECT_THAT(value, Eq(orderedValues[index])); + index++; + }); } TEST(CapabilitySet, ConstructSingleMemberMatrix) { @@ -230,6 +513,62 @@ TEST(CapabilitySet, InitializerListEmpty) { } } +TEST(CapabilitySet, LargeSetHasInsertedElements) { + CapabilitySet set; + for (auto c : kCapabilities) { + EXPECT_FALSE(set.Contains(c)); + } + + for (auto c : kCapabilities) { + set.Add(c); + EXPECT_TRUE(set.Contains(c)); + } + + for (auto c : kCapabilities) { + EXPECT_TRUE(set.Contains(c)); + } +} + +TEST(CapabilitySet, LargeSetHasUnsortedInsertedElements) { + std::vector shuffledCapabilities(kCapabilities.cbegin(), + kCapabilities.cend()); + std::mt19937 rng(0); + std::shuffle(shuffledCapabilities.begin(), shuffledCapabilities.end(), rng); + CapabilitySet set; + for (auto c : shuffledCapabilities) { + EXPECT_FALSE(set.Contains(c)); + } + + for (auto c : shuffledCapabilities) { + set.Add(c); + EXPECT_TRUE(set.Contains(c)); + } + + for (auto c : shuffledCapabilities) { + EXPECT_TRUE(set.Contains(c)); + } +} + +TEST(CapabilitySet, LargeSetHasUnsortedRemovedElement) { + std::vector shuffledCapabilities(kCapabilities.cbegin(), + kCapabilities.cend()); + std::mt19937 rng(0); + std::shuffle(shuffledCapabilities.begin(), shuffledCapabilities.end(), rng); + CapabilitySet set; + for (auto c : shuffledCapabilities) { + set.Add(c); + EXPECT_TRUE(set.Contains(c)); + } + + for (auto c : kCapabilities) { + set.Remove(c); + } + + for (auto c : shuffledCapabilities) { + EXPECT_FALSE(set.Contains(c)); + } +} + struct ForEachCase { CapabilitySet capabilities; std::vector expected; @@ -287,5 +626,20 @@ INSTANTIATE_TEST_SUITE_P( static_cast(0x7fffffff)}}, })); +using BoundaryTestWithParam = ::testing::TestWithParam; + +TEST_P(BoundaryTestWithParam, InsertedContains) { + CapabilitySet set; + set.Add(GetParam()); + EXPECT_TRUE(set.Contains(GetParam())); +} + +INSTANTIATE_TEST_SUITE_P( + Samples, BoundaryTestWithParam, + Values(static_cast(0), static_cast(63), + static_cast(64), static_cast(65), + static_cast(127), static_cast(128), + static_cast(129))); + } // namespace } // namespace spvtools From e751c7e7db28998c3c151e6702343afcfef7b17d Mon Sep 17 00:00:00 2001 From: David Neto Date: Fri, 7 Jul 2023 12:25:26 -0400 Subject: [PATCH 205/523] Treat spir-v.xml as utf-8 (#5306) * Treat spir-v.xml as utf-8 Treat the input file as utf-8, and configure the XML parser to use the utf-8 encoding. The Chromium build was breaking when trying to parse the XML file as ASCII. * Use Python io.open Try to fix the android-ndk-build flow. It seems to be using an old Python. For example, Python 2.6 builtin function open() did not support the 'encoding' keyword argument. But its io.open method did support it. --- utils/generate_registry_tables.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/utils/generate_registry_tables.py b/utils/generate_registry_tables.py index 28152ef3eb..14d4909fa6 100755 --- a/utils/generate_registry_tables.py +++ b/utils/generate_registry_tables.py @@ -15,8 +15,9 @@ """Generates the vendor tool table from the SPIR-V XML registry.""" import errno +import io import os.path -import xml.etree.ElementTree +from xml.etree.ElementTree import XML, XMLParser, TreeBuilder def mkdir_p(directory): @@ -78,8 +79,9 @@ def main(): help='output file for SPIR-V generators table') args = parser.parse_args() - with open(args.xml) as xml_in: - registry = xml.etree.ElementTree.fromstring(xml_in.read()) + with io.open(args.xml, encoding='utf-8') as xml_in: + parser = XMLParser(target=TreeBuilder(), encoding='utf-8') + registry = XML(xml_in.read(), parser=parser) mkdir_p(os.path.dirname(args.generator_output)) with open(args.generator_output, 'w') as f: From 4be7d0e3cac3a70fc3161a1656e52efbe46b6630 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Mon, 10 Jul 2023 08:21:45 -0700 Subject: [PATCH 206/523] Use android ndk r25 (#5309) * Use android ndk r25 We currently use R21 of the Android NDK for our tests. There have been to LTS release since that one, and we do not expect people to use it anymore. Also, it contains Python 2.7, not Python3. The python scripts in SPIR-V Tools expect Python 3, so we have to update. We chose the latest LTS release. * Roll external/googletest/ be03d00f5..4a1a299b2 (1 commit) https://github.com/google/googletest/compare/be03d00f5f0c...4a1a299b206b $ git log be03d00f5..4a1a299b2 --date=short --no-merges --format='%ad %ae %s' 2023-07-07 absl-team Update docstring of PrintWithFallback(..) to reflect the recently changed ordering. Created with: roll-dep external/googletest * Roll external/re2/ 1c1ffbe3c..a57a1d646 (2 commits) https://github.com/google/re2/compare/1c1ffbe3c6b2...a57a1d6462a1 $ git log 1c1ffbe3c..a57a1d646 --date=short --no-merges --format='%ad %ae %s' 2023-07-06 junyer Stop using `std::map`. 2023-07-06 junyer Bump the CMake baseline to 3.13. Created with: roll-dep external/re2 * Roll external/spirv-headers/ 3469b164e..d0006a393 (3 commits) https://github.com/KhronosGroup/SPIRV-Headers/compare/3469b164e25c...d0006a3938d7 $ git log 3469b164e..d0006a393 --date=short --no-merges --format='%ad %ae %s' 2023-07-05 lynix680 Regenerate headers 2023-06-30 lynix680 Add NZSL as a source language 2023-06-30 lynix680 Add NZSLc as a generator Created with: roll-dep external/spirv-headers --- DEPS | 6 +++--- kokoro/scripts/linux/build-docker.sh | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/DEPS b/DEPS index 969c760949..9177e1eb22 100644 --- a/DEPS +++ b/DEPS @@ -7,13 +7,13 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': 'be03d00f5f0cc3a997d1a368bee8a1fe93651f48', + 'googletest_revision': '4a1a299b206ba250a4318f74938ea67c75c3c0c9', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '1c1ffbe3c6b2bd26f65b1c1b7bc71d16ba162cf1', - 'spirv_headers_revision': '3469b164e25cee24435029a569933cb42578db5d', + 're2_revision': 'a57a1d6462a1613e5e2cfd6fb1ce26d36706a9af', + 'spirv_headers_revision': 'd0006a3938d7acedffb26ab517fe3e95b5288cc6', } deps = { diff --git a/kokoro/scripts/linux/build-docker.sh b/kokoro/scripts/linux/build-docker.sh index 4f24c2d192..679df0fc1a 100755 --- a/kokoro/scripts/linux/build-docker.sh +++ b/kokoro/scripts/linux/build-docker.sh @@ -156,7 +156,7 @@ elif [ $TOOL = "cmake-smoketest" ]; then echo $(date): ctest completed. elif [ $TOOL = "cmake-android-ndk" ]; then using cmake-3.17.2 - using ndk-r21d + using ndk-r25c using ninja-1.10.0 clean_dir "$ROOT_DIR/build" @@ -176,7 +176,7 @@ elif [ $TOOL = "cmake-android-ndk" ]; then ninja echo $(date): Build completed. elif [ $TOOL = "android-ndk-build" ]; then - using ndk-r21d + using ndk-r25c clean_dir "$ROOT_DIR/build" cd "$ROOT_DIR/build" From 4594ffce92f55c0afe26a62cb3c18f3cb262bb18 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 11 Jul 2023 11:54:04 +0000 Subject: [PATCH 207/523] Roll external/re2/ a57a1d646..e66463312 (1 commit) (#5313) https://github.com/google/re2/compare/a57a1d6462a1...e66463312e1d $ git log a57a1d646..e66463312 --date=short --no-merges --format='%ad %ae %s' 2023-07-10 junyer Avoid expanding counted repetitions of empty-width ops. 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 9177e1eb22..b3623c72ba 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': 'a57a1d6462a1613e5e2cfd6fb1ce26d36706a9af', + 're2_revision': 'e66463312e1d30d427bbde6c40e7fd627dcfb82e', 'spirv_headers_revision': 'd0006a3938d7acedffb26ab517fe3e95b5288cc6', } From 0530a532fc7a21c2065042580f3e3f6102dbdebf Mon Sep 17 00:00:00 2001 From: alan-baker Date: Tue, 11 Jul 2023 08:40:40 -0400 Subject: [PATCH 208/523] Validate GroupNonUniform instructions (#5296) Fixes #5283 * Validate group non-uniform instructions --- source/val/validate_non_uniform.cpp | 347 +++++++++++++- source/val/validation_state.cpp | 17 + source/val/validation_state.h | 1 + test/opt/amd_ext_to_khr.cpp | 21 +- test/val/val_non_uniform_test.cpp | 717 ++++++++++++++++++++++++++++ 5 files changed, 1094 insertions(+), 9 deletions(-) diff --git a/source/val/validate_non_uniform.cpp b/source/val/validate_non_uniform.cpp index af04e76af0..2c36ce3324 100644 --- a/source/val/validate_non_uniform.cpp +++ b/source/val/validate_non_uniform.cpp @@ -26,6 +26,207 @@ namespace spvtools { namespace val { namespace { +spv_result_t ValidateGroupNonUniformElect(ValidationState_t& _, + const Instruction* inst) { + if (!_.IsBoolScalarType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Result must be a boolean scalar type"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateGroupNonUniformAnyAll(ValidationState_t& _, + const Instruction* inst) { + if (!_.IsBoolScalarType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Result must be a boolean scalar type"; + } + + if (!_.IsBoolScalarType(_.GetOperandTypeId(inst, 3))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Predicate must be a boolean scalar type"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateGroupNonUniformAllEqual(ValidationState_t& _, + const Instruction* inst) { + if (!_.IsBoolScalarType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Result must be a boolean scalar type"; + } + + const auto value_type = _.GetOperandTypeId(inst, 3); + if (!_.IsFloatScalarOrVectorType(value_type) && + !_.IsIntScalarOrVectorType(value_type) && + !_.IsBoolScalarOrVectorType(value_type)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Value must be a scalar or vector of integer, floating-point, or " + "boolean type"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateGroupNonUniformBroadcastShuffle(ValidationState_t& _, + const Instruction* inst) { + const auto type_id = inst->type_id(); + if (!_.IsFloatScalarOrVectorType(type_id) && + !_.IsIntScalarOrVectorType(type_id) && + !_.IsBoolScalarOrVectorType(type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Result must be a scalar or vector of integer, floating-point, " + "or boolean type"; + } + + const auto value_type_id = _.GetOperandTypeId(inst, 3); + if (value_type_id != type_id) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "The type of Value must match the Result type"; + } + + const auto GetOperandName = [](const spv::Op opcode) { + std::string operand; + switch (opcode) { + case spv::Op::OpGroupNonUniformBroadcast: + case spv::Op::OpGroupNonUniformShuffle: + operand = "Id"; + break; + case spv::Op::OpGroupNonUniformShuffleXor: + operand = "Mask"; + break; + case spv::Op::OpGroupNonUniformQuadBroadcast: + operand = "Index"; + break; + case spv::Op::OpGroupNonUniformQuadSwap: + operand = "Direction"; + break; + case spv::Op::OpGroupNonUniformShuffleUp: + case spv::Op::OpGroupNonUniformShuffleDown: + default: + operand = "Delta"; + break; + } + return operand; + }; + + const auto id_type_id = _.GetOperandTypeId(inst, 4); + if (!_.IsUnsignedIntScalarType(id_type_id)) { + std::string operand = GetOperandName(inst->opcode()); + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << operand << " must be an unsigned integer scalar"; + } + + const bool should_be_constant = + inst->opcode() == spv::Op::OpGroupNonUniformQuadSwap || + ((inst->opcode() == spv::Op::OpGroupNonUniformBroadcast || + inst->opcode() == spv::Op::OpGroupNonUniformQuadBroadcast) && + _.version() < SPV_SPIRV_VERSION_WORD(1, 5)); + if (should_be_constant) { + const auto id_id = inst->GetOperandAs(4); + const auto id_op = _.GetIdOpcode(id_id); + if (!spvOpcodeIsConstant(id_op)) { + std::string operand = GetOperandName(inst->opcode()); + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Before SPIR-V 1.5, " << operand + << " must be a constant instruction"; + } + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateGroupNonUniformBroadcastFirst(ValidationState_t& _, + const Instruction* inst) { + const auto type_id = inst->type_id(); + if (!_.IsFloatScalarOrVectorType(type_id) && + !_.IsIntScalarOrVectorType(type_id) && + !_.IsBoolScalarOrVectorType(type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Result must be a scalar or vector of integer, floating-point, " + "or boolean type"; + } + + const auto value_type_id = _.GetOperandTypeId(inst, 3); + if (value_type_id != type_id) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "The type of Value must match the Result type"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateGroupNonUniformBallot(ValidationState_t& _, + const Instruction* inst) { + if (!_.IsUnsignedIntVectorType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Result must be a 4-component unsigned integer vector"; + } + + if (_.GetDimension(inst->type_id()) != 4) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Result must be a 4-component unsigned integer vector"; + } + + const auto pred_type_id = _.GetOperandTypeId(inst, 3); + if (!_.IsBoolScalarType(pred_type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Predicate must be a boolean scalar"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateGroupNonUniformInverseBallot(ValidationState_t& _, + const Instruction* inst) { + if (!_.IsBoolScalarType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Result must be a boolean scalar"; + } + + const auto value_type_id = _.GetOperandTypeId(inst, 3); + if (!_.IsUnsignedIntVectorType(value_type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Value must be a 4-component unsigned integer vector"; + } + + if (_.GetDimension(value_type_id) != 4) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Value must be a 4-component unsigned integer vector"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateGroupNonUniformBallotBitExtract(ValidationState_t& _, + const Instruction* inst) { + if (!_.IsBoolScalarType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Result must be a boolean scalar"; + } + + const auto value_type_id = _.GetOperandTypeId(inst, 3); + if (!_.IsUnsignedIntVectorType(value_type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Value must be a 4-component unsigned integer vector"; + } + + if (_.GetDimension(value_type_id) != 4) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Value must be a 4-component unsigned integer vector"; + } + + const auto id_type_id = _.GetOperandTypeId(inst, 4); + if (!_.IsUnsignedIntScalarType(id_type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Id must be an unsigned integer scalar"; + } + + return SPV_SUCCESS; +} + spv_result_t ValidateGroupNonUniformBallotBitCount(ValidationState_t& _, const Instruction* inst) { // Scope is already checked by ValidateExecutionScope() above. @@ -60,6 +261,107 @@ spv_result_t ValidateGroupNonUniformBallotBitCount(ValidationState_t& _, return SPV_SUCCESS; } +spv_result_t ValidateGroupNonUniformBallotFind(ValidationState_t& _, + const Instruction* inst) { + if (!_.IsUnsignedIntScalarType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Result must be an unsigned integer scalar"; + } + + const auto value_type_id = _.GetOperandTypeId(inst, 3); + if (!_.IsUnsignedIntVectorType(value_type_id)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Value must be a 4-component unsigned integer vector"; + } + + if (_.GetDimension(value_type_id) != 4) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Value must be a 4-component unsigned integer vector"; + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateGroupNonUniformArithmetic(ValidationState_t& _, + const Instruction* inst) { + const bool is_unsigned = inst->opcode() == spv::Op::OpGroupNonUniformUMin || + inst->opcode() == spv::Op::OpGroupNonUniformUMax; + const bool is_float = inst->opcode() == spv::Op::OpGroupNonUniformFAdd || + inst->opcode() == spv::Op::OpGroupNonUniformFMul || + inst->opcode() == spv::Op::OpGroupNonUniformFMin || + inst->opcode() == spv::Op::OpGroupNonUniformFMax; + const bool is_bool = inst->opcode() == spv::Op::OpGroupNonUniformLogicalAnd || + inst->opcode() == spv::Op::OpGroupNonUniformLogicalOr || + inst->opcode() == spv::Op::OpGroupNonUniformLogicalXor; + if (is_float) { + if (!_.IsFloatScalarOrVectorType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Result must be a floating-point scalar or vector"; + } + } else if (is_bool) { + if (!_.IsBoolScalarOrVectorType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Result must be a boolean scalar or vector"; + } + } else if (is_unsigned) { + if (!_.IsUnsignedIntScalarOrVectorType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Result must be an unsigned integer scalar or vector"; + } + } else if (!_.IsIntScalarOrVectorType(inst->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Result must be an integer scalar or vector"; + } + + const auto value_type_id = _.GetOperandTypeId(inst, 4); + if (value_type_id != inst->type_id()) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "The type of Value must match the Result type"; + } + + const auto group_op = inst->GetOperandAs(3); + bool is_clustered_reduce = group_op == spv::GroupOperation::ClusteredReduce; + bool is_partitioned_nv = + group_op == spv::GroupOperation::PartitionedReduceNV || + group_op == spv::GroupOperation::PartitionedInclusiveScanNV || + group_op == spv::GroupOperation::PartitionedExclusiveScanNV; + if (inst->operands().size() <= 5) { + if (is_clustered_reduce) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "ClusterSize must be present when Operation is ClusteredReduce"; + } else if (is_partitioned_nv) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Ballot must be present when Operation is PartitionedReduceNV, " + "PartitionedInclusiveScanNV, or PartitionedExclusiveScanNV"; + } + } else { + const auto operand_id = inst->GetOperandAs(5); + const auto* operand = _.FindDef(operand_id); + if (is_partitioned_nv) { + if (!operand || !_.IsIntScalarOrVectorType(operand->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Ballot must be a 4-component integer vector"; + } + + if (_.GetDimension(operand->type_id()) != 4) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Ballot must be a 4-component integer vector"; + } + } else { + if (!operand || !_.IsUnsignedIntScalarType(operand->type_id())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "ClusterSize must be an unsigned integer scalar"; + } + + if (!spvOpcodeIsConstant(operand->opcode())) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "ClusterSize must be a constant instruction"; + } + } + } + return SPV_SUCCESS; +} + spv_result_t ValidateGroupNonUniformRotateKHR(ValidationState_t& _, const Instruction* inst) { // Scope is already checked by ValidateExecutionScope() above. @@ -120,15 +422,58 @@ spv_result_t NonUniformPass(ValidationState_t& _, const Instruction* inst) { const spv::Op opcode = inst->opcode(); if (spvOpcodeIsNonUniformGroupOperation(opcode)) { - const uint32_t execution_scope = inst->word(3); + const uint32_t execution_scope = inst->GetOperandAs(2); if (auto error = ValidateExecutionScope(_, inst, execution_scope)) { return error; } } switch (opcode) { + case spv::Op::OpGroupNonUniformElect: + return ValidateGroupNonUniformElect(_, inst); + case spv::Op::OpGroupNonUniformAny: + case spv::Op::OpGroupNonUniformAll: + return ValidateGroupNonUniformAnyAll(_, inst); + case spv::Op::OpGroupNonUniformAllEqual: + return ValidateGroupNonUniformAllEqual(_, inst); + case spv::Op::OpGroupNonUniformBroadcast: + case spv::Op::OpGroupNonUniformShuffle: + case spv::Op::OpGroupNonUniformShuffleXor: + case spv::Op::OpGroupNonUniformShuffleUp: + case spv::Op::OpGroupNonUniformShuffleDown: + case spv::Op::OpGroupNonUniformQuadBroadcast: + case spv::Op::OpGroupNonUniformQuadSwap: + return ValidateGroupNonUniformBroadcastShuffle(_, inst); + case spv::Op::OpGroupNonUniformBroadcastFirst: + return ValidateGroupNonUniformBroadcastFirst(_, inst); + case spv::Op::OpGroupNonUniformBallot: + return ValidateGroupNonUniformBallot(_, inst); + case spv::Op::OpGroupNonUniformInverseBallot: + return ValidateGroupNonUniformInverseBallot(_, inst); + case spv::Op::OpGroupNonUniformBallotBitExtract: + return ValidateGroupNonUniformBallotBitExtract(_, inst); case spv::Op::OpGroupNonUniformBallotBitCount: return ValidateGroupNonUniformBallotBitCount(_, inst); + case spv::Op::OpGroupNonUniformBallotFindLSB: + case spv::Op::OpGroupNonUniformBallotFindMSB: + return ValidateGroupNonUniformBallotFind(_, inst); + case spv::Op::OpGroupNonUniformIAdd: + case spv::Op::OpGroupNonUniformFAdd: + case spv::Op::OpGroupNonUniformIMul: + case spv::Op::OpGroupNonUniformFMul: + case spv::Op::OpGroupNonUniformSMin: + case spv::Op::OpGroupNonUniformUMin: + case spv::Op::OpGroupNonUniformFMin: + case spv::Op::OpGroupNonUniformSMax: + case spv::Op::OpGroupNonUniformUMax: + case spv::Op::OpGroupNonUniformFMax: + case spv::Op::OpGroupNonUniformBitwiseAnd: + case spv::Op::OpGroupNonUniformBitwiseOr: + case spv::Op::OpGroupNonUniformBitwiseXor: + case spv::Op::OpGroupNonUniformLogicalAnd: + case spv::Op::OpGroupNonUniformLogicalOr: + case spv::Op::OpGroupNonUniformLogicalXor: + return ValidateGroupNonUniformArithmetic(_, inst); case spv::Op::OpGroupNonUniformRotateKHR: return ValidateGroupNonUniformRotateKHR(_, inst); default: diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index d1572591ec..6071ce2067 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1010,6 +1010,23 @@ bool ValidationState_t::IsUnsignedIntVectorType(uint32_t id) const { return false; } +bool ValidationState_t::IsUnsignedIntScalarOrVectorType(uint32_t id) const { + const Instruction* inst = FindDef(id); + if (!inst) { + return false; + } + + if (inst->opcode() == spv::Op::OpTypeInt) { + return inst->GetOperandAs(2) == 0; + } + + if (inst->opcode() == spv::Op::OpTypeVector) { + return IsUnsignedIntScalarType(GetComponentType(id)); + } + + return false; +} + bool ValidationState_t::IsSignedIntScalarType(uint32_t id) const { const Instruction* inst = FindDef(id); return inst && inst->opcode() == spv::Op::OpTypeInt && inst->word(3) == 1; diff --git a/source/val/validation_state.h b/source/val/validation_state.h index bfae821478..1a64a41c99 100644 --- a/source/val/validation_state.h +++ b/source/val/validation_state.h @@ -602,6 +602,7 @@ class ValidationState_t { bool IsIntScalarOrVectorType(uint32_t id) const; bool IsUnsignedIntScalarType(uint32_t id) const; bool IsUnsignedIntVectorType(uint32_t id) const; + bool IsUnsignedIntScalarOrVectorType(uint32_t id) const; bool IsSignedIntScalarType(uint32_t id) const; bool IsSignedIntVectorType(uint32_t id) const; bool IsBoolScalarType(uint32_t id) const; diff --git a/test/opt/amd_ext_to_khr.cpp b/test/opt/amd_ext_to_khr.cpp index 3340e898ce..a520d600b1 100644 --- a/test/opt/amd_ext_to_khr.cpp +++ b/test/opt/amd_ext_to_khr.cpp @@ -26,15 +26,17 @@ using AmdExtToKhrTest = PassTest<::testing::Test>; using ::testing::HasSubstr; -std::string GetTest(std::string op_code, std::string new_op_code) { +std::string GetTest(std::string op_code, std::string new_op_code, + bool is_float = false) { const std::string text = R"( ; CHECK: OpCapability Shader ; CHECK-NOT: OpExtension "SPV_AMD_shader_ballot" ; CHECK: OpFunction ; CHECK-NEXT: OpLabel -; CHECK-NEXT: [[undef:%\w+]] = OpUndef %uint +; CHECK-NEXT: [[undef:%\w+]] = OpUndef % ; CHECK-NEXT: )" + new_op_code + - R"( %uint %uint_3 Reduce [[undef]] + " %" + (is_float ? "float" : "uint") + + R"( %uint_3 Reduce [[undef]] OpCapability Shader OpCapability Groups OpExtension "SPV_AMD_shader_ballot" @@ -44,12 +46,15 @@ std::string GetTest(std::string op_code, std::string new_op_code) { %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 + %float = OpTypeFloat 32 %uint_3 = OpConstant %uint 3 %1 = OpFunction %void None %3 %6 = OpLabel - %7 = OpUndef %uint + %7 = OpUndef %)" + + (is_float ? "float" : "uint") + R"( %8 = )" + op_code + - R"( %uint %uint_3 Reduce %7 + " %" + (is_float ? "float" : "uint") + + R"( %uint_3 Reduce %7 OpReturn OpFunctionEnd @@ -64,7 +69,7 @@ TEST_F(AmdExtToKhrTest, ReplaceGroupIAddNonUniformAMD) { } TEST_F(AmdExtToKhrTest, ReplaceGroupFAddNonUniformAMD) { std::string text = - GetTest("OpGroupFAddNonUniformAMD", "OpGroupNonUniformFAdd"); + GetTest("OpGroupFAddNonUniformAMD", "OpGroupNonUniformFAdd", true); SinglePassRunAndMatch(text, true); } TEST_F(AmdExtToKhrTest, ReplaceGroupUMinNonUniformAMD) { @@ -79,7 +84,7 @@ TEST_F(AmdExtToKhrTest, ReplaceGroupSMinNonUniformAMD) { } TEST_F(AmdExtToKhrTest, ReplaceGroupFMinNonUniformAMD) { std::string text = - GetTest("OpGroupFMinNonUniformAMD", "OpGroupNonUniformFMin"); + GetTest("OpGroupFMinNonUniformAMD", "OpGroupNonUniformFMin", true); SinglePassRunAndMatch(text, true); } TEST_F(AmdExtToKhrTest, ReplaceGroupUMaxNonUniformAMD) { @@ -94,7 +99,7 @@ TEST_F(AmdExtToKhrTest, ReplaceGroupSMaxNonUniformAMD) { } TEST_F(AmdExtToKhrTest, ReplaceGroupFMaxNonUniformAMD) { std::string text = - GetTest("OpGroupFMaxNonUniformAMD", "OpGroupNonUniformFMax"); + GetTest("OpGroupFMaxNonUniformAMD", "OpGroupNonUniformFMax", true); SinglePassRunAndMatch(text, true); } diff --git a/test/val/val_non_uniform_test.cpp b/test/val/val_non_uniform_test.cpp index af571d3a9f..a020500d66 100644 --- a/test/val/val_non_uniform_test.cpp +++ b/test/val/val_non_uniform_test.cpp @@ -44,6 +44,8 @@ OpCapability GroupNonUniformShuffleRelative OpCapability GroupNonUniformArithmetic OpCapability GroupNonUniformClustered OpCapability GroupNonUniformQuad +OpCapability GroupNonUniformPartitionedNV +OpExtension "SPV_NV_shader_subgroup_partitioned" )"; ss << capabilities_and_extensions; @@ -62,16 +64,27 @@ OpCapability GroupNonUniformQuad %float = OpTypeFloat 32 %u32vec4 = OpTypeVector %u32 4 %u32vec3 = OpTypeVector %u32 3 +%v2bool = OpTypeVector %bool 2 +%v4float = OpTypeVector %float 4 +%struct = OpTypeStruct %int +%v4int = OpTypeVector %int 4 %true = OpConstantTrue %bool %false = OpConstantFalse %bool %u32_0 = OpConstant %u32 0 +%int_0 = OpConstant %int 0 %float_0 = OpConstant %float 0 %u32vec4_null = OpConstantComposite %u32vec4 %u32_0 %u32_0 %u32_0 %u32_0 %u32vec3_null = OpConstantComposite %u32vec3 %u32_0 %u32_0 %u32_0 +%v2bool_false = OpConstantNull %v2bool +%v4float_null = OpConstantNull %v4float +%struct_null = OpConstantNull %struct +%v4int_null = OpConstantComposite %v4int %int_0 %int_0 %int_0 %int_0 + +%u32_undef = OpUndef %u32 %cross_device = OpConstant %u32 0 %device = OpConstant %u32 1 @@ -122,6 +135,32 @@ std::string ConvertScope(spv::Scope scope) { } } +std::string ConvertMatch(const std::string& type) { + if (type == "%bool") { + return "%true"; + } else if (type == "%u32") { + return "%u32_0"; + } else if (type == "%int") { + return "%int_0"; + } else if (type == "%float") { + return "%float_0"; + } else if (type == "%u32vec4") { + return "%u32vec4_null"; + } else if (type == "%u32vec3") { + return "%u32vec3_null"; + } else if (type == "%v2bool") { + return "%v2bool_false"; + } else if (type == "%v4float") { + return "%v4float_null"; + } else if (type == "%struct") { + return "%struct_null"; + } else if (type == "%v4int") { + return "%v4int_null"; + } + + return "INVALID"; +} + TEST_P(GroupNonUniform, Vulkan1p1) { std::string opcode = std::get<0>(GetParam()); std::string type = std::get<1>(GetParam()); @@ -129,6 +168,13 @@ TEST_P(GroupNonUniform, Vulkan1p1) { std::string args = std::get<3>(GetParam()); std::string error = std::get<4>(GetParam()); + const std::string match = "match_res"; + size_t pos = std::string::npos; + while ((pos = args.find(match)) != std::string::npos) { + const std::string replace = ConvertMatch(type); + args = args.substr(0, pos) + replace + args.substr(pos + match.size()); + } + std::ostringstream sstr; sstr << "%result = " << opcode << " "; sstr << type << " "; @@ -162,6 +208,13 @@ TEST_P(GroupNonUniform, Spirv1p3) { std::string args = std::get<3>(GetParam()); std::string error = std::get<4>(GetParam()); + const std::string match = "match_res"; + size_t pos = std::string::npos; + while ((pos = args.find(match)) != std::string::npos) { + const std::string replace = ConvertMatch(type); + args = args.substr(0, pos) + replace + args.substr(pos + match.size()); + } + std::ostringstream sstr; sstr << "%result = " << opcode << " "; sstr << type << " "; @@ -292,6 +345,530 @@ INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallotBitCountBadValue, GroupNonUniform, Values("Expected Value to be a vector of four " "components of integer type scalar"))); +INSTANTIATE_TEST_SUITE_P(GroupNonUniformElectGood, GroupNonUniform, + Combine(Values("OpGroupNonUniformElect"), + Values("%bool"), Values(spv::Scope::Subgroup), + Values(""), Values(""))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformElectBadResultType, GroupNonUniform, + Combine(Values("OpGroupNonUniformElect"), + Values("%void", "%u32", "%int", "%float", "%u32vec4", "%u32vec3", + "%v2bool", "%v4float", "%struct"), + Values(spv::Scope::Subgroup), Values(""), + Values("Result must be a boolean scalar type"))); + +INSTANTIATE_TEST_SUITE_P(GroupNonUniformAnyAllGood, GroupNonUniform, + Combine(Values("OpGroupNonUniformAny", + "OpGroupNonUniformAll"), + Values("%bool"), Values(spv::Scope::Subgroup), + Values("%true", "%false"), Values(""))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformAnyAllBadResultType, GroupNonUniform, + Combine(Values("OpGroupNonUniformAny", "OpGroupNonUniformAll"), + Values("%void", "%u32", "%int", "%float", "%u32vec4", "%u32vec3", + "%v2bool", "%v4float", "%struct"), + Values(spv::Scope::Subgroup), Values("%true"), + Values("Result must be a boolean scalar type"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformAnyAllBadOperand, GroupNonUniform, + Combine(Values("OpGroupNonUniformAny", "OpGroupNonUniformAll"), + Values("%bool"), Values(spv::Scope::Subgroup), + Values("%u32_0", "%int_0", "%float_0", "%u32vec4_null", + "%u32vec3_null", "%v2bool_false", "%v4float_null", + "%struct_null"), + Values("Predicate must be a boolean scalar type"))); + +INSTANTIATE_TEST_SUITE_P(GroupNonUniformAllEqualGood, GroupNonUniform, + Combine(Values("OpGroupNonUniformAllEqual"), + Values("%bool"), Values(spv::Scope::Subgroup), + Values("%true", "%false"), Values(""))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformAllEqualBadResultType, GroupNonUniform, + Combine(Values("OpGroupNonUniformAllEqual"), + Values("%void", "%u32", "%int", "%float", "%u32vec4", "%u32vec3", + "%v2bool", "%v4float", "%struct"), + Values(spv::Scope::Subgroup), Values("%true"), + Values("Result must be a boolean scalar type"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformAllEqualBadOperand, GroupNonUniform, + Combine(Values("OpGroupNonUniformAllEqual"), Values("%bool"), + Values(spv::Scope::Subgroup), Values("%struct_null"), + Values("Value must be a scalar or vector of integer, " + "floating-point, or boolean type"))); + +INSTANTIATE_TEST_SUITE_P(GroupNonUniformBroadcastGood, GroupNonUniform, + Combine(Values("OpGroupNonUniformBroadcast", + "OpGroupNonUniformQuadBroadcast", + "OpGroupNonUniformQuadSwap"), + Values("%bool", "%u32", "%int", "%float", + "%u32vec4", "%u32vec3", "%v2bool", + "%v4float", "%v4int"), + Values(spv::Scope::Subgroup), + Values("match_res %u32_0"), Values(""))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBroadcastShuffleBadResultType, GroupNonUniform, + Combine(Values("OpGroupNonUniformBroadcast", "OpGroupNonUniformShuffle", + "OpGroupNonUniformShuffleXor", "OpGroupNonUniformShuffleUp", + "OpGroupNonUniformShuffleDown", + "OpGroupNonUniformQuadBroadcast", + "OpGroupNonUniformQuadSwap"), + Values("%void", "%struct"), Values(spv::Scope::Subgroup), + Values("%u32_0 %u32_0"), + Values("Result must be a scalar or vector of integer, " + "floating-point, or boolean type"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBroadcastShuffleBadOperand1, GroupNonUniform, + Combine(Values("OpGroupNonUniformBroadcast", "OpGroupNonUniformShuffle", + "OpGroupNonUniformShuffleXor", "OpGroupNonUniformShuffleUp", + "OpGroupNonUniformShuffleDown", + "OpGroupNonUniformQuadBroadcast", + "OpGroupNonUniformQuadSwap"), + Values("%bool"), Values(spv::Scope::Subgroup), + Values("%u32_0 %u32_0", "%int_0 %u32_0", "%float_0 %u32_0", + "%u32vec4_null %u32_0", "%u32vec3_null %u32_0", + "%v2bool_false %u32_0", "%v4float_null %u32_0", + "%struct_null %u32_0", "%v4int_null %u32_0"), + Values("The type of Value must match the Result type"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBroadcastShuffleBadOperand2, GroupNonUniform, + Combine(Values("OpGroupNonUniformBroadcast", "OpGroupNonUniformShuffle", + "OpGroupNonUniformShuffleXor", "OpGroupNonUniformShuffleUp", + "OpGroupNonUniformShuffleDown", + "OpGroupNonUniformQuadBroadcast", + "OpGroupNonUniformQuadSwap"), + Values("%bool"), Values(spv::Scope::Subgroup), + Values("%true %true", "%true %int_0", "%true %float_0", + "%true %u32vec4_null", "%true %u32vec3_null", + "%true %v4float_null", "%true %v2bool_false", + "%true %struct_null", "%true %v4int_null"), + Values("must be an unsigned integer scalar"))); + +INSTANTIATE_TEST_SUITE_P(GroupNonUniformBroadcastShuffleOperand2NotConstant, + GroupNonUniform, + Combine(Values("OpGroupNonUniformBroadcast", + "OpGroupNonUniformQuadBroadcast", + "OpGroupNonUniformQuadSwap"), + Values("%bool"), Values(spv::Scope::Subgroup), + Values("%true %u32_undef"), + Values("must be a constant instruction"))); + +INSTANTIATE_TEST_SUITE_P(GroupNonUniformBroadcastFirstGood, GroupNonUniform, + Combine(Values("OpGroupNonUniformBroadcastFirst"), + Values("%bool", "%u32", "%int", "%float", + "%u32vec4", "%u32vec3", "%v2bool", + "%v4float", "%v4int"), + Values(spv::Scope::Subgroup), + Values("match_res"), Values(""))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBroadcasFirsttBadResultType, GroupNonUniform, + Combine(Values("OpGroupNonUniformBroadcastFirst"), + Values("%void", "%struct"), Values(spv::Scope::Subgroup), + Values("%u32_0"), + Values("Result must be a scalar or vector of integer, " + "floating-point, or boolean type"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBroadcastBadOperand, GroupNonUniform, + Combine(Values("OpGroupNonUniformBroadcastFirst"), Values("%bool"), + Values(spv::Scope::Subgroup), + Values("%u32_0", "%int_0", "%float_0", "%u32vec4_null", + "%u32vec3_null", "%v2bool_false", "%v4float_null", + "%struct_null", "%v4int_null"), + Values("The type of Value must match the Result type"))); + +INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallotGood, GroupNonUniform, + Combine(Values("OpGroupNonUniformBallot"), + Values("%u32vec4"), + Values(spv::Scope::Subgroup), + Values("%true", "%false"), Values(""))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBallotBadResultType, GroupNonUniform, + Combine(Values("OpGroupNonUniformBallot"), + Values("%void", "%bool", "%u32", "%int", "%float", "%u32vec3", + "%v2bool", "%v4float", "%struct", "%v4int"), + Values(spv::Scope::Subgroup), Values("%true", "%false"), + Values("Result must be a 4-component unsigned integer vector"))); + +INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallotBadOperand, GroupNonUniform, + Combine(Values("OpGroupNonUniformBallot"), + Values("%u32vec4"), + Values(spv::Scope::Subgroup), + Values("%u32_0", "%int_0", "%float_0", + "%u32vec4_null", "%u32vec3_null", + "%v2bool_false", "%v4float_null", + "%struct_null", "%v4int_null"), + Values("Predicate must be a boolean scalar"))); + +INSTANTIATE_TEST_SUITE_P(GroupNonUniformInverseBallotGood, GroupNonUniform, + Combine(Values("OpGroupNonUniformInverseBallot"), + Values("%bool"), Values(spv::Scope::Subgroup), + Values("%u32vec4_null"), Values(""))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformInverseBallotBadResultType, GroupNonUniform, + Combine(Values("OpGroupNonUniformInverseBallot"), + Values("%void", "%u32", "%int", "%float", "%u32vec4", "%u32vec3", + "%v2bool", "%v4float", "%struct", "%v4int"), + Values(spv::Scope::Subgroup), Values("%u32vec4_null"), + Values("Result must be a boolean scalar"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformInverseBallotBadOperand, GroupNonUniform, + Combine(Values("OpGroupNonUniformInverseBallot"), Values("%bool"), + Values(spv::Scope::Subgroup), + Values("%true", "%false", "%u32_0", "%int_0", "%float_0", + "%u32vec3_null", "%v2bool_false", "%v4float_null", + "%struct_null", "%v4int_null"), + Values("Value must be a 4-component unsigned integer vector"))); + +INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallotBitExtractGood, GroupNonUniform, + Combine(Values("OpGroupNonUniformBallotBitExtract"), + Values("%bool"), Values(spv::Scope::Subgroup), + Values("%u32vec4_null %u32_0"), Values(""))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBallotBitExtractBadResultType, GroupNonUniform, + Combine(Values("OpGroupNonUniformBallotBitExtract"), + Values("%void", "%u32", "%int", "%float", "%u32vec4", "%u32vec3", + "%v2bool", "%v4float", "%struct", "%v4int"), + Values(spv::Scope::Subgroup), Values("%u32vec4_null %u32_0"), + Values("Result must be a boolean scalar"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBallotBitExtractBadOperand1, GroupNonUniform, + Combine(Values("OpGroupNonUniformBallotBitExtract"), Values("%bool"), + Values(spv::Scope::Subgroup), + Values("%true %u32_0", "%false %u32_0", "%u32_0 %u32_0", + "%int_0 %u32_0", "%float_0 %u32_0", "%u32vec3_null %u32_0", + "%v2bool_false %u32_0", "%v4float_null %u32_0", + "%struct_null %u32_0", "%v4int_null %u32_0"), + Values("Value must be a 4-component unsigned integer vector"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBallotBitExtractBadOperand2, GroupNonUniform, + Combine(Values("OpGroupNonUniformBallotBitExtract"), Values("%bool"), + Values(spv::Scope::Subgroup), + Values("%u32vec4_null %true", "%u32vec4_null %false", + "%u32vec4_null %int_0", "%u32vec4_null %float_0", + "%u32vec4_null %u32vec3_null", "%u32vec4_null %v2bool_false", + "%u32vec4_null %v4float_null", "%u32vec4_null %struct_null", + "%u32vec4_null %v4int_null"), + Values("Id must be an unsigned integer scalar"))); + +INSTANTIATE_TEST_SUITE_P(GroupNonUniformBallotFindGood, GroupNonUniform, + Combine(Values("OpGroupNonUniformBallotFindLSB", + "OpGroupNonUniformBallotFindMSB"), + Values("%u32"), Values(spv::Scope::Subgroup), + Values("%u32vec4_null"), Values(""))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBallotFindBadResultType, GroupNonUniform, + Combine(Values("OpGroupNonUniformBallotFindLSB", + "OpGroupNonUniformBallotFindMSB"), + Values("%void", "%bool", "%int", "%float", "%u32vec4", "%u32vec3", + "%v2bool", "%v4float", "%struct", "%v4int"), + Values(spv::Scope::Subgroup), Values("%u32vec4_null"), + Values("Result must be an unsigned integer scalar"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBallotFindBadOperand, GroupNonUniform, + Combine(Values("OpGroupNonUniformBallotFindLSB", + "OpGroupNonUniformBallotFindMSB"), + Values("%u32"), Values(spv::Scope::Subgroup), + Values("%true", "%false", "%u32_0", "%int_0", "%float_0", + "%u32vec3_null", "%v2bool_false", "%v4float_null", + "%struct_null", "%v4int_null"), + Values("Value must be a 4-component unsigned integer vector"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformIntegerArithmeticGood, GroupNonUniform, + Combine(Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul", + "OpGroupNonUniformSMin", "OpGroupNonUniformSMax", + "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr", + "OpGroupNonUniformBitwiseXor"), + Values("%u32", "%int", "%u32vec4", "%u32vec3", "%v4int"), + Values(spv::Scope::Subgroup), + Values("Reduce match_res", "InclusiveScan match_res", + "ExclusiveScan match_res", + "ClusteredReduce match_res %u32_0", + "PartitionedReduceNV match_res %u32vec4_null", + "PartitionedInclusiveScanNV match_res %u32vec4_null", + "PartitionedExclusiveScanNV match_res %v4int_null"), + Values(""))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformIntegerArithmeticBadResultType, GroupNonUniform, + Combine(Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul", + "OpGroupNonUniformSMin", "OpGroupNonUniformSMax", + "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr", + "OpGroupNonUniformBitwiseXor"), + Values("%bool", "%float", "%v4float", "%struct"), + Values(spv::Scope::Subgroup), + Values("Reduce match_res", "InclusiveScan match_res", + "ExclusiveScan match_res", + "ClusteredReduce match_res %u32_0"), + Values("Result must be an integer scalar or vector"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformIntegerArithmeticBadValue, GroupNonUniform, + Combine(Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul", + "OpGroupNonUniformSMin", "OpGroupNonUniformSMax", + "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr", + "OpGroupNonUniformBitwiseXor"), + Values("%int", "%u32vec4", "%u32vec3", "%v4int"), + Values(spv::Scope::Subgroup), + Values("Reduce %u32_0", "InclusiveScan %u32_0", + "ExclusiveScan %u32_0", "ClusteredReduce %u32_0 %u32_0"), + Values("The type of Value must match the Result type"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformIntegerArithmeticMissingClusterSize, GroupNonUniform, + Combine( + Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul", + "OpGroupNonUniformSMin", "OpGroupNonUniformUMin", + "OpGroupNonUniformSMax", "OpGroupNonUniformUMax", + "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr", + "OpGroupNonUniformBitwiseXor"), + Values("%u32"), Values(spv::Scope::Subgroup), + Values("ClusteredReduce match_res"), + Values( + "ClusterSize must be present when Operation is ClusteredReduce"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformIntegerArithmeticMissingBallot, GroupNonUniform, + Combine( + Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul", + "OpGroupNonUniformSMin", "OpGroupNonUniformUMin", + "OpGroupNonUniformSMax", "OpGroupNonUniformUMax", + "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr", + "OpGroupNonUniformBitwiseXor"), + Values("%u32"), Values(spv::Scope::Subgroup), + Values("PartitionedReduceNV match_res", + "PartitionedInclusiveScanNV match_res", + "PartitionedExclusiveScanNV match_res"), + Values("Ballot must be present when Operation is PartitionedReduceNV, " + "PartitionedInclusiveScanNV, or PartitionedExclusiveScanNV"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformIntegerArithmeticBadClusterSizeType, GroupNonUniform, + Combine(Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul", + "OpGroupNonUniformSMin", "OpGroupNonUniformUMin", + "OpGroupNonUniformSMax", "OpGroupNonUniformUMax", + "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr", + "OpGroupNonUniformBitwiseXor"), + Values("%u32"), Values(spv::Scope::Subgroup), + Values("ClusteredReduce match_res %true", + "ClusteredReduce match_res %false", + "ClusteredReduce match_res %int_0", + "ClusteredReduce match_res %float_0", + "ClusteredReduce match_res %u32vec4_null", + "ClusteredReduce match_res %u32vec3_null", + "ClusteredReduce match_res %v2bool_false", + "ClusteredReduce match_res %v4float_null", + "ClusteredReduce match_res %struct_null", + "ClusteredReduce match_res %v4int_null"), + Values("ClusterSize must be an unsigned integer scalar"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformIntegerArithmeticBadBallotType, GroupNonUniform, + Combine(Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul", + "OpGroupNonUniformSMin", "OpGroupNonUniformUMin", + "OpGroupNonUniformSMax", "OpGroupNonUniformUMax", + "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr", + "OpGroupNonUniformBitwiseXor"), + Values("%u32"), Values(spv::Scope::Subgroup), + Values("PartitionedReduceNV match_res %true", + "PartitionedReduceNV match_res %false", + "PartitionedReduceNV match_res %int_0", + "PartitionedReduceNV match_res %float_0", + "PartitionedReduceNV match_res %u32_0", + "PartitionedReduceNV match_res %u32vec3_null", + "PartitionedReduceNV match_res %v2bool_false", + "PartitionedReduceNV match_res %v4float_null", + "PartitionedReduceNV match_res %struct_null"), + Values("Ballot must be a 4-component integer vector"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformIntegerArithmeticClusterSizeNotConstant, GroupNonUniform, + Combine(Values("OpGroupNonUniformIAdd", "OpGroupNonUniformIMul", + "OpGroupNonUniformSMin", "OpGroupNonUniformUMin", + "OpGroupNonUniformSMax", "OpGroupNonUniformUMax", + "OpGroupNonUniformBitwiseAnd", "OpGroupNonUniformBitwiseOr", + "OpGroupNonUniformBitwiseXor"), + Values("%u32"), Values(spv::Scope::Subgroup), + Values("ClusteredReduce match_res %u32_undef"), + Values("ClusterSize must be a constant instruction"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformUnsignedIntegerArithmeticGood, GroupNonUniform, + Combine(Values("OpGroupNonUniformUMin", "OpGroupNonUniformUMax"), + Values("%u32", "%u32vec4", "%u32vec3"), + Values(spv::Scope::Subgroup), + Values("Reduce match_res", "InclusiveScan match_res", + "ExclusiveScan match_res", + "ClusteredReduce match_res %u32_0"), + Values(""))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformUnsignedIntegerArithmeticBadResultType, GroupNonUniform, + Combine(Values("OpGroupNonUniformUMin", "OpGroupNonUniformUMax"), + Values("%bool", "%int", "%float", "%v4float", "%struct", "%v4int"), + Values(spv::Scope::Subgroup), + Values("Reduce match_res", "InclusiveScan match_res", + "ExclusiveScan match_res", + "ClusteredReduce match_res %u32_0"), + Values("Result must be an unsigned integer scalar or vector"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformUnsignedIntegerArithmeticBadValue, GroupNonUniform, + Combine(Values("OpGroupNonUniformUMin", "OpGroupNonUniformUMax"), + Values("%u32vec4", "%u32vec3"), Values(spv::Scope::Subgroup), + Values("Reduce %u32_0", "InclusiveScan %u32_0", + "ExclusiveScan %u32_0", "ClusteredReduce %u32_0 %u32_0"), + Values("The type of Value must match the Result type"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformFloatArithmeticGood, GroupNonUniform, + Combine(Values("OpGroupNonUniformFAdd", "OpGroupNonUniformFMul", + "OpGroupNonUniformFMin", "OpGroupNonUniformFMax"), + Values("%float", "%v4float"), Values(spv::Scope::Subgroup), + Values("Reduce match_res", "InclusiveScan match_res", + "ExclusiveScan match_res", + "ClusteredReduce match_res %u32_0"), + Values(""))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformFloatArithmeticBadResultType, GroupNonUniform, + Combine(Values("OpGroupNonUniformFAdd", "OpGroupNonUniformFMul", + "OpGroupNonUniformFMin", "OpGroupNonUniformFMax"), + Values("%bool", "%u32", "%int", "%u32vec4", "%u32vec3", "%struct", + "%v4int"), + Values(spv::Scope::Subgroup), + Values("Reduce match_res", "InclusiveScan match_res", + "ExclusiveScan match_res", + "ClusteredReduce match_res %u32_0"), + Values("Result must be a floating-point scalar or vector"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformFloatArithmeticBadValue, GroupNonUniform, + Combine(Values("OpGroupNonUniformFAdd", "OpGroupNonUniformFMul", + "OpGroupNonUniformFMin", "OpGroupNonUniformFMax"), + Values("%v4float"), Values(spv::Scope::Subgroup), + Values("Reduce %float_0", "InclusiveScan %float_0", + "ExclusiveScan %float_0", "ClusteredReduce %float_0 %u32_0"), + Values("The type of Value must match the Result type"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformFloatArithmeticMissingClusterSize, GroupNonUniform, + Combine( + Values("OpGroupNonUniformFAdd", "OpGroupNonUniformFMul", + "OpGroupNonUniformFMin", "OpGroupNonUniformFMax"), + Values("%float"), Values(spv::Scope::Subgroup), + Values("ClusteredReduce match_res"), + Values( + "ClusterSize must be present when Operation is ClusteredReduce"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformFloatArithmeticBadClusterSizeType, GroupNonUniform, + Combine(Values("OpGroupNonUniformFAdd", "OpGroupNonUniformFMul", + "OpGroupNonUniformFMin", "OpGroupNonUniformFMax"), + Values("%float"), Values(spv::Scope::Subgroup), + Values("ClusteredReduce match_res %true", + "ClusteredReduce match_res %false", + "ClusteredReduce match_res %int_0", + "ClusteredReduce match_res %float_0", + "ClusteredReduce match_res %u32vec4_null", + "ClusteredReduce match_res %u32vec3_null", + "ClusteredReduce match_res %v2bool_false", + "ClusteredReduce match_res %v4float_null", + "ClusteredReduce match_res %struct_null", + "ClusteredReduce match_res %v4int_null"), + Values("ClusterSize must be an unsigned integer scalar"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformFloatArithmeticClusterSizeNotConstant, GroupNonUniform, + Combine(Values("OpGroupNonUniformFAdd", "OpGroupNonUniformFMul", + "OpGroupNonUniformFMin", "OpGroupNonUniformFMax"), + Values("%float"), Values(spv::Scope::Subgroup), + Values("ClusteredReduce match_res %u32_undef"), + Values("ClusterSize must be a constant instruction"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBooleanArithmeticGood, GroupNonUniform, + Combine(Values("OpGroupNonUniformLogicalAnd", "OpGroupNonUniformLogicalOr", + "OpGroupNonUniformLogicalXor"), + Values("%bool", "%v2bool"), Values(spv::Scope::Subgroup), + Values("Reduce match_res", "InclusiveScan match_res", + "ExclusiveScan match_res", + "ClusteredReduce match_res %u32_0"), + Values(""))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBooleanArithmeticBadResultType, GroupNonUniform, + Combine(Values("OpGroupNonUniformLogicalAnd", "OpGroupNonUniformLogicalOr", + "OpGroupNonUniformLogicalXor"), + Values("%u32", "%int", "%float", "%u32vec4", "%u32vec3", "%struct", + "%v4float", "%v4int"), + Values(spv::Scope::Subgroup), + Values("Reduce match_res", "InclusiveScan match_res", + "ExclusiveScan match_res", + "ClusteredReduce match_res %u32_0"), + Values("Result must be a boolean scalar or vector"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBooleanArithmeticBadValue, GroupNonUniform, + Combine(Values("OpGroupNonUniformLogicalAnd", "OpGroupNonUniformLogicalOr", + "OpGroupNonUniformLogicalXor"), + Values("%v2bool"), Values(spv::Scope::Subgroup), + Values("Reduce %true", "InclusiveScan %true", + "ExclusiveScan %false", "ClusteredReduce %false %u32_0"), + Values("The type of Value must match the Result type"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBooleanArithmeticMissingClusterSize, GroupNonUniform, + Combine( + Values("OpGroupNonUniformLogicalAnd", "OpGroupNonUniformLogicalOr", + "OpGroupNonUniformLogicalXor"), + Values("%bool"), Values(spv::Scope::Subgroup), + Values("ClusteredReduce match_res"), + Values( + "ClusterSize must be present when Operation is ClusteredReduce"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBooleanArithmeticBadClusterSizeType, GroupNonUniform, + Combine(Values("OpGroupNonUniformLogicalAnd", "OpGroupNonUniformLogicalOr", + "OpGroupNonUniformLogicalXor"), + Values("%bool"), Values(spv::Scope::Subgroup), + Values("ClusteredReduce match_res %true", + "ClusteredReduce match_res %false", + "ClusteredReduce match_res %int_0", + "ClusteredReduce match_res %float_0", + "ClusteredReduce match_res %u32vec4_null", + "ClusteredReduce match_res %u32vec3_null", + "ClusteredReduce match_res %v2bool_false", + "ClusteredReduce match_res %v4float_null", + "ClusteredReduce match_res %struct_null", + "ClusteredReduce match_res %v4int_null"), + Values("ClusterSize must be an unsigned integer scalar"))); + +INSTANTIATE_TEST_SUITE_P( + GroupNonUniformBooleanArithmeticClusterSizeNotConstant, GroupNonUniform, + Combine(Values("OpGroupNonUniformLogicalAnd", "OpGroupNonUniformLogicalOr", + "OpGroupNonUniformLogicalXor"), + Values("%bool"), Values(spv::Scope::Subgroup), + Values("ClusteredReduce match_res %u32_undef"), + Values("ClusterSize must be a constant instruction"))); + TEST_F(ValidateGroupNonUniform, VulkanGroupNonUniformBallotBitCountOperation) { std::string test = R"( OpCapability Shader @@ -327,6 +904,146 @@ OpFunctionEnd "be only: Reduce, InclusiveScan, or ExclusiveScan.")); } +TEST_F(ValidateGroupNonUniform, BroadcastNonConstantSpv1p4) { + const std::string text = R"( +OpCapability Shader +OpCapability GroupNonUniformBallot +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%subgroup = OpConstant %int 3 +%struct = OpTypeStruct %int +%ptr_struct = OpTypePointer StorageBuffer %struct +%ptr_int = OpTypePointer StorageBuffer %int +%var = OpVariable %ptr_struct StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = OpAccessChain %ptr_int %var %int_0 +%ld = OpLoad %int %gep +%broadcast = OpGroupNonUniformBroadcast %int %subgroup %int_0 %ld +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("Before SPIR-V 1.5, Id must be a constant instruction")); +} + +TEST_F(ValidateGroupNonUniform, BroadcastNonConstantSpv1p5) { + const std::string text = R"( +OpCapability Shader +OpCapability GroupNonUniformBallot +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%subgroup = OpConstant %int 3 +%struct = OpTypeStruct %int +%ptr_struct = OpTypePointer StorageBuffer %struct +%ptr_int = OpTypePointer StorageBuffer %int +%var = OpVariable %ptr_struct StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = OpAccessChain %ptr_int %var %int_0 +%ld = OpLoad %int %gep +%broadcast = OpGroupNonUniformBroadcast %int %subgroup %int_0 %ld +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_5); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); +} + +TEST_F(ValidateGroupNonUniform, QuadBroadcastNonConstantSpv1p4) { + const std::string text = R"( +OpCapability Shader +OpCapability GroupNonUniformQuad +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%subgroup = OpConstant %int 3 +%struct = OpTypeStruct %int +%ptr_struct = OpTypePointer StorageBuffer %struct +%ptr_int = OpTypePointer StorageBuffer %int +%var = OpVariable %ptr_struct StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = OpAccessChain %ptr_int %var %int_0 +%ld = OpLoad %int %gep +%broadcast = OpGroupNonUniformQuadBroadcast %int %subgroup %int_0 %ld +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("Before SPIR-V 1.5, Index must be a constant instruction")); +} + +TEST_F(ValidateGroupNonUniform, QuadBroadcastNonConstantSpv1p5) { + const std::string text = R"( +OpCapability Shader +OpCapability GroupNonUniformQuad +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%subgroup = OpConstant %int 3 +%struct = OpTypeStruct %int +%ptr_struct = OpTypePointer StorageBuffer %struct +%ptr_int = OpTypePointer StorageBuffer %int +%var = OpVariable %ptr_struct StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = OpAccessChain %ptr_int %var %int_0 +%ld = OpLoad %int %gep +%broadcast = OpGroupNonUniformQuadBroadcast %int %subgroup %int_0 %ld +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_5); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); +} + } // namespace } // namespace val } // namespace spvtools From abcd228d92df403364882bf07c4805a71e77283b Mon Sep 17 00:00:00 2001 From: David Neto Date: Tue, 11 Jul 2023 09:58:57 -0400 Subject: [PATCH 209/523] Update README to say Android NDK r25c is required (#5312) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7cec2af2fa..8c76895785 100644 --- a/README.md +++ b/README.md @@ -478,12 +478,12 @@ iterator debugging. ### Android ndk-build SPIR-V Tools supports building static libraries `libSPIRV-Tools.a` and -`libSPIRV-Tools-opt.a` for Android: +`libSPIRV-Tools-opt.a` for Android. Using the Android NDK r25c or later: ``` cd -export ANDROID_NDK=/path/to/your/ndk +export ANDROID_NDK=/path/to/your/ndk # NDK r25c or later mkdir build && cd build mkdir libs From 7ff331af660719912d48ac722ea971e06c22e5ab Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Wed, 12 Jul 2023 00:50:41 +0900 Subject: [PATCH 210/523] source: Give better message if using new Source Language (#5314) --- source/binary.cpp | 16 +++++++++++++++- test/binary_parse_test.cpp | 5 ++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/source/binary.cpp b/source/binary.cpp index 207d4a9b37..6d910f0f8a 100644 --- a/source/binary.cpp +++ b/source/binary.cpp @@ -626,7 +626,6 @@ spv_result_t Parser::parseOperand(size_t inst_offset, } break; case SPV_OPERAND_TYPE_CAPABILITY: - case SPV_OPERAND_TYPE_SOURCE_LANGUAGE: case SPV_OPERAND_TYPE_EXECUTION_MODEL: case SPV_OPERAND_TYPE_ADDRESSING_MODEL: case SPV_OPERAND_TYPE_MEMORY_MODEL: @@ -683,6 +682,21 @@ spv_result_t Parser::parseOperand(size_t inst_offset, spvPushOperandTypes(entry->operandTypes, expected_operands); } break; + case SPV_OPERAND_TYPE_SOURCE_LANGUAGE: { + spv_operand_desc entry; + if (grammar_.lookupOperand(type, word, &entry)) { + return diagnostic() + << "Invalid " << spvOperandTypeStr(parsed_operand.type) + << " operand: " << word + << ", if you are creating a new source language please use " + "value 0 " + "(Unknown) and when ready, add your source language to " + "SPRIV-Headers"; + } + // Prepare to accept operands to this operand, if needed. + spvPushOperandTypes(entry->operandTypes, expected_operands); + } break; + case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE: case SPV_OPERAND_TYPE_FUNCTION_CONTROL: case SPV_OPERAND_TYPE_LOOP_CONTROL: diff --git a/test/binary_parse_test.cpp b/test/binary_parse_test.cpp index 50710cd131..1a868dbae6 100644 --- a/test/binary_parse_test.cpp +++ b/test/binary_parse_test.cpp @@ -1154,7 +1154,10 @@ INSTANTIATE_TEST_SUITE_P( {"%2 = OpSpecConstantOp %1 !1000 %2", "Invalid OpSpecConstantOp opcode: 1000"}, {"OpCapability !9999", "Invalid capability operand: 9999"}, - {"OpSource !9999 100", "Invalid source language operand: 9999"}, + {"OpSource !9999 100", + "Invalid source language operand: 9999, if you are creating a new " + "source language please use value 0 (Unknown) and when ready, add " + "your source language to SPRIV-Headers"}, {"OpEntryPoint !9999", "Invalid execution model operand: 9999"}, {"OpMemoryModel !9999", "Invalid addressing model operand: 9999"}, {"OpMemoryModel Logical !9999", "Invalid memory model operand: 9999"}, From 3424b16c10dfa51b4b67fb4edf98d004154e5482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Wed, 12 Jul 2023 17:34:44 +0200 Subject: [PATCH 211/523] enumset: STL-ize container (#5311) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds forward iterator, and renames functions to it matches the std::unordered_set/std::set better. This goes against the SPIR-V coding style, but might be better in the long run, especially when this set is used along real STL sets. (Right now, they are not compatible, and requires 2 syntaxes). This container could in theory handle bidirectional iterator, but for now, only forward seemed required for our use-cases. Signed-off-by: Nathan Gauër --- source/assembly_grammar.cpp | 2 +- source/enum_set.h | 187 ++++++++++++++-- source/opt/feature_manager.cpp | 14 +- source/opt/feature_manager.h | 4 +- source/val/validate_capability.cpp | 2 +- source/val/validate_instruction.cpp | 13 +- source/val/validation_state.cpp | 8 +- source/val/validation_state.h | 4 +- test/enum_set_test.cpp | 329 +++++++++++++++++++++------- 9 files changed, 435 insertions(+), 128 deletions(-) diff --git a/source/assembly_grammar.cpp b/source/assembly_grammar.cpp index 56c7964d8c..7596b31c81 100644 --- a/source/assembly_grammar.cpp +++ b/source/assembly_grammar.cpp @@ -184,7 +184,7 @@ CapabilitySet AssemblyGrammar::filterCapsAgainstTargetEnv( // 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.Add(cap_array[i]); + cap_set.insert(cap_array[i]); } } return cap_set; diff --git a/source/enum_set.h b/source/enum_set.h index 9b0bb5b4e3..ef3d4d17b7 100644 --- a/source/enum_set.h +++ b/source/enum_set.h @@ -78,68 +78,195 @@ class EnumSet { static constexpr size_t kBucketSize = sizeof(BucketType) * 8ULL; public: + class Iterator { + public: + typedef Iterator self_type; + typedef T value_type; + typedef T& reference; + typedef T* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef size_t difference_type; + + Iterator(const Iterator& other) + : set_(other.set_), + bucketIndex_(other.bucketIndex_), + bucketOffset_(other.bucketOffset_) {} + + Iterator& operator++() { + do { + if (bucketIndex_ >= set_->buckets_.size()) { + bucketIndex_ = set_->buckets_.size(); + bucketOffset_ = 0; + break; + } + + if (bucketOffset_ + 1 == kBucketSize) { + bucketOffset_ = 0; + ++bucketIndex_; + } else { + ++bucketOffset_; + } + + } while (bucketIndex_ < set_->buckets_.size() && + !set_->HasEnumAt(bucketIndex_, bucketOffset_)); + return *this; + } + + Iterator operator++(int) { + Iterator old = *this; + operator++(); + return old; + } + + T operator*() const { + return GetValueFromBucket(set_->buckets_[bucketIndex_], bucketOffset_); + } + + bool operator!=(const Iterator& other) const { + return set_ != other.set_ || bucketOffset_ != other.bucketOffset_ || + bucketIndex_ != other.bucketIndex_; + } + + bool operator==(const Iterator& other) const { + return !(operator!=(other)); + } + + Iterator& operator=(const Iterator& other) { + set_ = other.set_; + bucketIndex_ = other.bucketIndex_; + bucketOffset_ = other.bucketOffset_; + return *this; + } + + private: + Iterator(const EnumSet* set, size_t bucketIndex, ElementType bucketOffset) + : set_(set), bucketIndex_(bucketIndex), bucketOffset_(bucketOffset) {} + + private: + const EnumSet* set_; + // Index of the bucket in the vector. + size_t bucketIndex_; + // Offset in bits in the current bucket. + ElementType bucketOffset_; + + friend class EnumSet; + }; + + // Required to allow the use of std::inserter. + using value_type = T; + using const_iterator = Iterator; + using iterator = Iterator; + + public: + iterator cbegin() const noexcept { + return iterator(this, /* bucketIndex= */ 0, /* bucketOffset= */ 0); + } + + iterator begin() const noexcept { return cbegin(); } + + iterator cend() const noexcept { + return iterator(this, buckets_.size(), /* bucketOffset= */ 0); + } + + iterator end() const noexcept { return cend(); } + // Creates an empty set. - EnumSet() : buckets_(0) {} + EnumSet() : buckets_(0), size_(0) {} // Creates a set and store `value` in it. - EnumSet(T value) : EnumSet() { Add(value); } + EnumSet(T value) : EnumSet() { insert(value); } // Creates a set and stores each `values` in it. EnumSet(std::initializer_list values) : EnumSet() { for (auto item : values) { - Add(item); + insert(item); } } // Creates a set, and insert `count` enum values pointed by `array` in it. EnumSet(ElementType count, const T* array) : EnumSet() { for (ElementType i = 0; i < count; i++) { - Add(array[i]); + insert(array[i]); } } // Copies the EnumSet `other` into a new EnumSet. - EnumSet(const EnumSet& other) : buckets_(other.buckets_) {} + EnumSet(const EnumSet& other) + : buckets_(other.buckets_), size_(other.size_) {} // Moves the EnumSet `other` into a new EnumSet. - EnumSet(EnumSet&& other) : buckets_(std::move(other.buckets_)) {} + EnumSet(EnumSet&& other) + : buckets_(std::move(other.buckets_)), size_(other.size_) {} // Deep-copies the EnumSet `other` into this EnumSet. EnumSet& operator=(const EnumSet& other) { buckets_ = other.buckets_; + size_ = other.size_; return *this; } - // Add the enum value `value` into the set. - // The set is unchanged if the value already exists. - void Add(T value) { + // Matches std::unordered_set::insert behavior. + std::pair insert(const T& value) { const size_t index = FindBucketForValue(value); + const ElementType offset = ComputeBucketOffset(value); + if (index >= buckets_.size() || buckets_[index].start != ComputeBucketStart(value)) { + size_ += 1; InsertBucketFor(index, value); - return; + return std::make_pair(Iterator(this, index, offset), true); } + auto& bucket = buckets_[index]; + const auto mask = ComputeMaskForValue(value); + if (bucket.data & mask) { + return std::make_pair(Iterator(this, index, offset), false); + } + + size_ += 1; bucket.data |= ComputeMaskForValue(value); + return std::make_pair(Iterator(this, index, offset), true); + } + + // Inserts `value` in the set if possible. + // Similar to `std::unordered_set::insert`, except the hint is ignored. + // Returns an iterator to the inserted element, or the element preventing + // insertion. + iterator insert(const_iterator, const T& value) { + return insert(value).first; } + // Inserts `value` in the set if possible. + // Similar to `std::unordered_set::insert`, except the hint is ignored. + // Returns an iterator to the inserted element, or the element preventing + // insertion. + iterator insert(const_iterator, T&& value) { return insert(value).first; } + // Removes the value `value` into the set. // The set is unchanged if the value is not in the set. - void Remove(T value) { + size_t erase(const T& value) { const size_t index = FindBucketForValue(value); if (index >= buckets_.size() || buckets_[index].start != ComputeBucketStart(value)) { - return; + return 0; } + auto& bucket = buckets_[index]; - bucket.data &= ~ComputeMaskForValue(value); + const auto mask = ComputeMaskForValue(value); + if (!(bucket.data & mask)) { + return 0; + } + + size_ -= 1; + bucket.data &= ~mask; if (bucket.data == 0) { buckets_.erase(buckets_.cbegin() + index); } + return 1; } // Returns true if `value` is present in the set. - bool Contains(T value) const { + bool contains(T value) const { const size_t index = FindBucketForValue(value); if (index >= buckets_.size() || buckets_[index].start != ComputeBucketStart(value)) { @@ -149,12 +276,16 @@ class EnumSet { return bucket.data & ComputeMaskForValue(value); } + // Returns the 1 if `value` is present in the set, `0` otherwise. + inline size_t count(T value) const { return contains(value) ? 1 : 0; } + // Calls `unaryFunction` once for each value in the set. // Values are sorted in increasing order using their numerical values. + // TODO(#5315): replace usages with either ranged-for or std::for_each. void ForEach(std::function unaryFunction) const { for (const auto& bucket : buckets_) { - for (uint8_t i = 0; i < kBucketSize; i++) { - if (bucket.data & (1ULL << i)) { + for (ElementType i = 0; i < kBucketSize; i++) { + if (bucket.data & (static_cast(1) << i)) { unaryFunction(GetValueFromBucket(bucket, i)); } } @@ -162,12 +293,14 @@ class EnumSet { } // Returns true if the set is holds no values. - bool IsEmpty() const { return buckets_.size() == 0; } + inline bool empty() const { return size_ == 0; } + + size_t size() const { return size_; } // Returns true if this set contains at least one value contained in `in_set`. // Note: If `in_set` is empty, this function returns true. bool HasAnyOf(const EnumSet& in_set) const { - if (in_set.IsEmpty()) { + if (in_set.empty()) { return true; } @@ -213,7 +346,7 @@ class EnumSet { } // Returns the index of the bit that corresponds to `value` in the bucket. - static constexpr inline size_t ComputeBucketOffset(T value) { + static constexpr inline ElementType ComputeBucketOffset(T value) { return static_cast(value) % kBucketSize; } @@ -225,7 +358,7 @@ class EnumSet { // Returns the `enum` stored in `bucket` at `offset`. // `offset` is the bit-offset in the bucket storage. static constexpr inline T GetValueFromBucket(const Bucket& bucket, - ElementType offset) { + BucketType offset) { return static_cast(static_cast(bucket.start) + offset); } @@ -277,8 +410,20 @@ class EnumSet { #endif } + // Returns true if the bucket at `bucketIndex/ stores the enum at + // `bucketOffset`, false otherwise. + bool HasEnumAt(size_t bucketIndex, BucketType bucketOffset) const { + assert(bucketIndex < buckets_.size()); + assert(bucketOffset < kBucketSize); + return buckets_[bucketIndex].data & (1ULL << bucketOffset); + } + // Returns true if `lhs` and `rhs` hold the exact same values. friend bool operator==(const EnumSet& lhs, const EnumSet& rhs) { + if (lhs.size_ != rhs.size_) { + return false; + } + if (lhs.buckets_.size() != rhs.buckets_.size()) { return false; } @@ -292,6 +437,8 @@ class EnumSet { // Storage for the buckets. std::vector buckets_; + // How many enums is this set storing. + size_t size_; }; // A set of spv::Capability. diff --git a/source/opt/feature_manager.cpp b/source/opt/feature_manager.cpp index 07e053b8eb..0dc50ffde5 100644 --- a/source/opt/feature_manager.cpp +++ b/source/opt/feature_manager.cpp @@ -40,19 +40,19 @@ void FeatureManager::AddExtension(Instruction* ext) { const std::string name = ext->GetInOperand(0u).AsString(); Extension extension; if (GetExtensionFromString(name.c_str(), &extension)) { - extensions_.Add(extension); + extensions_.insert(extension); } } void FeatureManager::RemoveExtension(Extension ext) { - if (!extensions_.Contains(ext)) return; - extensions_.Remove(ext); + if (!extensions_.contains(ext)) return; + extensions_.erase(ext); } void FeatureManager::AddCapability(spv::Capability cap) { - if (capabilities_.Contains(cap)) return; + if (capabilities_.contains(cap)) return; - capabilities_.Add(cap); + capabilities_.insert(cap); spv_operand_desc desc = {}; if (SPV_SUCCESS == grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, @@ -63,8 +63,8 @@ void FeatureManager::AddCapability(spv::Capability cap) { } void FeatureManager::RemoveCapability(spv::Capability cap) { - if (!capabilities_.Contains(cap)) return; - capabilities_.Remove(cap); + if (!capabilities_.contains(cap)) return; + capabilities_.erase(cap); } void FeatureManager::AddCapabilities(Module* module) { diff --git a/source/opt/feature_manager.h b/source/opt/feature_manager.h index b96988de47..666235270d 100644 --- a/source/opt/feature_manager.h +++ b/source/opt/feature_manager.h @@ -28,14 +28,14 @@ class FeatureManager { explicit FeatureManager(const AssemblyGrammar& grammar) : grammar_(grammar) {} // Returns true if |ext| is an enabled extension in the module. - bool HasExtension(Extension ext) const { return extensions_.Contains(ext); } + bool HasExtension(Extension ext) const { return extensions_.contains(ext); } // Removes the given |extension| from the current FeatureManager. void RemoveExtension(Extension extension); // Returns true if |cap| is an enabled capability in the module. bool HasCapability(spv::Capability cap) const { - return capabilities_.Contains(cap); + return capabilities_.contains(cap); } // Removes the given |capability| from the current FeatureManager. diff --git a/source/val/validate_capability.cpp b/source/val/validate_capability.cpp index 98dab4237f..81d2ad52d2 100644 --- a/source/val/validate_capability.cpp +++ b/source/val/validate_capability.cpp @@ -240,7 +240,7 @@ bool IsEnabledByExtension(ValidationState_t& _, uint32_t capability) { ExtensionSet operand_exts(operand_desc->numExtensions, operand_desc->extensions); - if (operand_exts.IsEmpty()) return false; + if (operand_exts.empty()) return false; return _.HasAnyOfExtensions(operand_exts); } diff --git a/source/val/validate_instruction.cpp b/source/val/validate_instruction.cpp index fde6e52e5b..47c74a7334 100644 --- a/source/val/validate_instruction.cpp +++ b/source/val/validate_instruction.cpp @@ -178,10 +178,11 @@ spv_result_t CheckRequiredCapabilities(ValidationState_t& state, // Vulkan API requires more capabilities on rounding mode. if (spvIsVulkanEnv(state.context()->target_env)) { - enabling_capabilities.Add(spv::Capability::StorageUniformBufferBlock16); - enabling_capabilities.Add(spv::Capability::StorageUniform16); - enabling_capabilities.Add(spv::Capability::StoragePushConstant16); - enabling_capabilities.Add(spv::Capability::StorageInputOutput16); + enabling_capabilities.insert( + spv::Capability::StorageUniformBufferBlock16); + enabling_capabilities.insert(spv::Capability::StorageUniform16); + enabling_capabilities.insert(spv::Capability::StoragePushConstant16); + enabling_capabilities.insert(spv::Capability::StorageInputOutput16); } } else { enabling_capabilities = state.grammar().filterCapsAgainstTargetEnv( @@ -195,7 +196,7 @@ spv_result_t CheckRequiredCapabilities(ValidationState_t& state, if (inst->opcode() != spv::Op::OpCapability) { const bool enabled_by_cap = state.HasAnyOfCapabilities(enabling_capabilities); - if (!enabling_capabilities.IsEmpty() && !enabled_by_cap) { + if (!enabling_capabilities.empty() && !enabled_by_cap) { return state.diag(SPV_ERROR_INVALID_CAPABILITY, inst) << "Operand " << which_operand << " of " << spvOpcodeString(inst->opcode()) @@ -303,7 +304,7 @@ spv_result_t VersionCheck(ValidationState_t& _, const Instruction* inst) { } ExtensionSet exts(inst_desc->numExtensions, inst_desc->extensions); - if (exts.IsEmpty()) { + if (exts.empty()) { // If no extensions can enable this instruction, then emit error // messages only concerning core SPIR-V versions if errors happen. if (min_version == ~0u) { diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 6071ce2067..b272d308aa 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -360,9 +360,9 @@ void ValidationState_t::RegisterCapability(spv::Capability cap) { // Avoid redundant work. Otherwise the recursion could induce work // quadrdatic in the capability dependency depth. (Ok, not much, but // it's something.) - if (module_capabilities_.Contains(cap)) return; + if (module_capabilities_.contains(cap)) return; - module_capabilities_.Add(cap); + module_capabilities_.insert(cap); spv_operand_desc desc; if (SPV_SUCCESS == grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, uint32_t(cap), &desc)) { @@ -419,9 +419,9 @@ void ValidationState_t::RegisterCapability(spv::Capability cap) { } void ValidationState_t::RegisterExtension(Extension ext) { - if (module_extensions_.Contains(ext)) return; + if (module_extensions_.contains(ext)) return; - module_extensions_.Add(ext); + module_extensions_.insert(ext); switch (ext) { case kSPV_AMD_gpu_shader_half_float: diff --git a/source/val/validation_state.h b/source/val/validation_state.h index 1a64a41c99..5ab6ac6021 100644 --- a/source/val/validation_state.h +++ b/source/val/validation_state.h @@ -317,7 +317,7 @@ class ValidationState_t { /// Returns true if the capability is enabled in the module. bool HasCapability(spv::Capability cap) const { - return module_capabilities_.Contains(cap); + return module_capabilities_.contains(cap); } /// Returns a reference to the set of capabilities in the module. @@ -328,7 +328,7 @@ class ValidationState_t { /// Returns true if the extension is enabled in the module. bool HasExtension(Extension ext) const { - return module_extensions_.Contains(ext); + return module_extensions_.contains(ext); } /// Returns true if any of the capabilities is enabled, or if |capabilities| diff --git a/test/enum_set_test.cpp b/test/enum_set_test.cpp index bf9e4432b0..d1ef36ae97 100644 --- a/test/enum_set_test.cpp +++ b/test/enum_set_test.cpp @@ -288,26 +288,26 @@ constexpr std::array kCapabilities{ TEST(EnumSet, IsEmpty1) { EnumSet set; - EXPECT_TRUE(set.IsEmpty()); - set.Add(TestEnum::ZERO); - EXPECT_FALSE(set.IsEmpty()); + EXPECT_TRUE(set.empty()); + set.insert(TestEnum::ZERO); + EXPECT_FALSE(set.empty()); } TEST(EnumSet, IsEmpty2) { EnumSet set; - EXPECT_TRUE(set.IsEmpty()); - set.Add(TestEnum::ONE_HUNDRED_FIFTY); - EXPECT_FALSE(set.IsEmpty()); + EXPECT_TRUE(set.empty()); + set.insert(TestEnum::ONE_HUNDRED_FIFTY); + EXPECT_FALSE(set.empty()); } TEST(EnumSet, IsEmpty3) { EnumSet set(TestEnum::FOUR); - EXPECT_FALSE(set.IsEmpty()); + EXPECT_FALSE(set.empty()); } TEST(EnumSet, IsEmpty4) { EnumSet set(TestEnum::THREE_HUNDRED); - EXPECT_FALSE(set.IsEmpty()); + EXPECT_FALSE(set.empty()); } TEST(EnumSetHasAnyOf, EmptySetEmptyQuery) { @@ -320,26 +320,26 @@ TEST(EnumSetHasAnyOf, EmptySetEmptyQuery) { TEST(EnumSetHasAnyOf, MaskSetEmptyQuery) { EnumSet set; const EnumSet empty; - set.Add(TestEnum::FIVE); - set.Add(TestEnum::EIGHT); + set.insert(TestEnum::FIVE); + set.insert(TestEnum::EIGHT); EXPECT_TRUE(set.HasAnyOf(empty)); } TEST(EnumSetHasAnyOf, OverflowSetEmptyQuery) { EnumSet set; const EnumSet empty; - set.Add(TestEnum::TWO_HUNDRED); - set.Add(TestEnum::THREE_HUNDRED); + set.insert(TestEnum::TWO_HUNDRED); + set.insert(TestEnum::THREE_HUNDRED); EXPECT_TRUE(set.HasAnyOf(empty)); } TEST(EnumSetHasAnyOf, EmptyQuery) { EnumSet set; const EnumSet empty; - set.Add(TestEnum::FIVE); - set.Add(TestEnum::EIGHT); - set.Add(TestEnum::TWO_HUNDRED); - set.Add(TestEnum::THREE_HUNDRED); + set.insert(TestEnum::FIVE); + set.insert(TestEnum::EIGHT); + set.insert(TestEnum::TWO_HUNDRED); + set.insert(TestEnum::THREE_HUNDRED); EXPECT_TRUE(set.HasAnyOf(empty)); } @@ -347,7 +347,7 @@ TEST(EnumSetHasAnyOf, EmptyQueryAlwaysTrue) { EnumSet set; const EnumSet empty; EXPECT_TRUE(set.HasAnyOf(empty)); - set.Add(TestEnum::FIVE); + set.insert(TestEnum::FIVE); EXPECT_TRUE(set.HasAnyOf(empty)); EXPECT_TRUE( @@ -356,23 +356,23 @@ TEST(EnumSetHasAnyOf, EmptyQueryAlwaysTrue) { TEST(EnumSetHasAnyOf, ReflexiveMask) { EnumSet set(TestEnum::THREE); - set.Add(TestEnum::TWENTY_FOUR); - set.Add(TestEnum::THIRTY); + set.insert(TestEnum::TWENTY_FOUR); + set.insert(TestEnum::THIRTY); EXPECT_TRUE(set.HasAnyOf(set)); } TEST(EnumSetHasAnyOf, ReflexiveOverflow) { EnumSet set(TestEnum::TWO_HUNDRED); - set.Add(TestEnum::TWO_HUNDRED); - set.Add(TestEnum::FOUR_HUNDRED); + set.insert(TestEnum::TWO_HUNDRED); + set.insert(TestEnum::FOUR_HUNDRED); EXPECT_TRUE(set.HasAnyOf(set)); } TEST(EnumSetHasAnyOf, Reflexive) { EnumSet set(TestEnum::THREE); - set.Add(TestEnum::TWENTY_FOUR); - set.Add(TestEnum::THREE_HUNDRED); - set.Add(TestEnum::FOUR_HUNDRED); + set.insert(TestEnum::TWENTY_FOUR); + set.insert(TestEnum::THREE_HUNDRED); + set.insert(TestEnum::FOUR_HUNDRED); EXPECT_TRUE(set.HasAnyOf(set)); } @@ -381,7 +381,7 @@ TEST(EnumSetHasAnyOf, EmptySetHasNone) { EnumSet items; for (uint32_t i = 0; i < 200; ++i) { TestEnum enumValue = static_cast(i); - items.Add(enumValue); + items.insert(enumValue); EXPECT_FALSE(set.HasAnyOf(items)); EXPECT_FALSE(set.HasAnyOf(EnumSet(enumValue))); } @@ -391,12 +391,12 @@ TEST(EnumSetHasAnyOf, MaskSetMaskQuery) { EnumSet set(TestEnum::ZERO); EnumSet items(TestEnum::ONE); EXPECT_FALSE(set.HasAnyOf(items)); - set.Add(TestEnum::TWO); - items.Add(TestEnum::THREE); + set.insert(TestEnum::TWO); + items.insert(TestEnum::THREE); EXPECT_FALSE(set.HasAnyOf(items)); - set.Add(TestEnum::THREE); + set.insert(TestEnum::THREE); EXPECT_TRUE(set.HasAnyOf(items)); - set.Add(TestEnum::FOUR); + set.insert(TestEnum::FOUR); EXPECT_TRUE(set.HasAnyOf(items)); } @@ -404,12 +404,12 @@ TEST(EnumSetHasAnyOf, OverflowSetOverflowQuery) { EnumSet set(TestEnum::ONE_HUNDRED); EnumSet items(TestEnum::TWO_HUNDRED); EXPECT_FALSE(set.HasAnyOf(items)); - set.Add(TestEnum::THREE_HUNDRED); - items.Add(TestEnum::FOUR_HUNDRED); + set.insert(TestEnum::THREE_HUNDRED); + items.insert(TestEnum::FOUR_HUNDRED); EXPECT_FALSE(set.HasAnyOf(items)); - set.Add(TestEnum::TWO_HUNDRED); + set.insert(TestEnum::TWO_HUNDRED); EXPECT_TRUE(set.HasAnyOf(items)); - set.Add(TestEnum::FIVE_HUNDRED); + set.insert(TestEnum::FIVE_HUNDRED); EXPECT_TRUE(set.HasAnyOf(items)); } @@ -417,13 +417,13 @@ TEST(EnumSetHasAnyOf, GeneralCase) { EnumSet set(TestEnum::ZERO); EnumSet items(TestEnum::ONE_HUNDRED); EXPECT_FALSE(set.HasAnyOf(items)); - set.Add(TestEnum::THREE_HUNDRED); - items.Add(TestEnum::FOUR); + set.insert(TestEnum::THREE_HUNDRED); + items.insert(TestEnum::FOUR); EXPECT_FALSE(set.HasAnyOf(items)); - set.Add(TestEnum::FIVE); - items.Add(TestEnum::FIVE_HUNDRED); + set.insert(TestEnum::FIVE); + items.insert(TestEnum::FIVE_HUNDRED); EXPECT_FALSE(set.HasAnyOf(items)); - set.Add(TestEnum::FIVE_HUNDRED); + set.insert(TestEnum::FIVE_HUNDRED); EXPECT_TRUE(set.HasAnyOf(items)); EXPECT_FALSE(set.HasAnyOf(EnumSet(TestEnum::TWENTY))); EXPECT_FALSE(set.HasAnyOf(EnumSet(TestEnum::SIX_HUNDRED))); @@ -435,24 +435,37 @@ TEST(EnumSetHasAnyOf, GeneralCase) { TEST(EnumSet, DefaultIsEmpty) { EnumSet set; for (uint32_t i = 0; i < 1000; ++i) { - EXPECT_FALSE(set.Contains(static_cast(i))); + EXPECT_FALSE(set.contains(static_cast(i))); } } -TEST(CapabilitySet, ForEachOrderIsEnumOrder) { - constexpr size_t kValueCount = 500; - std::vector orderedValues(kValueCount); - for (size_t i = 0; i < kValueCount; i++) { - orderedValues[i] = static_cast(i); +namespace { +std::vector enumerateValuesFromToWithStep(size_t start, size_t end, + size_t step) { + assert(end > start && "end > start"); + std::vector orderedValues; + for (size_t i = start; i < end; i += step) { + orderedValues.push_back(static_cast(i)); } - std::vector shuffledValues(orderedValues.cbegin(), orderedValues.cend()); + return orderedValues; +} + +EnumSet createSetUnorderedInsertion( + const std::vector& values) { + std::vector shuffledValues(values.cbegin(), values.cend()); std::mt19937 rng(0); std::shuffle(shuffledValues.begin(), shuffledValues.end(), rng); - EnumSet set; for (auto value : shuffledValues) { - set.Add(value); + set.insert(value); } + return set; +} +} // namespace + +TEST(CapabilitySet, ForEachOrderIsEnumOrder) { + auto orderedValues = enumerateValuesFromToWithStep(0, 500, /* step= */ 1); + auto set = createSetUnorderedInsertion(orderedValues); size_t index = 0; set.ForEach([&orderedValues, &index](auto value) { @@ -461,71 +474,217 @@ TEST(CapabilitySet, ForEachOrderIsEnumOrder) { }); } +TEST(CapabilitySet, RangeBasedLoopOrderIsEnumOrder) { + auto orderedValues = enumerateValuesFromToWithStep(0, 2, /* step= */ 1); + auto set = createSetUnorderedInsertion(orderedValues); + + size_t index = 0; + for (auto value : set) { + ASSERT_THAT(value, Eq(orderedValues[index])); + index++; + } +} + TEST(CapabilitySet, ConstructSingleMemberMatrix) { CapabilitySet s(spv::Capability::Matrix); - EXPECT_TRUE(s.Contains(spv::Capability::Matrix)); - EXPECT_FALSE(s.Contains(spv::Capability::Shader)); - EXPECT_FALSE(s.Contains(static_cast(1000))); + EXPECT_TRUE(s.contains(spv::Capability::Matrix)); + EXPECT_FALSE(s.contains(spv::Capability::Shader)); + EXPECT_FALSE(s.contains(static_cast(1000))); } TEST(CapabilitySet, ConstructSingleMemberMaxInMask) { CapabilitySet s(static_cast(63)); - EXPECT_FALSE(s.Contains(spv::Capability::Matrix)); - EXPECT_FALSE(s.Contains(spv::Capability::Shader)); - EXPECT_TRUE(s.Contains(static_cast(63))); - EXPECT_FALSE(s.Contains(static_cast(64))); - EXPECT_FALSE(s.Contains(static_cast(1000))); + EXPECT_FALSE(s.contains(spv::Capability::Matrix)); + EXPECT_FALSE(s.contains(spv::Capability::Shader)); + EXPECT_TRUE(s.contains(static_cast(63))); + EXPECT_FALSE(s.contains(static_cast(64))); + EXPECT_FALSE(s.contains(static_cast(1000))); } TEST(CapabilitySet, ConstructSingleMemberMinOverflow) { // Check the first one that forces overflow beyond the mask. CapabilitySet s(static_cast(64)); - EXPECT_FALSE(s.Contains(spv::Capability::Matrix)); - EXPECT_FALSE(s.Contains(spv::Capability::Shader)); - EXPECT_FALSE(s.Contains(static_cast(63))); - EXPECT_TRUE(s.Contains(static_cast(64))); - EXPECT_FALSE(s.Contains(static_cast(1000))); + EXPECT_FALSE(s.contains(spv::Capability::Matrix)); + EXPECT_FALSE(s.contains(spv::Capability::Shader)); + EXPECT_FALSE(s.contains(static_cast(63))); + EXPECT_TRUE(s.contains(static_cast(64))); + EXPECT_FALSE(s.contains(static_cast(1000))); } TEST(CapabilitySet, ConstructSingleMemberMaxOverflow) { // Check the max 32-bit signed int. CapabilitySet s(static_cast(0x7fffffffu)); - EXPECT_FALSE(s.Contains(spv::Capability::Matrix)); - EXPECT_FALSE(s.Contains(spv::Capability::Shader)); - EXPECT_FALSE(s.Contains(static_cast(1000))); - EXPECT_TRUE(s.Contains(static_cast(0x7fffffffu))); + EXPECT_FALSE(s.contains(spv::Capability::Matrix)); + EXPECT_FALSE(s.contains(spv::Capability::Shader)); + EXPECT_FALSE(s.contains(static_cast(1000))); + EXPECT_TRUE(s.contains(static_cast(0x7fffffffu))); } TEST(CapabilitySet, AddEnum) { CapabilitySet s(spv::Capability::Shader); - s.Add(spv::Capability::Kernel); - s.Add(static_cast(42)); - EXPECT_FALSE(s.Contains(spv::Capability::Matrix)); - EXPECT_TRUE(s.Contains(spv::Capability::Shader)); - EXPECT_TRUE(s.Contains(spv::Capability::Kernel)); - EXPECT_TRUE(s.Contains(static_cast(42))); + s.insert(spv::Capability::Kernel); + s.insert(static_cast(42)); + EXPECT_FALSE(s.contains(spv::Capability::Matrix)); + EXPECT_TRUE(s.contains(spv::Capability::Shader)); + EXPECT_TRUE(s.contains(spv::Capability::Kernel)); + EXPECT_TRUE(s.contains(static_cast(42))); +} + +TEST(CapabilitySet, InsertReturnsIteratorToInserted) { + CapabilitySet set; + + auto[it, inserted] = set.insert(spv::Capability::Kernel); + + EXPECT_TRUE(inserted); + EXPECT_EQ(*it, spv::Capability::Kernel); +} + +TEST(CapabilitySet, InsertReturnsIteratorToElementOnDoubleInsertion) { + CapabilitySet set; + EXPECT_FALSE(set.contains(spv::Capability::Shader)); + { + auto[it, inserted] = set.insert(spv::Capability::Shader); + EXPECT_TRUE(inserted); + EXPECT_EQ(*it, spv::Capability::Shader); + } + EXPECT_TRUE(set.contains(spv::Capability::Shader)); + + auto[it, inserted] = set.insert(spv::Capability::Shader); + + EXPECT_FALSE(inserted); + EXPECT_EQ(*it, spv::Capability::Shader); + EXPECT_TRUE(set.contains(spv::Capability::Shader)); +} + +TEST(CapabilitySet, InsertWithHintWorks) { + CapabilitySet set; + EXPECT_FALSE(set.contains(spv::Capability::Shader)); + + auto it = set.insert(set.begin(), spv::Capability::Shader); + + EXPECT_EQ(*it, spv::Capability::Shader); + EXPECT_TRUE(set.contains(spv::Capability::Shader)); +} + +TEST(CapabilitySet, InsertWithEndHintWorks) { + CapabilitySet set; + EXPECT_FALSE(set.contains(spv::Capability::Shader)); + + auto it = set.insert(set.end(), spv::Capability::Shader); + + EXPECT_EQ(*it, spv::Capability::Shader); + EXPECT_TRUE(set.contains(spv::Capability::Shader)); +} + +TEST(CapabilitySet, IteratorCanBeCopied) { + CapabilitySet set; + set.insert(spv::Capability::Matrix); + set.insert(spv::Capability::Shader); + set.insert(spv::Capability::Geometry); + set.insert(spv::Capability::Float64); + set.insert(spv::Capability::Float16); + + auto a = set.begin(); + ++a; + auto b = a; + + EXPECT_EQ(*b, *a); + ++b; + EXPECT_NE(*b, *a); + + ++a; + EXPECT_EQ(*b, *a); + + ++a; + EXPECT_NE(*b, *a); +} + +TEST(CapabilitySet, IteratorBeginToEndPostfix) { + auto orderedValues = enumerateValuesFromToWithStep(0, 100, /* step= */ 1); + auto set = createSetUnorderedInsertion(orderedValues); + + size_t index = 0; + for (auto it = set.cbegin(); it != set.cend(); it++, index++) { + EXPECT_EQ(*it, orderedValues[index]); + } +} + +TEST(CapabilitySet, IteratorBeginToEndPrefix) { + auto orderedValues = enumerateValuesFromToWithStep(0, 100, /* step= */ 1); + auto set = createSetUnorderedInsertion(orderedValues); + + size_t index = 0; + for (auto it = set.cbegin(); it != set.cend(); ++it, index++) { + EXPECT_EQ(*it, orderedValues[index]); + } +} + +TEST(CapabilitySet, IteratorBeginToEndPrefixStep) { + auto orderedValues = enumerateValuesFromToWithStep(0, 100, /* step= */ 8); + auto set = createSetUnorderedInsertion(orderedValues); + + size_t index = 0; + for (auto it = set.cbegin(); it != set.cend(); ++it, index++) { + ASSERT_EQ(*it, orderedValues[index]); + } +} + +TEST(CapabilitySet, CompatibleWithSTLFind) { + CapabilitySet set; + set.insert(spv::Capability::Matrix); + set.insert(spv::Capability::Shader); + set.insert(spv::Capability::Geometry); + set.insert(spv::Capability::Tessellation); + set.insert(spv::Capability::Addresses); + set.insert(spv::Capability::Linkage); + set.insert(spv::Capability::Kernel); + set.insert(spv::Capability::Vector16); + set.insert(spv::Capability::Float16Buffer); + set.insert(spv::Capability::Float64); + + { + auto it = std::find(set.cbegin(), set.cend(), spv::Capability::Vector16); + ASSERT_NE(it, set.end()); + ASSERT_EQ(*it, spv::Capability::Vector16); + } + + { + auto it = std::find(set.cbegin(), set.cend(), spv::Capability::Float16); + ASSERT_EQ(it, set.end()); + } +} + +TEST(CapabilitySet, CompatibleWithSTLForEach) { + auto orderedValues = enumerateValuesFromToWithStep(0, 100, /* step= */ 15); + auto set = createSetUnorderedInsertion(orderedValues); + + size_t index = 0; + std::for_each(set.cbegin(), set.cend(), [&](auto item) { + ASSERT_EQ(item, orderedValues[index]); + index++; + }); } TEST(CapabilitySet, InitializerListEmpty) { CapabilitySet s{}; for (uint32_t i = 0; i < 1000; i++) { - EXPECT_FALSE(s.Contains(static_cast(i))); + EXPECT_FALSE(s.contains(static_cast(i))); } } TEST(CapabilitySet, LargeSetHasInsertedElements) { CapabilitySet set; for (auto c : kCapabilities) { - EXPECT_FALSE(set.Contains(c)); + EXPECT_FALSE(set.contains(c)); } for (auto c : kCapabilities) { - set.Add(c); - EXPECT_TRUE(set.Contains(c)); + set.insert(c); + EXPECT_TRUE(set.contains(c)); } for (auto c : kCapabilities) { - EXPECT_TRUE(set.Contains(c)); + EXPECT_TRUE(set.contains(c)); } } @@ -536,16 +695,16 @@ TEST(CapabilitySet, LargeSetHasUnsortedInsertedElements) { std::shuffle(shuffledCapabilities.begin(), shuffledCapabilities.end(), rng); CapabilitySet set; for (auto c : shuffledCapabilities) { - EXPECT_FALSE(set.Contains(c)); + EXPECT_FALSE(set.contains(c)); } for (auto c : shuffledCapabilities) { - set.Add(c); - EXPECT_TRUE(set.Contains(c)); + set.insert(c); + EXPECT_TRUE(set.contains(c)); } for (auto c : shuffledCapabilities) { - EXPECT_TRUE(set.Contains(c)); + EXPECT_TRUE(set.contains(c)); } } @@ -556,16 +715,16 @@ TEST(CapabilitySet, LargeSetHasUnsortedRemovedElement) { std::shuffle(shuffledCapabilities.begin(), shuffledCapabilities.end(), rng); CapabilitySet set; for (auto c : shuffledCapabilities) { - set.Add(c); - EXPECT_TRUE(set.Contains(c)); + set.insert(c); + EXPECT_TRUE(set.contains(c)); } for (auto c : kCapabilities) { - set.Remove(c); + set.erase(c); } for (auto c : shuffledCapabilities) { - EXPECT_FALSE(set.Contains(c)); + EXPECT_FALSE(set.contains(c)); } } @@ -630,8 +789,8 @@ using BoundaryTestWithParam = ::testing::TestWithParam; TEST_P(BoundaryTestWithParam, InsertedContains) { CapabilitySet set; - set.Add(GetParam()); - EXPECT_TRUE(set.Contains(GetParam())); + set.insert(GetParam()); + EXPECT_TRUE(set.contains(GetParam())); } INSTANTIATE_TEST_SUITE_P( From ee50fa7d85017c151e97819e95a1002168179878 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 12 Jul 2023 16:02:00 +0000 Subject: [PATCH 212/523] Roll external/googletest/ 4a1a299b2..cc366710b (1 commit) (#5317) https://github.com/google/googletest/compare/4a1a299b206b...cc366710bbf4 $ git log 4a1a299b2..cc366710b --date=short --no-merges --format='%ad %ae %s' 2023-07-03 steve Use template type FloatType in the cast. 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 b3623c72ba..5ae0459ce0 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '4a1a299b206ba250a4318f74938ea67c75c3c0c9', + 'googletest_revision': 'cc366710bbf40a9816d47c35802d06dbaccb8792', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From 9266197c37ddbcdd88b8a4d6cfc237e9d5b1522f Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Wed, 12 Jul 2023 15:12:26 -0600 Subject: [PATCH 213/523] instrument: Cast gl_VertexIndex and InstanceIndex to uint (#5319) This avoids errors like this from instrumenting vertex shaders: error: 165: Expected Constituents to be scalars or vectors of the same type as Result Type components %195 = OpCompositeConstruct %v4uint %uint_0 %191 %194 %uint_0 --- source/opt/instrument_pass.cpp | 5 +- test/opt/inst_bindless_check_test.cpp | 134 ++++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 2 deletions(-) diff --git a/source/opt/instrument_pass.cpp b/source/opt/instrument_pass.cpp index 6f800c3784..bd01ee64f5 100644 --- a/source/opt/instrument_pass.cpp +++ b/source/opt/instrument_pass.cpp @@ -233,11 +233,12 @@ uint32_t InstrumentPass::GenStageInfo(uint32_t stage_idx, uint32_t load_id = GenVarLoad( context()->GetBuiltinInputVarId(uint32_t(spv::BuiltIn::VertexIndex)), builder); - ids[1] = load_id; + ids[1] = GenUintCastCode(load_id, builder); + load_id = GenVarLoad(context()->GetBuiltinInputVarId( uint32_t(spv::BuiltIn::InstanceIndex)), builder); - ids[2] = load_id; + ids[2] = GenUintCastCode(load_id, builder); } break; case spv::ExecutionModel::GLCompute: case spv::ExecutionModel::TaskNV: diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp index c138d5a2e4..d18a33046e 100644 --- a/test/opt/inst_bindless_check_test.cpp +++ b/test/opt/inst_bindless_check_test.cpp @@ -5224,6 +5224,140 @@ OpFunctionEnd)" SinglePassRunAndMatch(text, true, 7u, 23u); } +TEST_F(InstBindlessTest, VertexIndexOOB) { + // #version 450 + // layout(std140, binding = 0) uniform foo { uint tex_index[1]; } + // uniform_index_buffer; layout(location = 0) out flat uint index; vec2 + // vertices[3]; void main() { + // vertices[0] = vec2(-1.0, -1.0); + // vertices[1] = vec2( 1.0, -1.0); + // vertices[2] = vec2( 0.0, 1.0); + // gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0, 1.0); + // index = uniform_index_buffer.tex_index[0]; + // } + // clang-format off + const std::string text = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Vertex %main "main" %vertices %_ %gl_VertexIndex %index %uniform_index_buffer +OpSource GLSL 450 +OpName %main "main" +OpName %vertices "vertices" +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 %_ "" +OpName %gl_VertexIndex "gl_VertexIndex" +OpName %index "index" +OpName %foo "foo" +OpMemberName %foo 0 "tex_index" +OpName %uniform_index_buffer "uniform_index_buffer" +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 +OpDecorate %gl_VertexIndex BuiltIn VertexIndex +OpDecorate %index Flat +OpDecorate %index Location 0 +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 +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v2float = OpTypeVector %float 2 +%uint = OpTypeInt 32 0 +%uint_3 = OpConstant %uint 3 +%_arr_v2float_uint_3 = OpTypeArray %v2float %uint_3 +%_ptr_Private__arr_v2float_uint_3 = OpTypePointer Private %_arr_v2float_uint_3 +%vertices = OpVariable %_ptr_Private__arr_v2float_uint_3 Private +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%float_n1 = OpConstant %float -1 +%16 = OpConstantComposite %v2float %float_n1 %float_n1 +%_ptr_Private_v2float = OpTypePointer Private %v2float +%int_1 = OpConstant %int 1 +%float_1 = OpConstant %float 1 +%21 = OpConstantComposite %v2float %float_1 %float_n1 +%int_2 = OpConstant %int 2 +%float_0 = OpConstant %float 0 +%25 = OpConstantComposite %v2float %float_0 %float_1 +%v4float = OpTypeVector %float 4 +%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 +%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex +%_ = OpVariable %_ptr_Output_gl_PerVertex Output +%_ptr_Input_int = OpTypePointer Input %int +%gl_VertexIndex = OpVariable %_ptr_Input_int Input +%int_3 = OpConstant %int 3 +%_ptr_Output_v4float = OpTypePointer Output %v4float +%_ptr_Output_uint = OpTypePointer Output %uint +%index = OpVariable %_ptr_Output_uint Output +%_arr_uint_uint_1 = OpTypeArray %uint %uint_1 +%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 +%5 = OpLabel +%18 = OpAccessChain %_ptr_Private_v2float %vertices %int_0 +OpStore %18 %16 +%22 = OpAccessChain %_ptr_Private_v2float %vertices %int_1 +OpStore %22 %21 +%26 = OpAccessChain %_ptr_Private_v2float %vertices %int_2 +OpStore %26 %25 +%35 = OpLoad %int %gl_VertexIndex +%37 = OpSMod %int %35 %int_3 +%38 = OpAccessChain %_ptr_Private_v2float %vertices %37 +%39 = OpLoad %v2float %38 +%40 = OpCompositeExtract %float %39 0 +%41 = OpCompositeExtract %float %39 1 +%42 = OpCompositeConstruct %v4float %40 %41 %float_0 %float_1 +%44 = OpAccessChain %_ptr_Output_v4float %_ %int_0 +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]] +OpStore %index %53 +; CHECK-NOT: OpStore %index %53 +OpReturn +;CHECK: OpReturn +OpFunctionEnd)" + + kStreamWrite6 + kCheckDesc; + // clang-format on + + SetTargetEnv(SPV_ENV_VULKAN_1_2); + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndMatch(text, true, 7u, 23u); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Compute shader From 9ab811a12525ed741eb42d7b22e2153f79cad6a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 13 Jul 2023 11:16:54 +0200 Subject: [PATCH 214/523] NFC: fix missing comments on functions (#5318) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nathan Gauër --- source/enum_set.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/enum_set.h b/source/enum_set.h index ef3d4d17b7..107e93dc6f 100644 --- a/source/enum_set.h +++ b/source/enum_set.h @@ -243,7 +243,8 @@ class EnumSet { iterator insert(const_iterator, T&& value) { return insert(value).first; } // Removes the value `value` into the set. - // The set is unchanged if the value is not in the set. + // Similar to `std::unordered_set::erase`. + // Returns the number of erased elements. size_t erase(const T& value) { const size_t index = FindBucketForValue(value); if (index >= buckets_.size() || @@ -295,6 +296,7 @@ class EnumSet { // Returns true if the set is holds no values. inline bool empty() const { return size_ == 0; } + // Returns the number of enums stored in this set. size_t size() const { return size_; } // Returns true if this set contains at least one value contained in `in_set`. From 5b4fb072ebbfd04292fd209ddda1e60bcce0f551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 13 Jul 2023 15:55:24 +0200 Subject: [PATCH 215/523] enumset: fix bug in the new iterator class (#5321) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The iterator class was initialized by setting the offset and bucket to 0. Big oversight: what if the first enum is not valid? Then `*iterator->begin()` would return the wrong value. Because the first capacity is Matrix, this bug was not visible by any SPIRV test. And this specific case wasn't tested correctly in the new enumset tests. Signed-off-by: Nathan Gauër --------- Signed-off-by: Nathan Gauër --- source/enum_set.h | 23 ++++++++++++++---- test/enum_set_test.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/source/enum_set.h b/source/enum_set.h index 107e93dc6f..b2d5a5bb00 100644 --- a/source/enum_set.h +++ b/source/enum_set.h @@ -119,6 +119,8 @@ class EnumSet { } T operator*() const { + assert(set_->HasEnumAt(bucketIndex_, bucketOffset_) && + "operator*() called on an invalid iterator."); return GetValueFromBucket(set_->buckets_[bucketIndex_], bucketOffset_); } @@ -143,11 +145,11 @@ class EnumSet { : set_(set), bucketIndex_(bucketIndex), bucketOffset_(bucketOffset) {} private: - const EnumSet* set_; + const EnumSet* set_ = nullptr; // Index of the bucket in the vector. - size_t bucketIndex_; + size_t bucketIndex_ = 0; // Offset in bits in the current bucket. - ElementType bucketOffset_; + ElementType bucketOffset_ = 0; friend class EnumSet; }; @@ -159,7 +161,18 @@ class EnumSet { public: iterator cbegin() const noexcept { - return iterator(this, /* bucketIndex= */ 0, /* bucketOffset= */ 0); + auto it = iterator(this, /* bucketIndex= */ 0, /* bucketOffset= */ 0); + if (buckets_.size() == 0) { + return it; + } + + // The iterator has the logic to find the next valid bit. If the value 0 + // is not stored, use it to find the next valid bit. + if (!HasEnumAt(it.bucketIndex_, it.bucketOffset_)) { + ++it; + } + + return it; } iterator begin() const noexcept { return cbegin(); } @@ -440,7 +453,7 @@ class EnumSet { // Storage for the buckets. std::vector buckets_; // How many enums is this set storing. - size_t size_; + size_t size_ = 0; }; // A set of spv::Capability. diff --git a/test/enum_set_test.cpp b/test/enum_set_test.cpp index d1ef36ae97..f23da7f6e1 100644 --- a/test/enum_set_test.cpp +++ b/test/enum_set_test.cpp @@ -629,6 +629,61 @@ TEST(CapabilitySet, IteratorBeginToEndPrefixStep) { } } +TEST(CapabilitySet, IteratorBeginOnEmpty) { + CapabilitySet set; + + auto begin = set.begin(); + auto end = set.end(); + ASSERT_EQ(begin, end); +} + +TEST(CapabilitySet, IteratorBeginOnSingleNonZeroValue) { + CapabilitySet set; + set.insert(spv::Capability::Shader); + + auto begin = set.begin(); + auto end = set.end(); + + ASSERT_NE(begin, end); + ASSERT_EQ(*begin, spv::Capability::Shader); +} + +TEST(CapabilitySet, IteratorForLoopNonZeroValue) { + CapabilitySet set; + set.insert(spv::Capability::Shader); + set.insert(spv::Capability::Tessellation); + + auto begin = set.begin(); + auto end = set.end(); + + ASSERT_NE(begin, end); + ASSERT_EQ(*begin, spv::Capability::Shader); + + begin++; + ASSERT_NE(begin, end); + ASSERT_EQ(*begin, spv::Capability::Tessellation); + + begin++; + ASSERT_EQ(begin, end); +} + +TEST(CapabilitySet, IteratorPastEnd) { + CapabilitySet set; + set.insert(spv::Capability::Shader); + + auto begin = set.begin(); + auto end = set.end(); + + ASSERT_NE(begin, end); + ASSERT_EQ(*begin, spv::Capability::Shader); + + begin++; + ASSERT_EQ(begin, end); + + begin++; + ASSERT_EQ(begin, end); +} + TEST(CapabilitySet, CompatibleWithSTLFind) { CapabilitySet set; set.insert(spv::Capability::Matrix); From d6b9389f6de87fe190e4eb304de45dfecf8d3c6f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 13 Jul 2023 15:14:12 +0000 Subject: [PATCH 216/523] Roll external/spirv-headers/ d0006a393..f1ba373ef (2 commits) (#5320) https://github.com/KhronosGroup/SPIRV-Headers/compare/d0006a3938d7...f1ba373ef037 $ git log d0006a393..f1ba373ef --date=short --no-merges --format='%ad %ae %s' 2023-07-06 alanbaker Add WGSL source language 2023-06-16 joycebrum Create SECURITY.md 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 5ae0459ce0..89b51ca560 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': 'e66463312e1d30d427bbde6c40e7fd627dcfb82e', - 'spirv_headers_revision': 'd0006a3938d7acedffb26ab517fe3e95b5288cc6', + 'spirv_headers_revision': 'f1ba373ef03752ee9f6f2b898bea1213f93e1ef2', } deps = { From 29431859f575633790365a0ac841b27440274f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 13 Jul 2023 20:40:47 +0200 Subject: [PATCH 217/523] NFC: replace EnumSet::ForEach with range-based-for (#5322) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EnumSet now supports iterators, meaning we can remove the custom ForEach. Signed-off-by: Nathan Gauër --- source/enum_set.h | 13 ------------- source/extensions.cpp | 5 +++-- source/opt/feature_manager.cpp | 6 ++++-- source/opt/ir_context.cpp | 6 +++--- source/val/validate_instruction.cpp | 8 ++++---- source/val/validation_state.cpp | 6 ++++-- test/enum_set_test.cpp | 11 ----------- test/unit_spirv.h | 5 ++--- 8 files changed, 20 insertions(+), 40 deletions(-) diff --git a/source/enum_set.h b/source/enum_set.h index b2d5a5bb00..75320679b4 100644 --- a/source/enum_set.h +++ b/source/enum_set.h @@ -293,19 +293,6 @@ class EnumSet { // Returns the 1 if `value` is present in the set, `0` otherwise. inline size_t count(T value) const { return contains(value) ? 1 : 0; } - // Calls `unaryFunction` once for each value in the set. - // Values are sorted in increasing order using their numerical values. - // TODO(#5315): replace usages with either ranged-for or std::for_each. - void ForEach(std::function unaryFunction) const { - for (const auto& bucket : buckets_) { - for (ElementType i = 0; i < kBucketSize; i++) { - if (bucket.data & (static_cast(1) << i)) { - unaryFunction(GetValueFromBucket(bucket, i)); - } - } - } - } - // Returns true if the set is holds no values. inline bool empty() const { return size_ == 0; } diff --git a/source/extensions.cpp b/source/extensions.cpp index ebf6bec061..ac987fcc0e 100644 --- a/source/extensions.cpp +++ b/source/extensions.cpp @@ -40,8 +40,9 @@ std::string GetExtensionString(const spv_parsed_instruction_t* inst) { std::string ExtensionSetToString(const ExtensionSet& extensions) { std::stringstream ss; - extensions.ForEach( - [&ss](Extension ext) { ss << ExtensionToString(ext) << " "; }); + for (auto extension : extensions) { + ss << ExtensionToString(extension) << " "; + } return ss.str(); } diff --git a/source/opt/feature_manager.cpp b/source/opt/feature_manager.cpp index 0dc50ffde5..51883706aa 100644 --- a/source/opt/feature_manager.cpp +++ b/source/opt/feature_manager.cpp @@ -57,8 +57,10 @@ void FeatureManager::AddCapability(spv::Capability cap) { spv_operand_desc desc = {}; if (SPV_SUCCESS == grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, uint32_t(cap), &desc)) { - CapabilitySet(desc->numCapabilities, desc->capabilities) - .ForEach([this](spv::Capability c) { AddCapability(c); }); + for (auto capability : + CapabilitySet(desc->numCapabilities, desc->capabilities)) { + AddCapability(capability); + } } } diff --git a/source/opt/ir_context.cpp b/source/opt/ir_context.cpp index 26501c2cce..2c3ee692d7 100644 --- a/source/opt/ir_context.cpp +++ b/source/opt/ir_context.cpp @@ -718,9 +718,9 @@ void IRContext::AddCombinatorsForExtension(Instruction* extension) { } void IRContext::InitializeCombinators() { - get_feature_mgr()->GetCapabilities()->ForEach([this](spv::Capability cap) { - AddCombinatorsForCapability(uint32_t(cap)); - }); + for (auto capability : *get_feature_mgr()->GetCapabilities()) { + AddCombinatorsForCapability(uint32_t(capability)); + } for (auto& extension : module()->ext_inst_imports()) { AddCombinatorsForExtension(&extension); diff --git a/source/val/validate_instruction.cpp b/source/val/validate_instruction.cpp index 47c74a7334..8710ffa44b 100644 --- a/source/val/validate_instruction.cpp +++ b/source/val/validate_instruction.cpp @@ -38,14 +38,14 @@ namespace { std::string ToString(const CapabilitySet& capabilities, const AssemblyGrammar& grammar) { std::stringstream ss; - capabilities.ForEach([&grammar, &ss](spv::Capability cap) { + for (auto capability : capabilities) { spv_operand_desc desc; if (SPV_SUCCESS == grammar.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, - uint32_t(cap), &desc)) + uint32_t(capability), &desc)) ss << desc->name << " "; else - ss << uint32_t(cap) << " "; - }); + ss << uint32_t(capability) << " "; + } return ss.str(); } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index b272d308aa..974a3c31b8 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -366,8 +366,10 @@ void ValidationState_t::RegisterCapability(spv::Capability cap) { spv_operand_desc desc; if (SPV_SUCCESS == grammar_.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, uint32_t(cap), &desc)) { - CapabilitySet(desc->numCapabilities, desc->capabilities) - .ForEach([this](spv::Capability c) { RegisterCapability(c); }); + for (auto capability : + CapabilitySet(desc->numCapabilities, desc->capabilities)) { + RegisterCapability(capability); + } } switch (cap) { diff --git a/test/enum_set_test.cpp b/test/enum_set_test.cpp index f23da7f6e1..a561dbfc86 100644 --- a/test/enum_set_test.cpp +++ b/test/enum_set_test.cpp @@ -463,17 +463,6 @@ EnumSet createSetUnorderedInsertion( } } // namespace -TEST(CapabilitySet, ForEachOrderIsEnumOrder) { - auto orderedValues = enumerateValuesFromToWithStep(0, 500, /* step= */ 1); - auto set = createSetUnorderedInsertion(orderedValues); - - size_t index = 0; - set.ForEach([&orderedValues, &index](auto value) { - EXPECT_THAT(value, Eq(orderedValues[index])); - index++; - }); -} - TEST(CapabilitySet, RangeBasedLoopOrderIsEnumOrder) { auto orderedValues = enumerateValuesFromToWithStep(0, 2, /* step= */ 1); auto set = createSetUnorderedInsertion(orderedValues); diff --git a/test/unit_spirv.h b/test/unit_spirv.h index bc9857e69f..9e7074cb33 100644 --- a/test/unit_spirv.h +++ b/test/unit_spirv.h @@ -202,9 +202,8 @@ inline std::vector AllTargetEnvironments() { // Returns the capabilities in a CapabilitySet as an ordered vector. inline std::vector ElementsIn( const spvtools::CapabilitySet& capabilities) { - std::vector result; - capabilities.ForEach([&result](spv::Capability c) { result.push_back(c); }); - return result; + return std::vector(capabilities.cbegin(), + capabilities.cend()); } } // namespace spvtest From 85a4482131b50984692843f16fc907570516d010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 17 Jul 2023 17:15:08 +0200 Subject: [PATCH 218/523] NFC: makes the FeatureManager immutable for users (#5329) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * NFC: makes the FeatureManager immutable for users The FeatureManager contains some internal state, like a set of capabilities and extensions. Those are derived from the module. Before this commit, the FeatureManager exposed Remove* functions which could unsync the reported extensions/capabilities from the truth: the module. The only valid usecase to remove items directly from the FeatureManager is by the context itself, when an instruction is killed: instead of running the whole an analysis, we remove the single outdated item. The was 2 users who mutated its state: - one to invalidate the manager. Moved to call a reset function. - one who removed an extension from the feature manager after removing it from the module. This logic has been moved to the context, who now handles the extension removal itself. Signed-off-by: Nathan Gauër * clang-format * add RemoveCapability since the fuzztests are using it * add tests --------- Signed-off-by: Nathan Gauër --- source/opt/feature_manager.h | 41 +-- source/opt/graphics_robust_access_pass.cpp | 6 +- source/opt/inst_debug_printf_pass.cpp | 10 +- source/opt/ir_context.cpp | 52 ++++ source/opt/ir_context.h | 24 +- source/opt/module.h | 1 + .../transformation_add_opphi_synonym_test.cpp | 6 +- .../transformation_add_type_float_test.cpp | 2 +- .../fuzz/transformation_add_type_int_test.cpp | 4 +- test/opt/ir_context_test.cpp | 248 ++++++++++++++++++ 10 files changed, 353 insertions(+), 41 deletions(-) diff --git a/source/opt/feature_manager.h b/source/opt/feature_manager.h index 666235270d..59735edb4a 100644 --- a/source/opt/feature_manager.h +++ b/source/opt/feature_manager.h @@ -25,26 +25,14 @@ namespace opt { // Tracks features enabled by a module. The IRContext has a FeatureManager. class FeatureManager { public: - explicit FeatureManager(const AssemblyGrammar& grammar) : grammar_(grammar) {} - // Returns true if |ext| is an enabled extension in the module. bool HasExtension(Extension ext) const { return extensions_.contains(ext); } - // Removes the given |extension| from the current FeatureManager. - void RemoveExtension(Extension extension); - // Returns true if |cap| is an enabled capability in the module. bool HasCapability(spv::Capability cap) const { return capabilities_.contains(cap); } - // Removes the given |capability| from the current FeatureManager. - void RemoveCapability(spv::Capability capability); - - // Analyzes |module| and records enabled extensions and capabilities. - void Analyze(Module* module); - - CapabilitySet* GetCapabilities() { return &capabilities_; } const CapabilitySet* GetCapabilities() const { return &capabilities_; } uint32_t GetExtInstImportId_GLSLstd450() const { @@ -64,23 +52,36 @@ class FeatureManager { return !(a == b); } - // Adds the given |capability| and all implied capabilities into the current - // FeatureManager. - void AddCapability(spv::Capability capability); + private: + explicit FeatureManager(const AssemblyGrammar& grammar) : grammar_(grammar) {} + + // Analyzes |module| and records enabled extensions and capabilities. + void Analyze(Module* module); // Add the extension |ext| to the feature manager. void AddExtension(Instruction* ext); - // Analyzes |module| and records imported external instruction sets. - void AddExtInstImportIds(Module* module); - - private: // Analyzes |module| and records enabled extensions. void AddExtensions(Module* module); + // Removes the given |extension| from the current FeatureManager. + void RemoveExtension(Extension extension); + + // Adds the given |capability| and all implied capabilities into the current + // FeatureManager. + void AddCapability(spv::Capability capability); + // Analyzes |module| and records enabled capabilities. void AddCapabilities(Module* module); + // Removes the given |capability| from the current FeatureManager. + void RemoveCapability(spv::Capability capability); + + CapabilitySet* GetCapabilities() { return &capabilities_; } + + // Analyzes |module| and records imported external instruction sets. + void AddExtInstImportIds(Module* module); + // Auxiliary object for querying SPIR-V grammar facts. const AssemblyGrammar& grammar_; @@ -100,6 +101,8 @@ class FeatureManager { // Common NonSemanticShader100DebugInfo external instruction import ids, // cached for performance. uint32_t extinst_importid_Shader100DebugInfo_ = 0; + + friend class IRContext; }; } // namespace opt diff --git a/source/opt/graphics_robust_access_pass.cpp b/source/opt/graphics_robust_access_pass.cpp index 8fff8a032b..e765c39760 100644 --- a/source/opt/graphics_robust_access_pass.cpp +++ b/source/opt/graphics_robust_access_pass.cpp @@ -573,9 +573,9 @@ uint32_t GraphicsRobustAccessPass::GetGlslInsts() { context()->module()->AddExtInstImport(std::move(import_inst)); module_status_.modified = true; context()->AnalyzeDefUse(inst); - // Reanalyze the feature list, since we added an extended instruction - // set improt. - context()->get_feature_mgr()->Analyze(context()->module()); + // Invalidates the feature manager, since we added an extended instruction + // set import. + context()->ResetFeatureManager(); } } return module_status_.glsl_insts_id; diff --git a/source/opt/inst_debug_printf_pass.cpp b/source/opt/inst_debug_printf_pass.cpp index 49347d1745..f7c227455e 100644 --- a/source/opt/inst_debug_printf_pass.cpp +++ b/source/opt/inst_debug_printf_pass.cpp @@ -241,15 +241,7 @@ Pass::Status InstDebugPrintfPass::ProcessImpl() { } } if (!non_sem_set_seen) { - for (auto c_itr = context()->module()->extension_begin(); - c_itr != context()->module()->extension_end(); ++c_itr) { - const std::string ext_name = c_itr->GetInOperand(0).AsString(); - if (ext_name == "SPV_KHR_non_semantic_info") { - context()->KillInst(&*c_itr); - break; - } - } - context()->get_feature_mgr()->RemoveExtension(kSPV_KHR_non_semantic_info); + context()->RemoveExtension(kSPV_KHR_non_semantic_info); } return Status::SuccessWithChange; } diff --git a/source/opt/ir_context.cpp b/source/opt/ir_context.cpp index 2c3ee692d7..cd6d858410 100644 --- a/source/opt/ir_context.cpp +++ b/source/opt/ir_context.cpp @@ -220,6 +220,28 @@ Instruction* IRContext::KillInst(Instruction* inst) { return next_instruction; } +bool IRContext::KillInstructionIf(Module::inst_iterator begin, + Module::inst_iterator end, + std::function condition) { + bool removed = false; + for (auto it = begin; it != end;) { + if (!condition(&*it)) { + ++it; + continue; + } + + removed = true; + // `it` is an iterator on an intrusive list. Next is invalidated on the + // current node when an instruction is killed. The iterator must be moved + // forward before deleting the node. + auto instruction = &*it; + ++it; + KillInst(instruction); + } + + return removed; +} + void IRContext::CollectNonSemanticTree( Instruction* inst, std::unordered_set* to_kill) { if (!inst->HasResultId()) return; @@ -251,6 +273,36 @@ bool IRContext::KillDef(uint32_t id) { return false; } +bool IRContext::RemoveCapability(spv::Capability capability) { + const bool removed = KillInstructionIf( + module()->capability_begin(), module()->capability_end(), + [capability](Instruction* inst) { + return static_cast(inst->GetSingleWordOperand(0)) == + capability; + }); + + if (removed && feature_mgr_ != nullptr) { + feature_mgr_->RemoveCapability(capability); + } + + return removed; +} + +bool IRContext::RemoveExtension(Extension extension) { + const std::string_view extensionName = ExtensionToString(extension); + const bool removed = KillInstructionIf( + module()->extension_begin(), module()->extension_end(), + [&extensionName](Instruction* inst) { + return inst->GetOperand(0).AsString() == extensionName; + }); + + if (removed && feature_mgr_ != nullptr) { + feature_mgr_->RemoveExtension(extension); + } + + return removed; +} + bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) { return ReplaceAllUsesWithPredicate(before, after, [](Instruction*) { return true; }); diff --git a/source/opt/ir_context.h b/source/opt/ir_context.h index 8419ee7e95..22e7869247 100644 --- a/source/opt/ir_context.h +++ b/source/opt/ir_context.h @@ -27,6 +27,7 @@ #include #include "source/assembly_grammar.h" +#include "source/enum_string_mapping.h" #include "source/opt/cfg.h" #include "source/opt/constants.h" #include "source/opt/debug_info_manager.h" @@ -159,7 +160,7 @@ class IRContext { inline IteratorRange types_values(); inline IteratorRange types_values() const; - // Iterators for extension instructions contained in this module. + // Iterators for ext_inst import instructions contained in this module. inline Module::inst_iterator ext_inst_import_begin(); inline Module::inst_iterator ext_inst_import_end(); inline IteratorRange ext_inst_imports(); @@ -204,12 +205,19 @@ class IRContext { // Add |capability| to the module, if it is not already enabled. inline void AddCapability(spv::Capability capability); - // Appends a capability instruction to this module. inline void AddCapability(std::unique_ptr&& c); + // Removes instruction declaring `capability` from this module. + // Returns true if the capability was removed, false otherwise. + bool RemoveCapability(spv::Capability capability); + // Appends an extension instruction to this module. inline void AddExtension(const std::string& ext_name); inline void AddExtension(std::unique_ptr&& e); + // Removes instruction declaring `extension` from this module. + // Returns true if the extension was removed, false otherwise. + bool RemoveExtension(Extension extension); + // Appends an extended instruction set instruction to this module. inline void AddExtInstImport(const std::string& name); inline void AddExtInstImport(std::unique_ptr&& e); @@ -422,6 +430,15 @@ class IRContext { // instruction exists. Instruction* KillInst(Instruction* inst); + // Deletes all the instruction in the range [`begin`; `end`[, for which the + // unary predicate `condition` returned true. + // Returns true if at least one instruction was removed, false otherwise. + // + // Pointer and iterator pointing to the deleted instructions become invalid. + // However other pointers and iterators are still valid. + bool KillInstructionIf(Module::inst_iterator begin, Module::inst_iterator end, + std::function condition); + // Collects the non-semantic instruction tree that uses |inst|'s result id // to be killed later. void CollectNonSemanticTree(Instruction* inst, @@ -772,7 +789,8 @@ class IRContext { // Analyzes the features in the owned module. Builds the manager if required. void AnalyzeFeatures() { - feature_mgr_ = MakeUnique(grammar_); + feature_mgr_ = + std::unique_ptr(new FeatureManager(grammar_)); feature_mgr_->Analyze(module()); } diff --git a/source/opt/module.h b/source/opt/module.h index ed2f3454e1..b9d69129f6 100644 --- a/source/opt/module.h +++ b/source/opt/module.h @@ -17,6 +17,7 @@ #include #include +#include #include #include #include diff --git a/test/fuzz/transformation_add_opphi_synonym_test.cpp b/test/fuzz/transformation_add_opphi_synonym_test.cpp index 4aca30ce61..03fd39a12d 100644 --- a/test/fuzz/transformation_add_opphi_synonym_test.cpp +++ b/test/fuzz/transformation_add_opphi_synonym_test.cpp @@ -365,8 +365,7 @@ TEST(TransformationAddOpPhiSynonymTest, VariablePointers) { MakeSynonymFact(12, 16)); // Remove the VariablePointers capability. - context.get()->get_feature_mgr()->RemoveCapability( - spv::Capability::VariablePointers); + context.get()->RemoveCapability(spv::Capability::VariablePointers); // The VariablePointers capability is required to add an OpPhi instruction of // pointer type. @@ -374,8 +373,7 @@ TEST(TransformationAddOpPhiSynonymTest, VariablePointers) { .IsApplicable(context.get(), transformation_context)); // Add the VariablePointers capability back. - context.get()->get_feature_mgr()->AddCapability( - spv::Capability::VariablePointers); + context.get()->AddCapability(spv::Capability::VariablePointers); // If the ids have pointer type, the storage class must be Workgroup or // StorageBuffer, but it is Function in this case. diff --git a/test/fuzz/transformation_add_type_float_test.cpp b/test/fuzz/transformation_add_type_float_test.cpp index 75f37887ae..135190acbf 100644 --- a/test/fuzz/transformation_add_type_float_test.cpp +++ b/test/fuzz/transformation_add_type_float_test.cpp @@ -74,7 +74,7 @@ TEST(TransformationAddTypeFloatTest, IsApplicable) { // By default, SPIR-V does not support 64-bit float types. // Below we add such capability, so the test should now pass. - context.get()->get_feature_mgr()->AddCapability(spv::Capability::Float64); + context.get()->AddCapability(spv::Capability::Float64); ASSERT_TRUE(TransformationAddTypeFloat(7, 64).IsApplicable( context.get(), transformation_context)); diff --git a/test/fuzz/transformation_add_type_int_test.cpp b/test/fuzz/transformation_add_type_int_test.cpp index b41d420371..e31730cc2f 100644 --- a/test/fuzz/transformation_add_type_int_test.cpp +++ b/test/fuzz/transformation_add_type_int_test.cpp @@ -88,13 +88,13 @@ TEST(TransformationAddTypeIntTest, IsApplicable) { // By default SPIR-V does not support 16-bit integers. // Below we add such capability, so the test should now be successful. - context.get()->get_feature_mgr()->AddCapability(spv::Capability::Int16); + context.get()->AddCapability(spv::Capability::Int16); ASSERT_TRUE(TransformationAddTypeInt(7, 16, true) .IsApplicable(context.get(), transformation_context)); // By default SPIR-V does not support 64-bit integers. // Below we add such capability, so the test should now pass. - context.get()->get_feature_mgr()->AddCapability(spv::Capability::Int64); + context.get()->AddCapability(spv::Capability::Int64); ASSERT_TRUE(TransformationAddTypeInt(7, 64, true) .IsApplicable(context.get(), transformation_context)); diff --git a/test/opt/ir_context_test.cpp b/test/opt/ir_context_test.cpp index 1acbefe7ee..621fe8cf09 100644 --- a/test/opt/ir_context_test.cpp +++ b/test/opt/ir_context_test.cpp @@ -1173,6 +1173,254 @@ TEST_P(TargetEnvCompareTest, Case) { } } +TEST_F(IRContextTest, ReturnsTrueWhenExtensionIsRemoved) { + const std::string text = R"( + OpCapability Shader + OpExtension "SPV_KHR_shader_clock" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %6 = OpTypeFunction %void + %1 = OpFunction %void None %6 + %9 = OpLabel + OpReturn + OpFunctionEnd)"; + + std::unique_ptr ctx = + BuildModule(SPV_ENV_UNIVERSAL_1_6, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock)); + EXPECT_EQ(std::distance(ctx->module()->extension_begin(), + ctx->module()->extension_end()), + 1); + + EXPECT_TRUE(ctx->RemoveExtension(kSPV_KHR_shader_clock)); + + EXPECT_FALSE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock)); + EXPECT_EQ(std::distance(ctx->module()->extension_begin(), + ctx->module()->extension_end()), + 0); +} + +TEST_F(IRContextTest, ReturnsFalseWhenExtensionIsNotRemoved) { + const std::string text = R"( + OpCapability Shader + OpExtension "SPV_KHR_device_group" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %6 = OpTypeFunction %void + %1 = OpFunction %void None %6 + %9 = OpLabel + OpReturn + OpFunctionEnd)"; + + std::unique_ptr ctx = + BuildModule(SPV_ENV_UNIVERSAL_1_6, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_device_group)); + EXPECT_EQ(std::distance(ctx->module()->extension_begin(), + ctx->module()->extension_end()), + 1); + + EXPECT_FALSE(ctx->RemoveExtension(kSPV_KHR_shader_clock)); + + EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_device_group)); + EXPECT_EQ(std::distance(ctx->module()->extension_begin(), + ctx->module()->extension_end()), + 1); +} + +TEST_F(IRContextTest, RemovesExtensionIfLast) { + const std::string text = R"( + OpCapability Shader + OpExtension "SPV_KHR_device_group" + OpExtension "SPV_KHR_shader_clock" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %6 = OpTypeFunction %void + %1 = OpFunction %void None %6 + %9 = OpLabel + OpReturn + OpFunctionEnd)"; + + std::unique_ptr ctx = + BuildModule(SPV_ENV_UNIVERSAL_1_6, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_device_group)); + EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock)); + EXPECT_EQ(std::distance(ctx->module()->extension_begin(), + ctx->module()->extension_end()), + 2); + + EXPECT_TRUE(ctx->RemoveExtension(kSPV_KHR_shader_clock)); + + EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_device_group)); + EXPECT_FALSE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock)); + EXPECT_EQ(std::distance(ctx->module()->extension_begin(), + ctx->module()->extension_end()), + 1); +} + +TEST_F(IRContextTest, RemovesExtensionIfFirst) { + const std::string text = R"( + OpCapability Shader + OpExtension "SPV_KHR_shader_clock" + OpExtension "SPV_KHR_device_group" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %6 = OpTypeFunction %void + %1 = OpFunction %void None %6 + %9 = OpLabel + OpReturn + OpFunctionEnd)"; + std::unique_ptr ctx = + BuildModule(SPV_ENV_UNIVERSAL_1_6, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_device_group)); + EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock)); + EXPECT_EQ(std::distance(ctx->module()->extension_begin(), + ctx->module()->extension_end()), + 2); + + EXPECT_TRUE(ctx->RemoveExtension(kSPV_KHR_shader_clock)); + + EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_device_group)); + EXPECT_FALSE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock)); + EXPECT_EQ(std::distance(ctx->module()->extension_begin(), + ctx->module()->extension_end()), + 1); +} + +TEST_F(IRContextTest, RemovesMultipleExtensions) { + const std::string text = R"( + OpCapability Shader + OpExtension "SPV_KHR_shader_clock" + OpExtension "SPV_KHR_shader_clock" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %6 = OpTypeFunction %void + %1 = OpFunction %void None %6 + %9 = OpLabel + OpReturn + OpFunctionEnd)"; + + std::unique_ptr ctx = + BuildModule(SPV_ENV_UNIVERSAL_1_6, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + EXPECT_TRUE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock)); + EXPECT_EQ(std::distance(ctx->module()->extension_begin(), + ctx->module()->extension_end()), + 2); + + EXPECT_TRUE(ctx->RemoveExtension(kSPV_KHR_shader_clock)); + + EXPECT_FALSE(ctx->get_feature_mgr()->HasExtension(kSPV_KHR_shader_clock)); + EXPECT_EQ(std::distance(ctx->module()->extension_begin(), + ctx->module()->extension_end()), + 0); +} + +TEST_F(IRContextTest, ReturnsTrueWhenCapabilityIsRemoved) { + const std::string text = R"( + OpCapability Shader + OpCapability ShaderClockKHR + OpExtension "SPV_KHR_shader_clock" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %6 = OpTypeFunction %void + %1 = OpFunction %void None %6 + %9 = OpLabel + OpReturn + OpFunctionEnd)"; + + std::unique_ptr ctx = + BuildModule(SPV_ENV_UNIVERSAL_1_6, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + EXPECT_TRUE( + ctx->get_feature_mgr()->HasCapability(spv::Capability::ShaderClockKHR)); + EXPECT_EQ(std::distance(ctx->module()->capability_begin(), + ctx->module()->capability_end()), + 2); + + EXPECT_TRUE(ctx->RemoveCapability(spv::Capability::ShaderClockKHR)); + + EXPECT_FALSE( + ctx->get_feature_mgr()->HasCapability(spv::Capability::ShaderClockKHR)); + EXPECT_EQ(std::distance(ctx->module()->capability_begin(), + ctx->module()->capability_end()), + 1); +} + +TEST_F(IRContextTest, ReturnsFalseWhenCapabilityIsNotRemoved) { + const std::string text = R"( + OpCapability Shader + OpCapability DeviceGroup + OpExtension "SPV_KHR_device_group" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %6 = OpTypeFunction %void + %1 = OpFunction %void None %6 + %9 = OpLabel + OpReturn + OpFunctionEnd)"; + + std::unique_ptr ctx = + BuildModule(SPV_ENV_UNIVERSAL_1_6, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + EXPECT_TRUE( + ctx->get_feature_mgr()->HasCapability(spv::Capability::DeviceGroup)); + EXPECT_EQ(std::distance(ctx->module()->capability_begin(), + ctx->module()->capability_end()), + 2); + + EXPECT_FALSE(ctx->RemoveCapability(spv::Capability::ShaderClockKHR)); + + EXPECT_TRUE( + ctx->get_feature_mgr()->HasCapability(spv::Capability::DeviceGroup)); + EXPECT_EQ(std::distance(ctx->module()->capability_begin(), + ctx->module()->capability_end()), + 2); +} + +TEST_F(IRContextTest, RemovesMultipleCapabilities) { + const std::string text = R"( + OpCapability Shader + OpCapability DeviceGroup + OpCapability DeviceGroup + OpExtension "SPV_KHR_device_group" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %6 = OpTypeFunction %void + %1 = OpFunction %void None %6 + %9 = OpLabel + OpReturn + OpFunctionEnd)"; + + std::unique_ptr ctx = + BuildModule(SPV_ENV_UNIVERSAL_1_6, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + EXPECT_TRUE( + ctx->get_feature_mgr()->HasCapability(spv::Capability::DeviceGroup)); + EXPECT_EQ(std::distance(ctx->module()->capability_begin(), + ctx->module()->capability_end()), + 3); + + EXPECT_TRUE(ctx->RemoveCapability(spv::Capability::DeviceGroup)); + + EXPECT_FALSE( + ctx->get_feature_mgr()->HasCapability(spv::Capability::DeviceGroup)); + EXPECT_EQ(std::distance(ctx->module()->capability_begin(), + ctx->module()->capability_end()), + 1); +} + INSTANTIATE_TEST_SUITE_P( TestCase, TargetEnvCompareTest, ::testing::Values( From 6add9ccf076adc5fe459ae86ab0aa1c8823960bd Mon Sep 17 00:00:00 2001 From: asudarsa Date: Mon, 17 Jul 2023 11:16:01 -0400 Subject: [PATCH 219/523] Add support for LiteralFloat type (#5323) Signed-off-by: Arvind Sudarsanam --- include/spirv-tools/libspirv.h | 1 + source/binary.cpp | 7 +++++++ source/diff/diff.cpp | 4 ++++ source/disassemble.cpp | 3 ++- source/operand.cpp | 2 ++ source/parsed_operand.cpp | 1 + source/text.cpp | 11 +++++++++++ 7 files changed, 28 insertions(+), 1 deletion(-) diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index 8ecaf0a4c7..0208097a80 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -143,6 +143,7 @@ typedef enum spv_operand_type_t { // may be larger than 32, which would require such a typed literal value to // occupy multiple SPIR-V words. SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER, + SPV_OPERAND_TYPE_LITERAL_FLOAT, // Always 32-bit float. // Set 3: The literal string operand type. SPV_OPERAND_TYPE_LITERAL_STRING, diff --git a/source/binary.cpp b/source/binary.cpp index 6d910f0f8a..3cfdee0434 100644 --- a/source/binary.cpp +++ b/source/binary.cpp @@ -546,6 +546,13 @@ spv_result_t Parser::parseOperand(size_t inst_offset, parsed_operand.number_bit_width = 32; break; + case SPV_OPERAND_TYPE_LITERAL_FLOAT: + // These are regular single-word literal float operands. + parsed_operand.type = SPV_OPERAND_TYPE_LITERAL_FLOAT; + parsed_operand.number_kind = SPV_NUMBER_FLOATING; + parsed_operand.number_bit_width = 32; + break; + case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER: parsed_operand.type = SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER; diff --git a/source/diff/diff.cpp b/source/diff/diff.cpp index d5cda462cb..6269af5004 100644 --- a/source/diff/diff.cpp +++ b/source/diff/diff.cpp @@ -2038,6 +2038,10 @@ spv_number_kind_t Differ::GetNumberKind(const IdInstructions& id_to, // Always unsigned integers. *number_bit_width = 32; return SPV_NUMBER_UNSIGNED_INT; + case SPV_OPERAND_TYPE_LITERAL_FLOAT: + // Always float. + *number_bit_width = 32; + return SPV_NUMBER_FLOATING; case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER: switch (inst.opcode()) { diff --git a/source/disassemble.cpp b/source/disassemble.cpp index f862efd56b..5173fbf677 100644 --- a/source/disassemble.cpp +++ b/source/disassemble.cpp @@ -357,7 +357,8 @@ void InstructionDisassembler::EmitOperand(const spv_parsed_instruction_t& inst, stream_ << opcode_desc->name; } break; case SPV_OPERAND_TYPE_LITERAL_INTEGER: - case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: { + case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: + case SPV_OPERAND_TYPE_LITERAL_FLOAT: { SetRed(); EmitNumericLiteral(&stream_, inst, operand); ResetColor(); diff --git a/source/operand.cpp b/source/operand.cpp index a78191b942..c2e5a99da7 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -155,6 +155,7 @@ const char* spvOperandTypeStr(spv_operand_type_t type) { case SPV_OPERAND_TYPE_LITERAL_INTEGER: case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER: case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER: + case SPV_OPERAND_TYPE_LITERAL_FLOAT: return "literal number"; case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER: return "possibly multi-word literal integer"; @@ -332,6 +333,7 @@ bool spvOperandIsConcrete(spv_operand_type_t type) { } switch (type) { case SPV_OPERAND_TYPE_LITERAL_INTEGER: + case SPV_OPERAND_TYPE_LITERAL_FLOAT: case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: diff --git a/source/parsed_operand.cpp b/source/parsed_operand.cpp index 5f8e94db84..cc33f8ba2c 100644 --- a/source/parsed_operand.cpp +++ b/source/parsed_operand.cpp @@ -24,6 +24,7 @@ namespace spvtools { void EmitNumericLiteral(std::ostream* out, const spv_parsed_instruction_t& inst, const spv_parsed_operand_t& operand) { if (operand.type != SPV_OPERAND_TYPE_LITERAL_INTEGER && + operand.type != SPV_OPERAND_TYPE_LITERAL_FLOAT && operand.type != SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER && operand.type != SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER && operand.type != SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER) diff --git a/source/text.cpp b/source/text.cpp index eb7f96b93f..737c223b53 100644 --- a/source/text.cpp +++ b/source/text.cpp @@ -312,6 +312,17 @@ spv_result_t spvTextEncodeOperand(const spvtools::AssemblyGrammar& grammar, } } break; + case SPV_OPERAND_TYPE_LITERAL_FLOAT: { + // The current operand is a 32-bit float. + // That's just how the grammar works. + spvtools::IdType expected_type = { + 32, false, spvtools::IdTypeClass::kScalarFloatType}; + if (auto error = context->binaryEncodeNumericLiteral( + textValue, error_code_for_literals, expected_type, pInst)) { + return error; + } + } break; + case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER: // This is a context-independent literal number which can be a 32-bit // number of floating point value. From 7dd5f95d25e4c1460d244fe7563d1ff335cdd623 Mon Sep 17 00:00:00 2001 From: ncesario-lunarg <71668273+ncesario-lunarg@users.noreply.github.com> Date: Mon, 17 Jul 2023 13:16:25 -0600 Subject: [PATCH 220/523] [spirv-opt] Handle OpFunction in GetPtr (#5316) When using PhysicalStorageBuffer it is possible for a function to return a pointer type. This was not being handled correctly in `GetLoadedVariablesFromFunctionCall` in the DCE pass because `IsPtr` returns the wrong result. Fixes #5270. --- source/opt/aggressive_dead_code_elim_pass.cpp | 3 + source/opt/mem_pass.cpp | 5 ++ test/opt/aggressive_dead_code_elim_test.cpp | 65 +++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp index 3f982f8856..3d08ec15e0 100644 --- a/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/source/opt/aggressive_dead_code_elim_pass.cpp @@ -438,6 +438,9 @@ std::vector AggressiveDCEPass::GetLoadedVariablesFromFunctionCall( const Instruction* inst) { assert(inst->opcode() == spv::Op::OpFunctionCall); std::vector live_variables; + // NOTE: we should only be checking function call parameters here, not the + // function itself, however, `IsPtr` will trivially return false for + // OpFunction inst->ForEachInId([this, &live_variables](const uint32_t* operand_id) { if (!IsPtr(*operand_id)) return; uint32_t var_id = GetVariableId(*operand_id); diff --git a/source/opt/mem_pass.cpp b/source/opt/mem_pass.cpp index 9f95785699..9972c4f75f 100644 --- a/source/opt/mem_pass.cpp +++ b/source/opt/mem_pass.cpp @@ -76,6 +76,11 @@ bool MemPass::IsNonPtrAccessChain(const spv::Op opcode) const { bool MemPass::IsPtr(uint32_t ptrId) { uint32_t varId = ptrId; Instruction* ptrInst = get_def_use_mgr()->GetDef(varId); + if (ptrInst->opcode() == spv::Op::OpFunction) { + // A function is not a pointer, but it's return type could be, which will + // erroneously lead to this function returning true later on + return false; + } while (ptrInst->opcode() == spv::Op::OpCopyObject) { varId = ptrInst->GetSingleWordInOperand(kCopyObjectOperandInIdx); ptrInst = get_def_use_mgr()->GetDef(varId); diff --git a/test/opt/aggressive_dead_code_elim_test.cpp b/test/opt/aggressive_dead_code_elim_test.cpp index 83aab3c46a..f8f15b6cc4 100644 --- a/test/opt/aggressive_dead_code_elim_test.cpp +++ b/test/opt/aggressive_dead_code_elim_test.cpp @@ -7884,6 +7884,71 @@ TEST_F(AggressiveDCETest, RemoveWhenUsingPrintfExtension) { SinglePassRunAndMatch(text, true); } +TEST_F(AggressiveDCETest, FunctionReturnPointer) { + // Run DCE when a function returning a pointer to a reference is present + + const std::string text = R"( + OpCapability Shader + OpCapability PhysicalStorageBufferAddresses + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel PhysicalStorageBuffer64 GLSL450 + OpEntryPoint Vertex %2 "main" %3 %4 + OpSource GLSL 450 + OpSourceExtension "GL_EXT_buffer_reference" + OpSourceExtension "GL_EXT_scalar_block_layout" + OpName %4 "color" + OpMemberDecorate %5 0 Offset 0 + OpDecorate %5 Block + OpMemberDecorate %7 0 Offset 0 + OpDecorate %7 Block + OpDecorate %8 AliasedPointer + OpDecorate %4 Location 0 + %9 = OpTypeVoid + %10 = OpTypeFunction %9 + OpTypeForwardPointer %11 PhysicalStorageBuffer + %12 = OpTypeInt 32 0 + %5 = OpTypeStruct %12 + %11 = OpTypePointer PhysicalStorageBuffer %5 +;CHECK: [[pt:%\w+]] = OpTypePointer PhysicalStorageBuffer {{%\w+}} + %13 = OpTypeFunction %11 +;CHECK: [[pt_fn:%\w+]] = OpTypeFunction [[pt]] + %7 = OpTypeStruct %11 + %14 = OpTypePointer PushConstant %7 + %3 = OpVariable %14 PushConstant + %15 = OpTypeInt 32 1 + %16 = OpConstant %15 0 + %17 = OpTypePointer PushConstant %11 + %18 = OpTypePointer Function %11 + %19 = OpTypeFloat 32 + %20 = OpTypeVector %19 4 + %21 = OpTypePointer Output %20 + %4 = OpVariable %21 Output + %22 = OpConstant %19 1 + %23 = OpConstant %19 0 + %24 = OpConstantComposite %20 %22 %23 %22 %22 + %6 = OpFunction %11 None %13 +;CHECK: [[fn:%\w+]] = OpFunction [[pt]] None [[pt_fn]] + %27 = OpLabel + %28 = OpAccessChain %17 %3 %16 + %29 = OpLoad %11 %28 + OpReturnValue %29 + OpFunctionEnd + %2 = OpFunction %9 None %10 + %25 = OpLabel + %8 = OpVariable %18 Function + %26 = OpFunctionCall %11 %6 +;CHECK: {{%\w+}} = OpFunctionCall [[pt]] [[fn]] + OpStore %8 %26 + OpStore %4 %24 + OpReturn + OpFunctionEnd +)"; + + // For physical storage buffer support + SetTargetEnv(SPV_ENV_VULKAN_1_2); + SinglePassRunAndMatch(text, true); +} + } // namespace } // namespace opt } // namespace spvtools From 9e0b780ff88329dfcb3bc5b7014959c80720afbb Mon Sep 17 00:00:00 2001 From: Joyce Date: Mon, 17 Jul 2023 17:34:04 -0300 Subject: [PATCH 221/523] Create SECURITY.md (#5325) Signed-off-by: Joyce --- SECURITY.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..99c5f441a3 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy + +## Supported Versions + +Security updates are applied only to the latest release. + +## Reporting a Vulnerability + +If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released. + +Please disclose it at [security advisory](https://github.com/KhronosGroup/SPIRV-Tools/security/advisories/new). + +This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure. From 4b6bd5a665ba0529747af3a0bc808732b7e78f48 Mon Sep 17 00:00:00 2001 From: Diego Novillo Date: Mon, 17 Jul 2023 17:01:08 -0400 Subject: [PATCH 222/523] Prepare release v2023.4 (#5330) --- CHANGES | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index c11067a242..c3d46a13d8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,32 @@ Revision history for SPIRV-Tools -v2023.3 2023-15-15 +v2023.4 2023-07-17 + - General + - Add support for LiteralFloat type (#5323) + - SPV_KHR_cooperative_matrix (#5286) + - Allow OpTypeBool in UniformConstant (#5237) + - Allow physical storage buffer pointer in IO (#5251) + - Remove const zero image operands (#5232) + - Optimizer + - Enable vector constant folding (#4913) (#5272) + - Fold negation of integer vectors (#5269) + - Add folding rule for OpTranspose (#5241) + - Add SPV_NV_bindless_texture to spirv optimizations (#5231) + - Instrument + - instrument: Cast gl_VertexIndex and InstanceIndex to uint (#5319) + - instrument: Fix buffer address length calculations (#5257) + - Validator + - Validate GroupNonUniform instructions (#5296) + - spirv-val: Label SPV_KHR_cooperative_matrix VUID (#5301) + - Validate layouts for PhysicalStorageBuffer pointers (#5291) + - spirv-val: Remove VUID from 1.3.251 spec (#5244) + - Diff + - spirv-diff: Update test expectations (#5264) + - spirv-diff: Leave undefined ids unpaired. (#5262) + - spirv-diff: Properly match SPV_KHR_ray_query types. (#5259) + - diff: Don't give up entry point matching too early. (#5224) + +v2023.3 2023-05-15 - General - Update spirv_headers to include SPV_KHR_ray_tracing_position_fetch (#5205) - spirv-tools: Add support for QNX (#5211) From 61221e7d6271abcd34f173276521a2d55515191c Mon Sep 17 00:00:00 2001 From: Mateusz Przybylski Date: Tue, 18 Jul 2023 07:40:43 -0700 Subject: [PATCH 223/523] Add python3 requirement for the script (#5326) as python2 may not recgonize utf encoding, per https://bugs.python.org/issue11033 --- utils/generate_language_headers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/generate_language_headers.py b/utils/generate_language_headers.py index 83fa99e1f7..18a8d5ea01 100755 --- a/utils/generate_language_headers.py +++ b/utils/generate_language_headers.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2017 Google Inc. # Licensed under the Apache License, Version 2.0 (the "License"); From 6c7e1acc5f9921b9a609dce62f30620bd6855764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 18 Jul 2023 20:42:42 +0200 Subject: [PATCH 224/523] NFC: fix missing algorithm include in enumset file (#5334) Caused issues with vs2017, required for std::min. --- source/enum_set.h | 1 + 1 file changed, 1 insertion(+) diff --git a/source/enum_set.h b/source/enum_set.h index 75320679b4..437a424382 100644 --- a/source/enum_set.h +++ b/source/enum_set.h @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include #include #include From 883417544b594850d59c11caf18cd7286c968b9b Mon Sep 17 00:00:00 2001 From: David Neto Date: Wed, 19 Jul 2023 17:47:24 -0400 Subject: [PATCH 225/523] Set cmake_policy CMP0128 (#5341) Work around a problem in CMake 3.22.1 in setting -std=c++17. Instead -std=c++11 is in effect for targets in test/*, but those targets require C++17. Fixes: #5340 --- CMakeLists.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ea869f88cf..4f999e9081 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,16 @@ cmake_minimum_required(VERSION 3.17.2) project(spirv-tools) +# Avoid a bug in CMake 3.22.1. By default it will set -std=c++11 for +# targets in test/*, when those tests need -std=c++17. +# https://github.com/KhronosGroup/SPIRV-Tools/issues/5340 +# The bug is fixed in CMake 3.22.2 +if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.22.1") + if (${CMAKE_VERSION} VERSION_LESS "3.22.2") + cmake_policy(SET CMP0128 NEW) + endif() +endif() + set_property(GLOBAL PROPERTY USE_FOLDERS ON) enable_testing() From 2813da26813cd10f54bc1ec0309e6664f7756c4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 20 Jul 2023 15:05:12 +0200 Subject: [PATCH 226/523] kokoro: rename glslang (#5339) * kokoro: rename glslang glslangValidator was renamed to glslang (https://github.com/KhronosGroup/glslang/pull/3257). Fixing build. * rename glslang to glslang-standalone --- kokoro/scripts/linux/build-docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kokoro/scripts/linux/build-docker.sh b/kokoro/scripts/linux/build-docker.sh index 679df0fc1a..a0dc96abcf 100755 --- a/kokoro/scripts/linux/build-docker.sh +++ b/kokoro/scripts/linux/build-docker.sh @@ -142,7 +142,7 @@ elif [ $TOOL = "cmake-smoketest" ]; then cmake -GNinja -DRE2_BUILD_TESTING=OFF -DCMAKE_BUILD_TYPE="Release" .. echo $(date): Build glslang... - ninja glslangValidator + ninja glslang-standalone echo $(date): Build everything... ninja From c50bc49f586a30b6c7799805dd077c92496a2332 Mon Sep 17 00:00:00 2001 From: David Neto Date: Thu, 20 Jul 2023 10:09:23 -0400 Subject: [PATCH 227/523] Fix link flags for Clang-based MinGW cross compile (#5342) See https://github.com/android/ndk/issues/1464 The old code tested for Windows and GCC as the compiler. Instead of checking for GCC, check the compiler is not MSVC. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f999e9081..375229ba2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -243,7 +243,7 @@ function(spvtools_default_compile_options TARGET) # For MinGW cross compile, statically link to the C++ runtime. # But it still depends on MSVCRT.dll. if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") - if (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") + if (NOT MSVC) set_target_properties(${TARGET} PROPERTIES LINK_FLAGS -static -static-libgcc -static-libstdc++) endif() From 876ccc6cd5fa4dff674d1c699cd74026df4b3c39 Mon Sep 17 00:00:00 2001 From: David Neto Date: Thu, 20 Jul 2023 10:14:35 -0400 Subject: [PATCH 228/523] Add /bigobj to test_opt for VS 2017 (#5336) This apparently is required for debug builds. Fixes: #5335 --- test/opt/CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt index 3b2d3844eb..37b145d66c 100644 --- a/test/opt/CMakeLists.txt +++ b/test/opt/CMakeLists.txt @@ -115,3 +115,12 @@ add_spvtools_unittest(TARGET opt LIBS SPIRV-Tools-opt PCH_FILE pch_test_opt ) +if (NOT "${SPIRV_SKIP_TESTS}" AND TARGET gmock_main) + if (MSVC) + if (${MSVC_VERSION} LESS 1920) + # The VS 2017 debug build requires /bigobj on test_opt + # https://github.com/KhronosGroup/SPIRV-Tools/issues/5335 + target_compile_options(test_opt PRIVATE /bigobj) + endif() + endif() +endif() From bf03d40922409560e03fad3d4393025763309895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 20 Jul 2023 16:18:19 +0200 Subject: [PATCH 229/523] opt: change Get* functions to return const& (#5331) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GetCapabilities returned a const*, and GetExtensions did not exist. This commit adds GetExtensions, and changes the return value to be a const&. This commit also removes the overload to GetCapabilities which returns a mutable set, as it is unused. Signed-off-by: Nathan Gauër --- source/opt/feature_manager.h | 8 ++++--- source/opt/ir_context.cpp | 2 +- test/opt/feature_manager_test.cpp | 37 +++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/source/opt/feature_manager.h b/source/opt/feature_manager.h index 59735edb4a..d150a2fa2b 100644 --- a/source/opt/feature_manager.h +++ b/source/opt/feature_manager.h @@ -33,7 +33,11 @@ class FeatureManager { return capabilities_.contains(cap); } - const CapabilitySet* GetCapabilities() const { return &capabilities_; } + // Returns the capabilities the module declares. + inline const CapabilitySet& GetCapabilities() const { return capabilities_; } + + // Returns the extensions the module imports. + inline const ExtensionSet& GetExtensions() const { return extensions_; } uint32_t GetExtInstImportId_GLSLstd450() const { return extinst_importid_GLSLstd450_; @@ -77,8 +81,6 @@ class FeatureManager { // Removes the given |capability| from the current FeatureManager. void RemoveCapability(spv::Capability capability); - CapabilitySet* GetCapabilities() { return &capabilities_; } - // Analyzes |module| and records imported external instruction sets. void AddExtInstImportIds(Module* module); diff --git a/source/opt/ir_context.cpp b/source/opt/ir_context.cpp index cd6d858410..239d316ca8 100644 --- a/source/opt/ir_context.cpp +++ b/source/opt/ir_context.cpp @@ -770,7 +770,7 @@ void IRContext::AddCombinatorsForExtension(Instruction* extension) { } void IRContext::InitializeCombinators() { - for (auto capability : *get_feature_mgr()->GetCapabilities()) { + for (auto capability : get_feature_mgr()->GetCapabilities()) { AddCombinatorsForCapability(uint32_t(capability)); } diff --git a/test/opt/feature_manager_test.cpp b/test/opt/feature_manager_test.cpp index a5105a9ac5..7e8f92c3c1 100644 --- a/test/opt/feature_manager_test.cpp +++ b/test/opt/feature_manager_test.cpp @@ -87,6 +87,25 @@ OpExtension "SPV_KHR_storage_buffer_storage_class" Extension::kSPV_KHR_storage_buffer_storage_class)); } +TEST_F(FeatureManagerTest, GetExtensionsReturnsExtensions) { + const std::string text = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" + )"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text); + ASSERT_NE(context, nullptr); + + const auto& extensions = context->get_feature_mgr()->GetExtensions(); + EXPECT_EQ(extensions.size(), 2); + EXPECT_TRUE(extensions.contains(Extension::kSPV_KHR_variable_pointers)); + EXPECT_TRUE( + extensions.contains(Extension::kSPV_KHR_storage_buffer_storage_class)); +} + // Test capability checks. TEST_F(FeatureManagerTest, ExplicitlyPresent1) { const std::string text = R"( @@ -142,6 +161,24 @@ OpMemoryModel Logical GLSL450 context->get_feature_mgr()->HasCapability(spv::Capability::Kernel)); } +TEST_F(FeatureManagerTest, GetCapabilitiesReturnsImplicitCapabilities) { + const std::string text = R"( +OpCapability Tessellation +OpMemoryModel Logical GLSL450 + )"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text); + ASSERT_NE(context, nullptr); + + const auto& capabilities = context->get_feature_mgr()->GetCapabilities(); + // Tesselation implies Shader, which implies Matrix. + EXPECT_EQ(capabilities.size(), 3); + EXPECT_TRUE(capabilities.contains(spv::Capability::Tessellation)); + EXPECT_TRUE(capabilities.contains(spv::Capability::Shader)); + EXPECT_TRUE(capabilities.contains(spv::Capability::Matrix)); +} + } // namespace } // namespace opt } // namespace spvtools From 45f7e55af442a765c1a74994ffb79688d2e7437e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Jul 2023 13:07:28 -0400 Subject: [PATCH 230/523] Bump word-wrap from 1.2.3 to 1.2.4 in /tools/sva (#5343) Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4. - [Release notes](https://github.com/jonschlinkert/word-wrap/releases) - [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4) --- updated-dependencies: - dependency-name: word-wrap 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 d25a286b6c..1f5624e1fd 100644 --- a/tools/sva/yarn.lock +++ b/tools/sva/yarn.lock @@ -1398,9 +1398,9 @@ widest-line@^4.0.1: string-width "^5.0.1" word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + version "1.2.4" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f" + integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA== workerpool@6.2.1: version "6.2.1" From daad2295c981e93c9bb6afdb966ee330bab25dcb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 20 Jul 2023 17:18:52 +0000 Subject: [PATCH 231/523] Roll external/googletest/ cc366710b..d66ce5851 (2 commits) (#5337) * Roll external/googletest/ cc366710b..1ed6a8c67 (3 commits) https://github.com/google/googletest/compare/cc366710bbf4...1ed6a8c67a0b $ git log cc366710b..1ed6a8c67 --date=short --no-merges --format='%ad %ae %s' 2023-07-19 dmauro Remove unused cast implementation 2023-07-11 kim.valen Fixed variables that could be declared 'const' 2023-05-11 chrisjohnsonmail add support for nrf52 Created with: roll-dep external/googletest * Roll external/spirv-headers/ f1ba373ef..14914db17 (6 commits) https://github.com/KhronosGroup/SPIRV-Headers/compare/f1ba373ef037...14914db17a1f $ git log f1ba373ef..14914db17 --date=short --no-merges --format='%ad %ae %s' 2023-07-19 kevin.petit Report failures in makeHeaders 2023-07-19 alanbaker Revert "Add support for fp_max_error extension" 2023-06-21 arvind.sudarsanam Change kind of FPMaxErrorDecorationINTEL to LiteralFloat 2023-06-09 arvind.sudarsanam Interchange capability and decoration 2023-03-09 arvind.sudarsanam Add parameters 2023-02-02 arvind.sudarsanam Header files changes to support SPV_INTEL_fp_max_error spec extension 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 89b51ca560..a70e6b7939 100644 --- a/DEPS +++ b/DEPS @@ -7,13 +7,13 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': 'cc366710bbf40a9816d47c35802d06dbaccb8792', + 'googletest_revision': '1ed6a8c67a0bd675149ece27bbec0ef1759854cf', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', 're2_revision': 'e66463312e1d30d427bbde6c40e7fd627dcfb82e', - 'spirv_headers_revision': 'f1ba373ef03752ee9f6f2b898bea1213f93e1ef2', + 'spirv_headers_revision': '14914db17a1fc16e06c4e49e5353bb80b3267e9c', } deps = { From 17d9669d51f2f30eb95e5b670f831fccb4b64802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 20 Jul 2023 19:54:50 +0200 Subject: [PATCH 232/523] enumset: add iterator based constructor/insert (#5344) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expanding a bit the EnumSet API to have iterator-based insert and constructors (like the STL). This is also a pre-requisite from the capability-trimming pass as it allows to build a const set from a constexpr std::array easily. Signed-off-by: Nathan Gauër --- source/enum_set.h | 17 ++++++++ test/enum_set_test.cpp | 93 +++++++++++++++++++++++++++++++++--------- 2 files changed, 90 insertions(+), 20 deletions(-) diff --git a/source/enum_set.h b/source/enum_set.h index 437a424382..a3751388ab 100644 --- a/source/enum_set.h +++ b/source/enum_set.h @@ -204,6 +204,14 @@ class EnumSet { } } + // Creates a set initialized with the content of the range [begin; end[. + template + EnumSet(InputIt begin, InputIt end) : EnumSet() { + for (; begin != end; ++begin) { + insert(*begin); + } + } + // Copies the EnumSet `other` into a new EnumSet. EnumSet(const EnumSet& other) : buckets_(other.buckets_), size_(other.size_) {} @@ -256,6 +264,15 @@ class EnumSet { // insertion. iterator insert(const_iterator, T&& value) { return insert(value).first; } + // Inserts all the values in the range [`first`; `last[. + // Similar to `std::unordered_set::insert`. + template + void insert(InputIt first, InputIt last) { + for (auto it = first; it != last; ++it) { + insert(*it); + } + } + // Removes the value `value` into the set. // Similar to `std::unordered_set::erase`. // Returns the number of erased elements. diff --git a/test/enum_set_test.cpp b/test/enum_set_test.cpp index a561dbfc86..7a6e4caba1 100644 --- a/test/enum_set_test.cpp +++ b/test/enum_set_test.cpp @@ -286,6 +286,30 @@ constexpr std::array kCapabilities{ spv::Capability::Max, }; +namespace { +std::vector enumerateValuesFromToWithStep(size_t start, size_t end, + size_t step) { + assert(end > start && "end > start"); + std::vector orderedValues; + for (size_t i = start; i < end; i += step) { + orderedValues.push_back(static_cast(i)); + } + return orderedValues; +} + +EnumSet createSetUnorderedInsertion( + const std::vector& values) { + std::vector shuffledValues(values.cbegin(), values.cend()); + std::mt19937 rng(0); + std::shuffle(shuffledValues.begin(), shuffledValues.end(), rng); + EnumSet set; + for (auto value : shuffledValues) { + set.insert(value); + } + return set; +} +} // namespace + TEST(EnumSet, IsEmpty1) { EnumSet set; EXPECT_TRUE(set.empty()); @@ -439,29 +463,58 @@ TEST(EnumSet, DefaultIsEmpty) { } } -namespace { -std::vector enumerateValuesFromToWithStep(size_t start, size_t end, - size_t step) { - assert(end > start && "end > start"); - std::vector orderedValues; - for (size_t i = start; i < end; i += step) { - orderedValues.push_back(static_cast(i)); - } - return orderedValues; +TEST(EnumSet, EqualityCompareEmpty) { + EnumSet set1; + EnumSet set2; + + EXPECT_TRUE(set1 == set2); + EXPECT_FALSE(set1 != set2); } -EnumSet createSetUnorderedInsertion( - const std::vector& values) { - std::vector shuffledValues(values.cbegin(), values.cend()); - std::mt19937 rng(0); - std::shuffle(shuffledValues.begin(), shuffledValues.end(), rng); - EnumSet set; - for (auto value : shuffledValues) { - set.insert(value); - } - return set; +TEST(EnumSet, EqualityCompareSame) { + EnumSet set1; + EnumSet set2; + + set1.insert(TestEnum::ONE); + set1.insert(TestEnum::TWENTY); + set2.insert(TestEnum::TWENTY); + set2.insert(TestEnum::ONE); + + EXPECT_TRUE(set1 == set2); + EXPECT_FALSE(set1 != set2); +} + +TEST(EnumSet, EqualityCompareDifferent) { + EnumSet set1; + EnumSet set2; + + set1.insert(TestEnum::ONE); + set1.insert(TestEnum::TWENTY); + set2.insert(TestEnum::FIVE); + set2.insert(TestEnum::ONE); + + EXPECT_FALSE(set1 == set2); + EXPECT_TRUE(set1 != set2); +} + +TEST(EnumSet, ConstructFromIterators) { + auto orderedValues = enumerateValuesFromToWithStep(0, 2, /* step= */ 1); + EnumSet set1 = createSetUnorderedInsertion(orderedValues); + + EnumSet set2(orderedValues.cbegin(), orderedValues.cend()); + + EXPECT_EQ(set1, set2); +} + +TEST(EnumSet, InsertUsingIteratorRange) { + auto orderedValues = enumerateValuesFromToWithStep(0, 2, /* step= */ 1); + EnumSet set1 = createSetUnorderedInsertion(orderedValues); + + EnumSet set2; + set2.insert(orderedValues.cbegin(), orderedValues.cend()); + + EXPECT_EQ(set1, set2); } -} // namespace TEST(CapabilitySet, RangeBasedLoopOrderIsEnumOrder) { auto orderedValues = enumerateValuesFromToWithStep(0, 2, /* step= */ 1); From d52c39c37d4d7aece12e6177203cc3d733e8b772 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Fri, 21 Jul 2023 07:17:12 -0700 Subject: [PATCH 233/523] Do not crash when folding 16-bit OpFDiv (#5338) The code currently tries to get the value of the floating point constant to see if it is -0.0. However, we are not able to get the value for 16-bit floating point value, and we hit an assert. To avoid this, we add an early check for the width to make sure it is either 32 or 64. Fixes https://github.com/microsoft/DirectXShaderCompiler/issues/5413. --- source/opt/const_folding_rules.cpp | 5 +++++ test/opt/fold_test.cpp | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/source/opt/const_folding_rules.cpp b/source/opt/const_folding_rules.cpp index 915f41ce14..e676974c8c 100644 --- a/source/opt/const_folding_rules.cpp +++ b/source/opt/const_folding_rules.cpp @@ -967,6 +967,11 @@ const analysis::Constant* FoldScalarFPDivide( return FoldFPScalarDivideByZero(result_type, numerator, const_mgr); } + uint32_t width = denominator->type()->AsFloat()->width(); + if (width != 32 && width != 64) { + return nullptr; + } + const analysis::FloatConstant* denominator_float = denominator->AsFloatConstant(); if (denominator_float && denominator->GetValueAsDouble() == -0.0) { diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index 14ac9153f5..c5adf6dd1c 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -285,6 +285,7 @@ OpName %main "main" %v2double_null = OpConstantNull %v2double %108 = OpConstant %half 0 %half_1 = OpConstant %half 1 +%half_2 = OpConstant %half 2 %half_0_1 = OpConstantComposite %v2half %108 %half_1 %106 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 %v4float_0_0_0_0 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 @@ -4517,6 +4518,17 @@ INSTANTIATE_TEST_SUITE_P(FloatRedundantFoldingTest, GeneralInstructionFoldingTes "%2 = OpDot %half %half_0_1 %half_0_1\n" + "OpReturn\n" + "OpFunctionEnd", + 2, 0), + // Test case 23: Don't fold 1.0(half) / 2.0(half) + // We do not have to code to emulate 16-bit float operations. Just make sure we do not crash. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_half Function\n" + + "%3 = OpLoad %half %n\n" + + "%2 = OpFDiv %half %half_1 %half_2\n" + + "OpReturn\n" + + "OpFunctionEnd", 2, 0) )); From ec90d2872acbb4802661c9186a1e0fce8924e97b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Jul 2023 10:15:44 -0400 Subject: [PATCH 234/523] roll deps (#5345) * Roll external/googletest/ 1ed6a8c67..01e18376e (1 commit) https://github.com/google/googletest/compare/1ed6a8c67a0b...01e18376efe6 $ git log 1ed6a8c67..01e18376e --date=short --no-merges --format='%ad %ae %s' 2023-07-21 absl-team Make `AbslStringify` usage public in GoogleTest Created with: roll-dep external/googletest * Roll external/spirv-headers/ 14914db17..51b106461 (1 commit) https://github.com/KhronosGroup/SPIRV-Headers/compare/14914db17a1f...51b106461707 $ git log 14914db17..51b106461 --date=short --no-merges --format='%ad %ae %s' 2023-07-21 arvind.sudarsanam Recommit PR #348 - Add fp-max-error support (#363) 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 a70e6b7939..ae4d50b69e 100644 --- a/DEPS +++ b/DEPS @@ -7,13 +7,13 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '1ed6a8c67a0bd675149ece27bbec0ef1759854cf', + 'googletest_revision': '01e18376efe643a82cff468734f87f8c60e314b6', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', 're2_revision': 'e66463312e1d30d427bbde6c40e7fd627dcfb82e', - 'spirv_headers_revision': '14914db17a1fc16e06c4e49e5353bb80b3267e9c', + 'spirv_headers_revision': '51b106461707f46d962554efe1bf56dee28958a3', } deps = { From 35d8b05de4212276d03a5d67201398fd49849896 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 25 Jul 2023 16:52:41 +0200 Subject: [PATCH 235/523] opt: add capability trimming pass (not default). (#5278) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a new optimization which tries to remove unnecessary capabilities from a SPIR-V module. When compiling a SPIR-V module, you may have some dead-code using features gated by a capability. DCE will remove this code, but the capability will remain. This means your module would still require some capability, even if it doesn't require it. Calling this pass on your module would remove obsolete capabilities. This pass wouldn't be enabled by default, and would only be usable from the API (at least for now). NOTE: this commit only adds the basic skeleton/structure, and doesn't mark as supported many capabilities it could support. I'll add them as supported as I write tests. Signed-off-by: Nathan Gauër --- include/spirv-tools/optimizer.hpp | 11 + source/opt/CMakeLists.txt | 2 + source/opt/ir_context.h | 22 + source/opt/passes.h | 1 + source/opt/trim_capabilities_pass.cpp | 320 ++++++++++ source/opt/trim_capabilities_pass.h | 151 +++++ test/opt/CMakeLists.txt | 1 + test/opt/trim_capabilities_pass_test.cpp | 746 +++++++++++++++++++++++ 8 files changed, 1254 insertions(+) create mode 100644 source/opt/trim_capabilities_pass.cpp create mode 100644 source/opt/trim_capabilities_pass.h create mode 100644 test/opt/trim_capabilities_pass_test.cpp diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp index ddc8384f7a..8579c8c4df 100644 --- a/include/spirv-tools/optimizer.hpp +++ b/include/spirv-tools/optimizer.hpp @@ -981,6 +981,17 @@ Optimizer::PassToken CreateRemoveDontInlinePass(); // object, currently the pass would remove accesschain pointer argument passed // to the function Optimizer::PassToken CreateFixFuncCallArgumentsPass(); + +// Creates a trim-capabilities pass. +// This pass removes unused capabilities for a given module, and if possible, +// associated extensions. +// See `trim_capabilities.h` for the list of supported capabilities. +// +// If the module contains unsupported capabilities, this pass will ignore them. +// This should be fine in most cases, but could yield to incorrect results if +// the unknown capability interacts with one of the trimmed capabilities. +Optimizer::PassToken CreateTrimCapabilitiesPass(); + } // namespace spvtools #endif // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_ diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt index eea3c47532..99a74cd7f8 100644 --- a/source/opt/CMakeLists.txt +++ b/source/opt/CMakeLists.txt @@ -122,6 +122,7 @@ set(SPIRV_TOOLS_OPT_SOURCES strip_nonsemantic_info_pass.h struct_cfg_analysis.h tree_iterator.h + trim_capabilities_pass.h type_manager.h types.h unify_const_pass.h @@ -236,6 +237,7 @@ set(SPIRV_TOOLS_OPT_SOURCES strip_debug_info_pass.cpp strip_nonsemantic_info_pass.cpp struct_cfg_analysis.cpp + trim_capabilities_pass.cpp type_manager.cpp types.cpp unify_const_pass.cpp diff --git a/source/opt/ir_context.h b/source/opt/ir_context.h index 22e7869247..7ff411a15f 100644 --- a/source/opt/ir_context.h +++ b/source/opt/ir_context.h @@ -154,6 +154,12 @@ class IRContext { inline IteratorRange capabilities(); inline IteratorRange capabilities() const; + // Iterators for extensions instructions contained in this module. + inline Module::inst_iterator extension_begin(); + inline Module::inst_iterator extension_end(); + inline IteratorRange extensions(); + inline IteratorRange extensions() const; + // Iterators for types, constants and global variables instructions. inline Module::inst_iterator types_values_begin(); inline Module::inst_iterator types_values_end(); @@ -982,6 +988,22 @@ IteratorRange IRContext::capabilities() const { return ((const Module*)module())->capabilities(); } +Module::inst_iterator IRContext::extension_begin() { + return module()->extension_begin(); +} + +Module::inst_iterator IRContext::extension_end() { + return module()->extension_end(); +} + +IteratorRange IRContext::extensions() { + return module()->extensions(); +} + +IteratorRange IRContext::extensions() const { + return ((const Module*)module())->extensions(); +} + Module::inst_iterator IRContext::types_values_begin() { return module()->types_values_begin(); } diff --git a/source/opt/passes.h b/source/opt/passes.h index eb3b1e5d31..f87216dd63 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/trim_capabilities_pass.h" #include "source/opt/unify_const_pass.h" #include "source/opt/upgrade_memory_model.h" #include "source/opt/vector_dce.h" diff --git a/source/opt/trim_capabilities_pass.cpp b/source/opt/trim_capabilities_pass.cpp new file mode 100644 index 0000000000..1a7633d65c --- /dev/null +++ b/source/opt/trim_capabilities_pass.cpp @@ -0,0 +1,320 @@ +// 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/trim_capabilities_pass.h" + +#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/spirv_target_env.h" +#include "source/util/string_utils.h" + +namespace spvtools { +namespace opt { + +namespace { +constexpr uint32_t kVariableStorageClassIndex = 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()); + const auto* def_use_mgr = instruction->context()->get_def_use_mgr(); + while (!instructions_to_visit.empty()) { + const Instruction* item = + def_use_mgr->GetDef(instructions_to_visit.front()); + instructions_to_visit.pop(); + + if (item->opcode() == spv::Op::OpTypePointer) { + instructions_to_visit.push( + item->GetSingleWordInOperand(kTypePointerTypeIdInIdx)); + continue; + } + + if (item->opcode() == spv::Op::OpTypeMatrix || + item->opcode() == spv::Op::OpTypeVector || + item->opcode() == spv::Op::OpTypeArray || + item->opcode() == spv::Op::OpTypeRuntimeArray) { + instructions_to_visit.push( + item->GetSingleWordInOperand(kTypeArrayTypeIndex)); + continue; + } + + if (item->opcode() == spv::Op::OpTypeStruct) { + item->ForEachInOperand([&instructions_to_visit](const uint32_t* op_id) { + instructions_to_visit.push(*op_id); + }); + continue; + } + + if (item->opcode() != spv::Op::OpTypeInt && + item->opcode() != spv::Op::OpTypeFloat) { + continue; + } + + if (item->GetSingleWordInOperand(kOpTypeScalarBitWidthIndex) == 16) { + return spv::Capability::StorageInputOutput16; + } + } + + return std::nullopt; +} + +// Opcode of interest to determine capabilities requirements. +constexpr std::array, 1> kOpcodeHandlers{{ + {spv::Op::OpVariable, Handler_OpVariable_StorageInputOutput16}, +}}; + +// ============== End opcode handler implementations. ======================= + +namespace { +ExtensionSet getExtensionsRelatedTo(const CapabilitySet& capabilities, + const AssemblyGrammar& grammar) { + ExtensionSet output; + const spv_operand_desc_t* desc = nullptr; + for (auto capability : capabilities) { + if (SPV_SUCCESS != grammar.lookupOperand(SPV_OPERAND_TYPE_CAPABILITY, + static_cast(capability), + &desc)) { + continue; + } + + for (uint32_t i = 0; i < desc->numExtensions; ++i) { + output.insert(desc->extensions[i]); + } + } + + return output; +} +} // namespace + +TrimCapabilitiesPass::TrimCapabilitiesPass() + : supportedCapabilities_( + TrimCapabilitiesPass::kSupportedCapabilities.cbegin(), + TrimCapabilitiesPass::kSupportedCapabilities.cend()), + forbiddenCapabilities_( + TrimCapabilitiesPass::kForbiddenCapabilities.cbegin(), + TrimCapabilitiesPass::kForbiddenCapabilities.cend()), + untouchableCapabilities_( + TrimCapabilitiesPass::kUntouchableCapabilities.cbegin(), + TrimCapabilitiesPass::kUntouchableCapabilities.cend()), + opcodeHandlers_(kOpcodeHandlers.cbegin(), kOpcodeHandlers.cend()) {} + +void TrimCapabilitiesPass::addInstructionRequirements( + Instruction* instruction, CapabilitySet* capabilities, + ExtensionSet* extensions) const { + // Ignoring OpCapability instructions. + if (instruction->opcode() == spv::Op::OpCapability) { + return; + } + + // First case: the opcode is itself gated by a capability. + { + const spv_opcode_desc_t* desc = {}; + auto result = + context()->grammar().lookupOpcode(instruction->opcode(), &desc); + if (result == SPV_SUCCESS) { + addSupportedCapabilitiesToSet(desc->numCapabilities, desc->capabilities, + capabilities); + if (desc->minVersion <= + spvVersionForTargetEnv(context()->GetTargetEnv())) { + extensions->insert(desc->extensions, + desc->extensions + desc->numExtensions); + } + } + } + + // 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. + if (operand.type == SPV_OPERAND_TYPE_LITERAL_STRING) { + continue; + } + + const spv_operand_desc_t* desc = {}; + auto result = context()->grammar().lookupOperand(operand.type, + operand.words[0], &desc); + if (result != SPV_SUCCESS) { + continue; + } + + addSupportedCapabilitiesToSet(desc->numCapabilities, desc->capabilities, + capabilities); + if (desc->minVersion <= spvVersionForTargetEnv(context()->GetTargetEnv())) { + extensions->insert(desc->extensions, + desc->extensions + desc->numExtensions); + } + } + + // Last case: some complex logic needs to be run to determine capabilities. + auto[begin, end] = opcodeHandlers_.equal_range(instruction->opcode()); + for (auto it = begin; it != end; it++) { + const OpcodeHandler handler = it->second; + auto result = handler(instruction); + if (result.has_value()) { + capabilities->insert(*result); + } + } +} + +std::pair +TrimCapabilitiesPass::DetermineRequiredCapabilitiesAndExtensions() const { + CapabilitySet required_capabilities; + ExtensionSet required_extensions; + + get_module()->ForEachInst([&](Instruction* instruction) { + addInstructionRequirements(instruction, &required_capabilities, + &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 + // API users to quickly determine if they can use the pass or not. But this + // list has to remain up-to-date with the pass code. If we can detect a + // capability as required, but it's not listed, it means the list is + // out-of-sync. This method is not ideal, but should cover most cases. + { + for (auto capability : required_capabilities) { + assert(supportedCapabilities_.contains(capability) && + "Module is using a capability that is not listed as supported."); + } + } +#endif + + return std::make_pair(std::move(required_capabilities), + std::move(required_extensions)); +} + +Pass::Status TrimCapabilitiesPass::TrimUnrequiredCapabilities( + const CapabilitySet& required_capabilities) const { + 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; + } + + // If the capability is unsupported, don't trim it. + if (!supportedCapabilities_.contains(capability)) { + continue; + } + + if (required_capabilities.contains(capability)) { + continue; + } + + capabilities_to_trim.insert(capability); + } + + for (auto capability : capabilities_to_trim) { + context()->RemoveCapability(capability); + } + + return capabilities_to_trim.size() == 0 ? Pass::Status::SuccessWithoutChange + : Pass::Status::SuccessWithChange; +} + +Pass::Status TrimCapabilitiesPass::TrimUnrequiredExtensions( + const ExtensionSet& required_extensions) const { + const auto supported_extensions = + getExtensionsRelatedTo(supportedCapabilities_, context()->grammar()); + + bool modified_module = false; + for (auto extension : supported_extensions) { + if (!required_extensions.contains(extension)) { + modified_module = true; + context()->RemoveExtension(extension); + } + } + + return modified_module ? Pass::Status::SuccessWithChange + : Pass::Status::SuccessWithoutChange; +} + +Pass::Status TrimCapabilitiesPass::Process() { + 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); +} + +} // namespace opt +} // namespace spvtools diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h new file mode 100644 index 0000000000..6f188c96bd --- /dev/null +++ b/source/opt/trim_capabilities_pass.h @@ -0,0 +1,151 @@ +// 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_TRIM_CAPABILITIES_PASS_H_ +#define SOURCE_OPT_TRIM_CAPABILITIES_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" + +namespace spvtools { +namespace opt { + +// This is required for NDK build. The unordered_set/unordered_map +// implementation don't work with class enums. +struct ClassEnumHash { + std::size_t operator()(spv::Capability value) const { + using StoringType = typename std::underlying_type_t; + return std::hash{}(static_cast(value)); + } + + std::size_t operator()(spv::Op value) const { + using StoringType = typename std::underlying_type_t; + return std::hash{}(static_cast(value)); + } +}; + +// An opcode handler is a function which, given an instruction, returns either +// the required capability, or nothing. +// Each handler checks one case for a capability requirement. +// +// Example: +// - `OpTypeImage` can have operand `A` operand which requires capability 1 +// - `OpTypeImage` can also have operand `B` which requires capability 2. +// -> We have 2 handlers: `Handler_OpTypeImage_1` and +// `Handler_OpTypeImage_2`. +using OpcodeHandler = + std::optional (*)(const Instruction* instruction); + +// This pass tried to remove superfluous capabilities declared in the module. +// - If all the capabilities listed by an extension are removed, the extension +// is also trimmed. +// - If the module countains any capability listed in `kForbiddenCapabilities`, +// the module is left untouched. +// - No capabilities listed in `kUntouchableCapabilities` are trimmed, even when +// not used. +// - Only capabilitied listed in `kSupportedCapabilities` are supported. +// - If the module contains unsupported capabilities, results might be +// incorrect. +class TrimCapabilitiesPass : public Pass { + private: + // All the capabilities supported by this optimization pass. If your module + // contains unsupported instruction, the pass could yield bad results. + static constexpr std::array kSupportedCapabilities{ + // clang-format off + spv::Capability::Groups, + spv::Capability::Linkage, + spv::Capability::MinLod, + spv::Capability::Shader, + spv::Capability::ShaderClockKHR, + spv::Capability::StorageInputOutput16 + // clang-format on + }; + + // Those capabilities disable all transformation of the module. + static constexpr std::array kForbiddenCapabilities{ + spv::Capability::Linkage, + }; + + // Those capabilities are never removed from a module because we cannot + // guess from the SPIR-V only if they are required or not. + static constexpr std::array kUntouchableCapabilities{ + spv::Capability::Shader, + }; + + public: + TrimCapabilitiesPass(); + TrimCapabilitiesPass(const TrimCapabilitiesPass&) = delete; + 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 { + for (uint32_t i = 0; i < capabilityCount; ++i) { + if (supportedCapabilities_.contains(capabilities[i])) { + output->insert(capabilities[i]); + } + } + } + + // 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. + void addInstructionRequirements(Instruction* instruction, + CapabilitySet* capabilities, + ExtensionSet* extensions) const; + + // Returns the list of required capabilities and extensions for the module. + // The returned capabilities form a subset of kSupportedCapabilities. + std::pair + DetermineRequiredCapabilitiesAndExtensions() const; + + // Trims capabilities not listed in `required_capabilities` if possible. + // Returns whether or not the module was modified. + Pass::Status TrimUnrequiredCapabilities( + const CapabilitySet& required_capabilities) const; + + // Trims extensions not listed in `required_extensions` if supported by this + // pass. An extensions is considered supported as soon as one capability this + // pass support requires it. + Pass::Status TrimUnrequiredExtensions( + const ExtensionSet& required_extensions) const; + + public: + const char* name() const override { return "trim-capabilities"; } + Status Process() override; + + private: + const CapabilitySet supportedCapabilities_; + const CapabilitySet forbiddenCapabilities_; + const CapabilitySet untouchableCapabilities_; + const std::unordered_multimap + opcodeHandlers_; +}; + +} // namespace opt +} // namespace spvtools +#endif // SOURCE_OPT_TRIM_CAPABILITIES_H_ diff --git a/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt index 37b145d66c..432a17d092 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 + trim_capabilities_pass_test.cpp type_manager_test.cpp types_test.cpp unify_const_test.cpp diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp new file mode 100644 index 0000000000..83a8943645 --- /dev/null +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -0,0 +1,746 @@ +// 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 TrimCapabilitiesPassTest = PassTest<::testing::Test>; + +TEST_F(TrimCapabilitiesPassTest, CheckKnownAliasTransformations) { + // Those are expected changes caused by the test process: + // - SPV is assembled. -> capability goes from text to number. + // - SPV is optimized. + // - SPV is disassembled -> capability goes from number to text. + // - CHECK rule compares both text versions. + // Because some capabilities share the same number (aliases), the text + // compared with the CHECK rules depends on which alias is the first on the + // SPIRV-Headers enum. This could change, and we want to easily distinguish + // real failure from alias order change. This test is only here to list known + // alias transformations. If this test breaks, it's not a bug in the + // optimization pass, but just the SPIRV-Headers enum order that has changed. + // If that happens, tests needs to be updated to the correct alias is used in + // the CHECK rule. + const std::string kTest = R"( + OpCapability Linkage + OpCapability StorageUniform16 + OpCapability StorageUniformBufferBlock16 + OpCapability ShaderViewportIndexLayerNV + OpCapability FragmentBarycentricNV + OpCapability ShadingRateNV + OpCapability ShaderNonUniformEXT + OpCapability RuntimeDescriptorArrayEXT + OpCapability InputAttachmentArrayDynamicIndexingEXT + OpCapability UniformTexelBufferArrayDynamicIndexingEXT + OpCapability StorageTexelBufferArrayDynamicIndexingEXT + OpCapability UniformBufferArrayNonUniformIndexingEXT + OpCapability SampledImageArrayNonUniformIndexingEXT + OpCapability StorageBufferArrayNonUniformIndexingEXT + OpCapability StorageImageArrayNonUniformIndexingEXT + OpCapability InputAttachmentArrayNonUniformIndexingEXT + OpCapability UniformTexelBufferArrayNonUniformIndexingEXT + OpCapability StorageTexelBufferArrayNonUniformIndexingEXT + OpCapability VulkanMemoryModelKHR + OpCapability VulkanMemoryModelDeviceScopeKHR + OpCapability PhysicalStorageBufferAddressesEXT + OpCapability DemoteToHelperInvocationEXT + OpCapability DotProductInputAllKHR + OpCapability DotProductInput4x8BitKHR + OpCapability DotProductInput4x8BitPackedKHR + OpCapability DotProductKHR +; CHECK: OpCapability Linkage +; CHECK-NOT: OpCapability StorageUniform16 +; CHECK-NOT: OpCapability StorageUniformBufferBlock16 +; CHECK-NOT: OpCapability ShaderViewportIndexLayerNV +; CHECK-NOT: OpCapability FragmentBarycentricNV +; CHECK-NOT: OpCapability ShadingRateNV +; CHECK-NOT: OpCapability ShaderNonUniformEXT +; CHECK-NOT: OpCapability RuntimeDescriptorArrayEXT +; CHECK-NOT: OpCapability InputAttachmentArrayDynamicIndexingEXT +; CHECK-NOT: OpCapability UniformTexelBufferArrayDynamicIndexingEXT +; CHECK-NOT: OpCapability StorageTexelBufferArrayDynamicIndexingEXT +; CHECK-NOT: OpCapability UniformBufferArrayNonUniformIndexingEXT +; CHECK-NOT: OpCapability SampledImageArrayNonUniformIndexingEXT +; CHECK-NOT: OpCapability StorageBufferArrayNonUniformIndexingEXT +; CHECK-NOT: OpCapability StorageImageArrayNonUniformIndexingEXT +; CHECK-NOT: OpCapability InputAttachmentArrayNonUniformIndexingEXT +; CHECK-NOT: OpCapability UniformTexelBufferArrayNonUniformIndexingEXT +; CHECK-NOT: OpCapability StorageTexelBufferArrayNonUniformIndexingEXT +; CHECK-NOT: OpCapability VulkanMemoryModelKHR +; CHECK-NOT: OpCapability VulkanMemoryModelDeviceScopeKHR +; CHECK-NOT: OpCapability PhysicalStorageBufferAddressesEXT +; CHECK-NOT: OpCapability DemoteToHelperInvocationEXT +; CHECK-NOT: OpCapability DotProductInputAllKHR +; CHECK-NOT: OpCapability DotProductInput4x8BitKHR +; CHECK-NOT: OpCapability DotProductInput4x8BitPackedKHR +; CHECK-NOT: OpCapability DotProductKHR +; CHECK: OpCapability UniformAndStorageBuffer16BitAccess +; CHECK: OpCapability StorageBuffer16BitAccess +; CHECK: OpCapability ShaderViewportIndexLayerEXT +; CHECK: OpCapability FragmentBarycentricKHR +; CHECK: OpCapability FragmentDensityEXT +; CHECK: OpCapability ShaderNonUniform +; CHECK: OpCapability RuntimeDescriptorArray +; CHECK: OpCapability InputAttachmentArrayDynamicIndexing +; CHECK: OpCapability UniformTexelBufferArrayDynamicIndexing +; CHECK: OpCapability StorageTexelBufferArrayDynamicIndexing +; CHECK: OpCapability UniformBufferArrayNonUniformIndexing +; CHECK: OpCapability SampledImageArrayNonUniformIndexing +; CHECK: OpCapability StorageBufferArrayNonUniformIndexing +; CHECK: OpCapability StorageImageArrayNonUniformIndexing +; CHECK: OpCapability InputAttachmentArrayNonUniformIndexing +; CHECK: OpCapability UniformTexelBufferArrayNonUniformIndexing +; CHECK: OpCapability StorageTexelBufferArrayNonUniformIndexing +; CHECK: OpCapability VulkanMemoryModel +; CHECK: OpCapability VulkanMemoryModelDeviceScope +; CHECK: OpCapability PhysicalStorageBufferAddresses +; CHECK: OpCapability DemoteToHelperInvocation +; CHECK: OpCapability DotProductInputAll +; CHECK: OpCapability DotProductInput4x8Bit +; CHECK: OpCapability DotProductInput4x8BitPacked +; CHECK: OpCapability DotProduct + OpMemoryModel Logical Vulkan + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %3 = OpTypeFunction %void + %1 = OpFunction %void None %3 + %6 = OpLabel + OpReturn + OpFunctionEnd; + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_3); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, LinkagePreventsChanges) { + const std::string kTest = R"( + OpCapability Linkage + OpCapability ClipDistance + OpCapability CullDistance + OpCapability DemoteToHelperInvocation + OpCapability DeviceGroup + OpCapability DrawParameters + OpCapability Float16 + OpCapability Float64 + OpCapability FragmentBarycentricKHR + OpCapability FragmentFullyCoveredEXT + OpCapability FragmentShadingRateKHR + OpCapability GroupNonUniform + OpCapability GroupNonUniformArithmetic + OpCapability GroupNonUniformBallot + OpCapability GroupNonUniformQuad + OpCapability GroupNonUniformShuffle + OpCapability Image1D + OpCapability ImageBuffer + OpCapability ImageGatherExtended + OpCapability ImageMSArray + OpCapability ImageQuery + OpCapability InputAttachment + OpCapability InputAttachmentArrayNonUniformIndexing + OpCapability Int16 + OpCapability Int64 + OpCapability Int64Atomics + OpCapability Int64ImageEXT + OpCapability MeshShadingNV + OpCapability MinLod + OpCapability MultiView + OpCapability MultiViewport + OpCapability PhysicalStorageBufferAddresses + OpCapability RayQueryKHR + OpCapability RayTracingKHR + OpCapability RayTracingNV + OpCapability RayTraversalPrimitiveCullingKHR + OpCapability RuntimeDescriptorArray + OpCapability SampleMaskPostDepthCoverage + OpCapability SampleRateShading + OpCapability Sampled1D + OpCapability SampledBuffer + OpCapability SampledImageArrayNonUniformIndexing + OpCapability Shader + OpCapability ShaderClockKHR + OpCapability ShaderLayer + OpCapability ShaderNonUniform + OpCapability ShaderViewportIndex + OpCapability ShaderViewportIndexLayerEXT + OpCapability SparseResidency + OpCapability StencilExportEXT + OpCapability StorageImageArrayNonUniformIndexingEXT + OpCapability StorageImageExtendedFormats + OpCapability StorageImageReadWithoutFormat + OpCapability StorageImageWriteWithoutFormat + OpCapability StorageInputOutput16 + OpCapability StoragePushConstant16 + OpCapability StorageTexelBufferArrayNonUniformIndexing + OpCapability StorageUniform16 + OpCapability StorageUniformBufferBlock16 + OpCapability Tessellation + OpCapability UniformTexelBufferArrayNonUniformIndexing + OpCapability VulkanMemoryModel + OpExtension "SPV_EXT_fragment_fully_covered" + OpExtension "SPV_EXT_shader_image_int64" + OpExtension "SPV_EXT_shader_stencil_export" + OpExtension "SPV_EXT_shader_viewport_index_layer" + OpExtension "SPV_KHR_fragment_shader_barycentric" + OpExtension "SPV_KHR_fragment_shading_rate" + OpExtension "SPV_KHR_post_depth_coverage" + OpExtension "SPV_KHR_ray_query" + OpExtension "SPV_KHR_ray_tracing" + OpExtension "SPV_KHR_shader_clock" + OpExtension "SPV_NV_mesh_shader" + OpExtension "SPV_NV_ray_tracing" + OpExtension "SPV_NV_viewport_array2" +; CHECK: OpCapability Linkage +; CHECK: OpCapability ClipDistance +; CHECK: OpCapability CullDistance +; CHECK: OpCapability DemoteToHelperInvocation +; CHECK: OpCapability DeviceGroup +; CHECK: OpCapability DrawParameters +; CHECK: OpCapability Float16 +; CHECK: OpCapability Float64 +; CHECK: OpCapability FragmentBarycentricKHR +; CHECK: OpCapability FragmentFullyCoveredEXT +; CHECK: OpCapability FragmentShadingRateKHR +; CHECK: OpCapability GroupNonUniform +; CHECK: OpCapability GroupNonUniformArithmetic +; CHECK: OpCapability GroupNonUniformBallot +; CHECK: OpCapability GroupNonUniformQuad +; CHECK: OpCapability GroupNonUniformShuffle +; CHECK: OpCapability Image1D +; CHECK: OpCapability ImageBuffer +; CHECK: OpCapability ImageGatherExtended +; CHECK: OpCapability ImageMSArray +; CHECK: OpCapability ImageQuery +; CHECK: OpCapability InputAttachment +; CHECK: OpCapability InputAttachmentArrayNonUniformIndexing +; CHECK: OpCapability Int16 +; CHECK: OpCapability Int64 +; CHECK: OpCapability Int64Atomics +; CHECK: OpCapability Int64ImageEXT +; CHECK: OpCapability MeshShadingNV +; CHECK: OpCapability MinLod +; CHECK: OpCapability MultiView +; CHECK: OpCapability MultiViewport +; CHECK: OpCapability PhysicalStorageBufferAddresses +; CHECK: OpCapability RayQueryKHR +; CHECK: OpCapability RayTracingKHR +; CHECK: OpCapability RayTracingNV +; CHECK: OpCapability RayTraversalPrimitiveCullingKHR +; CHECK: OpCapability RuntimeDescriptorArray +; CHECK: OpCapability SampleMaskPostDepthCoverage +; CHECK: OpCapability SampleRateShading +; CHECK: OpCapability Sampled1D +; CHECK: OpCapability SampledBuffer +; CHECK: OpCapability SampledImageArrayNonUniformIndexing +; CHECK: OpCapability Shader +; CHECK: OpCapability ShaderClockKHR +; CHECK: OpCapability ShaderLayer +; CHECK: OpCapability ShaderNonUniform +; CHECK: OpCapability ShaderViewportIndex +; CHECK: OpCapability ShaderViewportIndexLayerEXT +; CHECK: OpCapability SparseResidency +; CHECK: OpCapability StencilExportEXT +; CHECK: OpCapability StorageImageArrayNonUniformIndexing +; CHECK: OpCapability StorageImageExtendedFormats +; CHECK: OpCapability StorageImageReadWithoutFormat +; CHECK: OpCapability StorageImageWriteWithoutFormat +; CHECK: OpCapability StorageInputOutput16 +; CHECK: OpCapability StoragePushConstant16 +; CHECK: OpCapability StorageTexelBufferArrayNonUniformIndexing +; CHECK: OpCapability Tessellation +; CHECK: OpCapability UniformTexelBufferArrayNonUniformIndex +; CHECK: OpCapability VulkanMemoryModel +; CHECK: OpExtension "SPV_EXT_fragment_fully_covered" +; CHECK: OpExtension "SPV_EXT_shader_image_int64" +; CHECK: OpExtension "SPV_EXT_shader_stencil_export" +; CHECK: OpExtension "SPV_EXT_shader_viewport_index_layer" +; CHECK: OpExtension "SPV_KHR_fragment_shader_barycentric" +; CHECK: OpExtension "SPV_KHR_fragment_shading_rate" +; CHECK: OpExtension "SPV_KHR_post_depth_coverage" +; CHECK: OpExtension "SPV_KHR_ray_query" +; CHECK: OpExtension "SPV_KHR_ray_tracing" +; CHECK: OpExtension "SPV_KHR_shader_clock" +; CHECK: OpExtension "SPV_NV_mesh_shader" +; CHECK: OpExtension "SPV_NV_ray_tracing" +; CHECK: OpExtension "SPV_NV_viewport_array2" + OpMemoryModel Logical Vulkan + %void = OpTypeVoid + %3 = OpTypeFunction %void + %1 = OpFunction %void None %3 + %6 = OpLabel + OpReturn + OpFunctionEnd; + )"; + SetTargetEnv(SPV_ENV_VULKAN_1_3); + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, KeepShader) { + const std::string kTest = R"( + OpCapability Shader +; CHECK: 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::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, KeepShaderClockWhenInUse) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Int64 + OpCapability ShaderClockKHR + OpExtension "SPV_KHR_shader_clock" +; CHECK: OpCapability ShaderClockKHR +; CHECK: OpExtension "SPV_KHR_shader_clock" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %ulong = OpTypeInt 64 0 + %scope = OpConstant %uint 1 + %3 = OpTypeFunction %void + %1 = OpFunction %void None %3 + %6 = OpLabel + %7 = OpReadClockKHR %ulong %scope + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, TrimShaderClockWhenUnused) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Int64 + OpCapability ShaderClockKHR + OpExtension "SPV_KHR_shader_clock" +; CHECK-NOT: OpCapability ShaderClockKHR +; CHECK-NOT: OpExtension "SPV_KHR_shader_clock" + 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, AMDShaderBallotExtensionRemains) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Groups + OpExtension "SPV_AMD_shader_ballot" +; CHECK: OpCapability Groups +; CHECK: OpExtension "SPV_AMD_shader_ballot" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %1 = OpTypeFunction %void + %uint_0 = OpConstant %uint 0 + %2 = OpFunction %void None %1 + %3 = OpLabel + %4 = OpGroupIAddNonUniformAMD %uint %uint_0 ExclusiveScan %uint_0 + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, AMDShaderBallotExtensionRemoved) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Groups + OpExtension "SPV_AMD_shader_ballot" +; CHECK-NOT: OpCapability Groups +; CHECK-NOT: OpExtension "SPV_AMD_shader_ballot" + 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, MinLodCapabilityRemoved) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Sampled1D + OpCapability MinLod +; CHECK-NOT: OpCapability MinLod + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %float = OpTypeFloat 32 + %v3float = OpTypeVector %float 3 + %v4float = OpTypeVector %float 4 + %type_image = OpTypeImage %float Cube 2 0 0 1 Rgba32f + %ptr_type_image = OpTypePointer UniformConstant %type_image + %type_sampler = OpTypeSampler + %ptr_type_sampler = OpTypePointer UniformConstant %type_sampler + %float_0 = OpConstant %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 = OpImageSampleImplicitLod %v4float %24 %float_000 + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, MinLodCapabilityRemains) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Sampled1D + OpCapability MinLod +; CHECK: OpCapability MinLod + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %float = OpTypeFloat 32 + %v3float = OpTypeVector %float 3 + %v4float = OpTypeVector %float 4 + %type_image = OpTypeImage %float Cube 2 0 0 1 Rgba32f + %ptr_type_image = OpTypePointer UniformConstant %type_image + %type_sampler = OpTypeSampler + %ptr_type_sampler = OpTypePointer UniformConstant %type_sampler + %float_0 = OpConstant %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 = OpImageSampleImplicitLod %v4float %24 %float_000 MinLod %float_0 + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, StorageInputOutput16RemainsWithInputVariable) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 +; CHECK: OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" %input_var + OpDecorate %input_var BuiltIn LocalInvocationIndex + %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 + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16RemainsWithInputVariableArray) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 +; CHECK: OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" %input_var + OpDecorate %input_var BuiltIn LocalInvocationIndex + %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 + %input_var = OpVariable %ptr Input + %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::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16RemainsWithInputVariableStruct) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 +; CHECK: OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" %input_var + OpDecorate %input_var BuiltIn LocalInvocationIndex + %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 + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16RemainsWithInputVariableStructOfStruct) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 +; CHECK: OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" %input_var + OpDecorate %input_var BuiltIn LocalInvocationIndex + %void = OpTypeVoid + %half = OpTypeFloat 16 + %float = OpTypeFloat 32 + %struct = OpTypeStruct %float %half + %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 + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16RemainsWithInputVariableArrayOfStruct) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 +; CHECK: OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" %input_var + OpDecorate %input_var BuiltIn LocalInvocationIndex + %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 + %input_var = OpVariable %ptr Input + %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::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16RemainsWithInputVariableVector) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 +; CHECK: OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" %input_var + OpDecorate %input_var BuiltIn LocalInvocationIndex + %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 + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16RemainsWithInputVariableMatrix) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 +; CHECK: OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" %input_var + OpDecorate %input_var BuiltIn LocalInvocationIndex + %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 + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16IsRemovedWithoutInputVariable) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 +; CHECK-NOT: OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" %input_var + OpDecorate %input_var BuiltIn LocalInvocationIndex + %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, + StorageInputOutput16RemainsWithOutputVariable) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 +; CHECK: OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" %input_var + OpDecorate %input_var BuiltIn LocalInvocationIndex + %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 + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, + StorageInputOutput16IsRemovedWithoutOutputVariable) { + const std::string kTest = R"( + OpCapability Shader + OpCapability Float16 + OpCapability StorageInputOutput16 +; CHECK-NOT: OpCapability StorageInputOutput16 + OpExtension "SPV_KHR_16bit_storage" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" %input_var + OpDecorate %input_var BuiltIn LocalInvocationIndex + %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); +} + +} // namespace +} // namespace opt +} // namespace spvtools From a0f1c87272a738874c13ccad7c57b9d0a5072e33 Mon Sep 17 00:00:00 2001 From: ncesario-lunarg <71668273+ncesario-lunarg@users.noreply.github.com> Date: Wed, 26 Jul 2023 08:03:24 -0600 Subject: [PATCH 236/523] opt: Fix incorrect half float conversion (#5349) Fixes image operands not decorated as relaxed from getting marked relaxed and converted to half precision. Fixes #5044. --- source/opt/convert_to_half_pass.cpp | 7 +- source/opt/convert_to_half_pass.h | 9 +- test/opt/convert_relaxed_to_half_test.cpp | 100 ++++++++++++++++++++++ 3 files changed, 112 insertions(+), 4 deletions(-) diff --git a/source/opt/convert_to_half_pass.cpp b/source/opt/convert_to_half_pass.cpp index 2c4a631e17..cb0065d2d3 100644 --- a/source/opt/convert_to_half_pass.cpp +++ b/source/opt/convert_to_half_pass.cpp @@ -63,6 +63,10 @@ bool ConvertToHalfPass::IsRelaxed(uint32_t id) { void ConvertToHalfPass::AddRelaxed(uint32_t id) { relaxed_ids_set_.insert(id); } +bool ConvertToHalfPass::CanRelaxOpOperands(Instruction* inst) { + return image_ops_.count(inst->opcode()) == 0; +} + analysis::Type* ConvertToHalfPass::FloatScalarType(uint32_t width) { analysis::Float float_ty(width); return context()->get_type_mgr()->GetRegisteredType(&float_ty); @@ -313,7 +317,8 @@ bool ConvertToHalfPass::CloseRelaxInst(Instruction* inst) { relax = true; get_def_use_mgr()->ForEachUser(inst, [&relax, this](Instruction* uinst) { if (uinst->result_id() == 0 || !IsFloat(uinst, 32) || - (!IsDecoratedRelaxed(uinst) && !IsRelaxed(uinst->result_id()))) { + (!IsDecoratedRelaxed(uinst) && !IsRelaxed(uinst->result_id())) || + !CanRelaxOpOperands(uinst)) { relax = false; return; } diff --git a/source/opt/convert_to_half_pass.h b/source/opt/convert_to_half_pass.h index 24a478ffc6..8e10c4fb95 100644 --- a/source/opt/convert_to_half_pass.h +++ b/source/opt/convert_to_half_pass.h @@ -56,6 +56,9 @@ class ConvertToHalfPass : public Pass { // Add |id| to the relaxed id set void AddRelaxed(uint32_t id); + // Return true if the instruction's operands can be relaxed + bool CanRelaxOpOperands(Instruction* inst); + // Return type id for float with |width| analysis::Type* FloatScalarType(uint32_t width); @@ -133,13 +136,13 @@ class ConvertToHalfPass : public Pass { // Set of 450 extension operations to be processed std::unordered_set target_ops_450_; - // Set of sample operations + // Set of all sample operations, including dref and non-dref operations std::unordered_set image_ops_; - // Set of dref sample operations + // Set of only dref sample operations std::unordered_set dref_image_ops_; - // Set of dref sample operations + // Set of operations that can be marked as relaxed std::unordered_set closure_ops_; // Set of ids of all relaxed instructions diff --git a/test/opt/convert_relaxed_to_half_test.cpp b/test/opt/convert_relaxed_to_half_test.cpp index 27330e109a..62b9ae4535 100644 --- a/test/opt/convert_relaxed_to_half_test.cpp +++ b/test/opt/convert_relaxed_to_half_test.cpp @@ -1613,6 +1613,106 @@ OpFunctionEnd SinglePassRunAndCheck(test, test, true); } +TEST_F(ConvertToHalfTest, PreserveImageOperandPrecision) { + // Ensure that a non-relaxed texture coordinate does not get relaxed nor + // converted to half precision if the image instruction is marked relaxed. + + // Also ensure that a relaxed local variable does get converted to half + // precision before being passed to an image opeartor. + + // #version 310 es + // + // precision mediump float; + // + // layout(location = 10) in highp vec4 vertex_uv01; + // layout(binding = 0, set = 3) uniform sampler2D materialParams_baseColorMap; + // + // layout(location = 0) out vec4 fragColor; + // + // void main() { + // vec4 uv = vec4(2.0); + // fragColor = texture(materialParams_baseColorMap, uv.xy); + // fragColor = texture(materialParams_baseColorMap, vertex_uv01.xy); + // } + const std::string test = R"( + OpCapability Shader + OpCapability Float16 + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %13 %25 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpDecorate %9 RelaxedPrecision +;CHECK: OpDecorate [[uv:%\w+]] RelaxedPrecision + OpDecorate %13 Location 0 + OpDecorate %17 DescriptorSet 3 + OpDecorate %17 Binding 0 + OpDecorate %18 RelaxedPrecision + OpDecorate %23 RelaxedPrecision + OpDecorate %25 Location 10 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 +;CHECK: [[float32_t:%\w+]] = OpTypeFloat 32 + %7 = OpTypeVector %6 4 +;CHECK: [[vec4_t:%\w+]] = OpTypeVector [[float32_t]] 4 + %8 = OpTypePointer Function %7 + %10 = OpConstant %6 2 + %11 = OpConstantComposite %7 %10 %10 %10 %10 + %12 = OpTypePointer Output %7 +;CHECK: [[output_ptr_t:%\w+]] = OpTypePointer Output [[vec4_t]] + %13 = OpVariable %12 Output +;CHECK: [[output:%\w+]] = OpVariable [[output_ptr_t]] Output + %14 = OpTypeImage %6 2D 0 0 0 1 Unknown + %15 = OpTypeSampledImage %14 + %16 = OpTypePointer UniformConstant %15 + %17 = OpVariable %16 UniformConstant + %19 = OpTypeVector %6 2 +;CHECK: [[vec2_t:%\w+]] = OpTypeVector [[float32_t]] 2 + %24 = OpTypePointer Input %7 +;CHECK: [[input_ptr_t:%\w+]] = OpTypePointer Input [[vec4_t]] + %25 = OpVariable %24 Input + %29 = OpTypeFloat 16 +;CHECK: [[float16_t:%\w+]] = OpTypeFloat 16 + %30 = OpTypeVector %29 4 + %33 = OpTypeVector %29 2 +;CHECK: [[vec2_16b_t:%\w+]] = OpTypeVector [[float16_t]] 2 + %4 = OpFunction %2 None %3 + %5 = OpLabel + +; The only Function storage variable is marked as relaxed + %9 = OpVariable %8 Function +;CHECK: [[uv]] = OpVariable {{%\w+}} Function + OpStore %9 %11 + %18 = OpLoad %15 %17 + %20 = OpLoad %7 %9 + %31 = OpFConvert %30 %20 + %32 = OpFConvert %30 %20 + +; The first sample op should get a 16b coordinate + %21 = OpVectorShuffle %33 %31 %32 0 1 +;CHECK: [[uv_16b:%\w+]] = OpVectorShuffle [[vec2_16b_t]] + %22 = OpImageSampleImplicitLod %7 %18 %21 +;CHECK: OpImageSampleImplicitLod [[vec4_t]] {{%\w+}} [[uv_16b]] + + OpStore %13 %22 + %23 = OpLoad %15 %17 + %26 = OpLoad %7 %25 + +; The second sample op should get a 32b coordinate + %27 = OpVectorShuffle %19 %26 %26 0 1 +;CHECK: [[uv_32b:%\w+]] = OpVectorShuffle [[vec2_t]] + %28 = OpImageSampleImplicitLod %7 %23 %27 +;CHECK: OpImageSampleImplicitLod [[vec4_t]] {{%\w+}} [[uv_32b]] + + OpStore %13 %28 + OpReturn + OpFunctionEnd + )"; + + SinglePassRunAndMatch(test, true); +} + } // namespace } // namespace opt } // namespace spvtools From b5f600c08cc9d900c7450ecba3689ef45fa20d6d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 26 Jul 2023 11:07:23 -0400 Subject: [PATCH 237/523] Roll external/googletest/ 01e18376e..40412d851 (1 commit) (#5347) https://github.com/google/googletest/compare/01e18376efe6...40412d85124f $ git log 01e18376e..40412d851 --date=short --no-merges --format='%ad %ae %s' 2023-07-19 antsosnin Fix typo in gmock_cook_book.md 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 ae4d50b69e..f508b58530 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '01e18376efe643a82cff468734f87f8c60e314b6', + 'googletest_revision': '40412d85124f7c6f3d88454583c4633e5e10fc8c', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From c6d0b04802d3fa1b235fd5255b7769f4c22fd246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 27 Jul 2023 17:21:23 +0200 Subject: [PATCH 238/523] build: fix missing files in BUILD.gn (#5351) PR #5278 added 2 new files, but they were not added to the BUILD.gn file. Same fix for Android.mk. Fixes #5350 --- Android.mk | 1 + BUILD.gn | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Android.mk b/Android.mk index d2a8de5954..dcb8d63191 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/trim_capabilities_pass.cpp \ source/opt/type_manager.cpp \ source/opt/types.cpp \ source/opt/unify_const_pass.cpp \ diff --git a/BUILD.gn b/BUILD.gn index 44954b2df1..bc48e43b2a 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -790,6 +790,8 @@ static_library("spvtools_opt") { "source/opt/struct_cfg_analysis.cpp", "source/opt/struct_cfg_analysis.h", "source/opt/tree_iterator.h", + "source/opt/trim_capabilities_pass.cpp", + "source/opt/trim_capabilities_pass.h", "source/opt/type_manager.cpp", "source/opt/type_manager.h", "source/opt/types.cpp", From e68fe9be4e6ca63097ac4305d7552ad29afd5004 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 27 Jul 2023 16:04:50 -0700 Subject: [PATCH 239/523] Add SPV_EXT_shader_atomic_float_add to allow lists (#5348) Fixes #5346 --- source/opt/aggressive_dead_code_elim_pass.cpp | 1 + .../opt/local_access_chain_convert_pass.cpp | 2 +- source/opt/local_single_block_elim_pass.cpp | 111 +++++++++--------- source/opt/local_single_store_elim_pass.cpp | 105 ++++++++--------- 4 files changed, 109 insertions(+), 110 deletions(-) diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp index 3d08ec15e0..87324cdb13 100644 --- a/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/source/opt/aggressive_dead_code_elim_pass.cpp @@ -998,6 +998,7 @@ void AggressiveDCEPass::InitExtensions() { "SPV_KHR_uniform_group_instructions", "SPV_KHR_fragment_shader_barycentric", "SPV_NV_bindless_texture", + "SPV_EXT_shader_atomic_float_add", }); } diff --git a/source/opt/local_access_chain_convert_pass.cpp b/source/opt/local_access_chain_convert_pass.cpp index 81837ed15d..d024af60a8 100644 --- a/source/opt/local_access_chain_convert_pass.cpp +++ b/source/opt/local_access_chain_convert_pass.cpp @@ -427,7 +427,7 @@ 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_NV_bindless_texture", "SPV_EXT_shader_atomic_float_add"}); } bool LocalAccessChainConvertPass::AnyIndexIsOutOfBounds( diff --git a/source/opt/local_single_block_elim_pass.cpp b/source/opt/local_single_block_elim_pass.cpp index 77c9e2b1cd..5e524c4529 100644 --- a/source/opt/local_single_block_elim_pass.cpp +++ b/source/opt/local_single_block_elim_pass.cpp @@ -233,62 +233,61 @@ Pass::Status LocalSingleBlockLoadStoreElimPass::Process() { void LocalSingleBlockLoadStoreElimPass::InitExtensions() { extensions_allowlist_.clear(); - extensions_allowlist_.insert({ - "SPV_AMD_shader_explicit_vertex_parameter", - "SPV_AMD_shader_trinary_minmax", - "SPV_AMD_gcn_shader", - "SPV_KHR_shader_ballot", - "SPV_AMD_shader_ballot", - "SPV_AMD_gpu_shader_half_float", - "SPV_KHR_shader_draw_parameters", - "SPV_KHR_subgroup_vote", - "SPV_KHR_8bit_storage", - "SPV_KHR_16bit_storage", - "SPV_KHR_device_group", - "SPV_KHR_multiview", - "SPV_NVX_multiview_per_view_attributes", - "SPV_NV_viewport_array2", - "SPV_NV_stereo_view_rendering", - "SPV_NV_sample_mask_override_coverage", - "SPV_NV_geometry_shader_passthrough", - "SPV_AMD_texture_gather_bias_lod", - "SPV_KHR_storage_buffer_storage_class", - "SPV_KHR_variable_pointers", - "SPV_AMD_gpu_shader_int16", - "SPV_KHR_post_depth_coverage", - "SPV_KHR_shader_atomic_counter_ops", - "SPV_EXT_shader_stencil_export", - "SPV_EXT_shader_viewport_index_layer", - "SPV_AMD_shader_image_load_store_lod", - "SPV_AMD_shader_fragment_mask", - "SPV_EXT_fragment_fully_covered", - "SPV_AMD_gpu_shader_half_float_fetch", - "SPV_GOOGLE_decorate_string", - "SPV_GOOGLE_hlsl_functionality1", - "SPV_GOOGLE_user_type", - "SPV_NV_shader_subgroup_partitioned", - "SPV_EXT_demote_to_helper_invocation", - "SPV_EXT_descriptor_indexing", - "SPV_NV_fragment_shader_barycentric", - "SPV_NV_compute_shader_derivatives", - "SPV_NV_shader_image_footprint", - "SPV_NV_shading_rate", - "SPV_NV_mesh_shader", - "SPV_NV_ray_tracing", - "SPV_KHR_ray_tracing", - "SPV_KHR_ray_query", - "SPV_EXT_fragment_invocation_density", - "SPV_EXT_physical_storage_buffer", - "SPV_KHR_terminate_invocation", - "SPV_KHR_subgroup_uniform_control_flow", - "SPV_KHR_integer_dot_product", - "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", - }); + extensions_allowlist_.insert({"SPV_AMD_shader_explicit_vertex_parameter", + "SPV_AMD_shader_trinary_minmax", + "SPV_AMD_gcn_shader", + "SPV_KHR_shader_ballot", + "SPV_AMD_shader_ballot", + "SPV_AMD_gpu_shader_half_float", + "SPV_KHR_shader_draw_parameters", + "SPV_KHR_subgroup_vote", + "SPV_KHR_8bit_storage", + "SPV_KHR_16bit_storage", + "SPV_KHR_device_group", + "SPV_KHR_multiview", + "SPV_NVX_multiview_per_view_attributes", + "SPV_NV_viewport_array2", + "SPV_NV_stereo_view_rendering", + "SPV_NV_sample_mask_override_coverage", + "SPV_NV_geometry_shader_passthrough", + "SPV_AMD_texture_gather_bias_lod", + "SPV_KHR_storage_buffer_storage_class", + "SPV_KHR_variable_pointers", + "SPV_AMD_gpu_shader_int16", + "SPV_KHR_post_depth_coverage", + "SPV_KHR_shader_atomic_counter_ops", + "SPV_EXT_shader_stencil_export", + "SPV_EXT_shader_viewport_index_layer", + "SPV_AMD_shader_image_load_store_lod", + "SPV_AMD_shader_fragment_mask", + "SPV_EXT_fragment_fully_covered", + "SPV_AMD_gpu_shader_half_float_fetch", + "SPV_GOOGLE_decorate_string", + "SPV_GOOGLE_hlsl_functionality1", + "SPV_GOOGLE_user_type", + "SPV_NV_shader_subgroup_partitioned", + "SPV_EXT_demote_to_helper_invocation", + "SPV_EXT_descriptor_indexing", + "SPV_NV_fragment_shader_barycentric", + "SPV_NV_compute_shader_derivatives", + "SPV_NV_shader_image_footprint", + "SPV_NV_shading_rate", + "SPV_NV_mesh_shader", + "SPV_NV_ray_tracing", + "SPV_KHR_ray_tracing", + "SPV_KHR_ray_query", + "SPV_EXT_fragment_invocation_density", + "SPV_EXT_physical_storage_buffer", + "SPV_KHR_terminate_invocation", + "SPV_KHR_subgroup_uniform_control_flow", + "SPV_KHR_integer_dot_product", + "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"}); } } // namespace opt diff --git a/source/opt/local_single_store_elim_pass.cpp b/source/opt/local_single_store_elim_pass.cpp index e6a3f318b7..fefe2ce9e0 100644 --- a/source/opt/local_single_store_elim_pass.cpp +++ b/source/opt/local_single_store_elim_pass.cpp @@ -86,59 +86,58 @@ Pass::Status LocalSingleStoreElimPass::Process() { } void LocalSingleStoreElimPass::InitExtensionAllowList() { - extensions_allowlist_.insert({ - "SPV_AMD_shader_explicit_vertex_parameter", - "SPV_AMD_shader_trinary_minmax", - "SPV_AMD_gcn_shader", - "SPV_KHR_shader_ballot", - "SPV_AMD_shader_ballot", - "SPV_AMD_gpu_shader_half_float", - "SPV_KHR_shader_draw_parameters", - "SPV_KHR_subgroup_vote", - "SPV_KHR_8bit_storage", - "SPV_KHR_16bit_storage", - "SPV_KHR_device_group", - "SPV_KHR_multiview", - "SPV_NVX_multiview_per_view_attributes", - "SPV_NV_viewport_array2", - "SPV_NV_stereo_view_rendering", - "SPV_NV_sample_mask_override_coverage", - "SPV_NV_geometry_shader_passthrough", - "SPV_AMD_texture_gather_bias_lod", - "SPV_KHR_storage_buffer_storage_class", - "SPV_KHR_variable_pointers", - "SPV_AMD_gpu_shader_int16", - "SPV_KHR_post_depth_coverage", - "SPV_KHR_shader_atomic_counter_ops", - "SPV_EXT_shader_stencil_export", - "SPV_EXT_shader_viewport_index_layer", - "SPV_AMD_shader_image_load_store_lod", - "SPV_AMD_shader_fragment_mask", - "SPV_EXT_fragment_fully_covered", - "SPV_AMD_gpu_shader_half_float_fetch", - "SPV_GOOGLE_decorate_string", - "SPV_GOOGLE_hlsl_functionality1", - "SPV_NV_shader_subgroup_partitioned", - "SPV_EXT_descriptor_indexing", - "SPV_NV_fragment_shader_barycentric", - "SPV_NV_compute_shader_derivatives", - "SPV_NV_shader_image_footprint", - "SPV_NV_shading_rate", - "SPV_NV_mesh_shader", - "SPV_NV_ray_tracing", - "SPV_KHR_ray_query", - "SPV_EXT_fragment_invocation_density", - "SPV_EXT_physical_storage_buffer", - "SPV_KHR_terminate_invocation", - "SPV_KHR_subgroup_uniform_control_flow", - "SPV_KHR_integer_dot_product", - "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", - }); + extensions_allowlist_.insert({"SPV_AMD_shader_explicit_vertex_parameter", + "SPV_AMD_shader_trinary_minmax", + "SPV_AMD_gcn_shader", + "SPV_KHR_shader_ballot", + "SPV_AMD_shader_ballot", + "SPV_AMD_gpu_shader_half_float", + "SPV_KHR_shader_draw_parameters", + "SPV_KHR_subgroup_vote", + "SPV_KHR_8bit_storage", + "SPV_KHR_16bit_storage", + "SPV_KHR_device_group", + "SPV_KHR_multiview", + "SPV_NVX_multiview_per_view_attributes", + "SPV_NV_viewport_array2", + "SPV_NV_stereo_view_rendering", + "SPV_NV_sample_mask_override_coverage", + "SPV_NV_geometry_shader_passthrough", + "SPV_AMD_texture_gather_bias_lod", + "SPV_KHR_storage_buffer_storage_class", + "SPV_KHR_variable_pointers", + "SPV_AMD_gpu_shader_int16", + "SPV_KHR_post_depth_coverage", + "SPV_KHR_shader_atomic_counter_ops", + "SPV_EXT_shader_stencil_export", + "SPV_EXT_shader_viewport_index_layer", + "SPV_AMD_shader_image_load_store_lod", + "SPV_AMD_shader_fragment_mask", + "SPV_EXT_fragment_fully_covered", + "SPV_AMD_gpu_shader_half_float_fetch", + "SPV_GOOGLE_decorate_string", + "SPV_GOOGLE_hlsl_functionality1", + "SPV_NV_shader_subgroup_partitioned", + "SPV_EXT_descriptor_indexing", + "SPV_NV_fragment_shader_barycentric", + "SPV_NV_compute_shader_derivatives", + "SPV_NV_shader_image_footprint", + "SPV_NV_shading_rate", + "SPV_NV_mesh_shader", + "SPV_NV_ray_tracing", + "SPV_KHR_ray_query", + "SPV_EXT_fragment_invocation_density", + "SPV_EXT_physical_storage_buffer", + "SPV_KHR_terminate_invocation", + "SPV_KHR_subgroup_uniform_control_flow", + "SPV_KHR_integer_dot_product", + "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"}); } bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) { std::vector users; From 02cd71d41cc9c2b82f9980a512fc5882c0437efa Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 17:00:00 +0000 Subject: [PATCH 240/523] roll deps (#5352) * Roll external/googletest/ 40412d851..6f6ab4212 (2 commits) https://github.com/google/googletest/compare/40412d85124f...6f6ab4212aa0 $ git log 40412d851..6f6ab4212 --date=short --no-merges --format='%ad %ae %s' 2023-07-27 julien.combattelli Use #if and not #ifdef to check filesystem support 2023-07-28 absl-team Adjust includes to use <> instead of "", consistent with quickstart pages. Created with: roll-dep external/googletest * Roll external/re2/ e66463312..960c86176 (10 commits) https://github.com/google/re2/compare/e66463312e1d...960c861764ff $ git log e66463312..960c86176 --date=short --no-merges --format='%ad %ae %s' 2023-07-28 junyer Don't try to support ARM64 on Windows yet. 2023-07-28 junyer Try again to make cross-compiling on Windows work. 2023-07-28 junyer `bazelbuild/setup-bazelisk` doesn't work for some reason. 2023-07-28 junyer Bazelisk isn't installed with Chocolatey, apparently. 2023-07-28 junyer Avoid the Chocolatey install of Bazel(isk) getting in the way. 2023-07-28 junyer Try using `bazelbuild/setup-bazelisk` everywhere. 2023-07-28 junyer Tell the Python build where Bazelisk is. 2023-07-28 junyer Explicitly invoke Bazelisk rather than Bazel. 2023-07-28 junyer Avoid `Conflicts: python3-lldb-x.y` between packages. 2023-07-28 junyer Prepare to release `google-re2` 1.1. Created with: roll-dep external/re2 * Roll external/spirv-headers/ 51b106461..ae89923fa (1 commit) https://github.com/KhronosGroup/SPIRV-Headers/compare/51b106461707...ae89923fa781 $ git log 51b106461..ae89923fa --date=short --no-merges --format='%ad %ae %s' 2023-07-26 kevin.petit Add KHR suffix to Cooperative Matrix Operands 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 f508b58530..2b99d59545 100644 --- a/DEPS +++ b/DEPS @@ -7,13 +7,13 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '40412d85124f7c6f3d88454583c4633e5e10fc8c', + 'googletest_revision': '6f6ab4212aa02cfe02e480711246da4fc17b0761', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': 'e66463312e1d30d427bbde6c40e7fd627dcfb82e', - 'spirv_headers_revision': '51b106461707f46d962554efe1bf56dee28958a3', + 're2_revision': '960c861764ff54c9a12ff683ba55ccaad1a8f73b', + 'spirv_headers_revision': 'ae89923fa781650569ca15e5b498a9e4e46ee9c9', } deps = { From 47fff21d526c907a782550a39daf3931ec803e2c Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Tue, 1 Aug 2023 13:49:12 -0600 Subject: [PATCH 241/523] instrument: Reduce number of inst_bindless_stream_write_6 calls (#5327) Multiple calls to this function were causing vkCreateGraphicsPipelines to be 3x slower on some driver. I suspect this was because each call had to be inlined separately which bloated the code and caused more work in the driver's SPIRV -> native instruction compilation. --- source/opt/inst_bindless_check_pass.cpp | 616 ++++++++++++++++-------- test/opt/inst_bindless_check_test.cpp | 115 ++++- 2 files changed, 498 insertions(+), 233 deletions(-) diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp index f265cdd042..339fb1b62c 100644 --- a/source/opt/inst_bindless_check_pass.cpp +++ b/source/opt/inst_bindless_check_pass.cpp @@ -132,50 +132,58 @@ void InstBindlessCheckPass::SetupInputBufferIds() { // clang-format off // GLSL: -//bool inst_bindless_check_desc(uint shader_id, uint line, uvec4 stage_info, uint desc_set_idx, uint binding_idx, uint desc_idx, -// uint offset) +//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) //{ -// if (desc_set_idx >= inst_bindless_input_buffer.desc_sets.length()) { -// // kInstErrorBindlessBounds -// inst_bindless_stream_write_6(shader_id, line, stage_info, 1, desc_set_idx, binding_idx, desc_idx, 0, 0); -// return false; +// uint error = 0u; +// uint param5 = 0u; +// uint param6 = 0u; +// uint num_bindings = 0u; +// uint init_state = 0u; +// if (desc_set >= 32u) { +// error = 1u; // } -// DescriptorSetData set_data = inst_bindless_input_buffer.desc_sets[desc_set_idx]; -// uvec2 ptr_vec = uvec2(set_data); -// if (ptr_vec.x == 0 && ptr_vec.y == 0) { -// // kInstErrorBindlessBounds -// inst_bindless_stream_write_6(shader_id, line, stage_info, 1, desc_set_idx, binding_idx, desc_idx, 0, 0); -// return false; +// 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; +// } // } -// uint num_bindings = set_data.num_bindings; -// if (binding_idx >= num_bindings) { -// // kInstErrorBindlessBounds -// inst_bindless_stream_write_6(shader_id, line, stage_info, 1, desc_set_idx, binding_idx, desc_idx, 0, 0); -// return false; +// if (error == 0u) { +// num_bindings = set_data.num_bindings; +// if (binding >= num_bindings) { +// error = 1u; +// } // } -// uint binding_length = set_data.data[binding_idx]; -// if (desc_idx >= binding_length) { -// // kInstErrorBindlessBounds -// inst_bindless_stream_write_6(shader_id, line, stage_info, 1, desc_set_idx, binding_idx, desc_idx, binding_length, 0); -// return false; +// if (error == 0u) { +// if (desc_index >= set_data.data[binding]) { +// error = 1u; +// param5 = set_data.data[binding]; +// } // } -// uint desc_records_start = set_data.data[num_bindings + binding_idx]; -// uint init_or_len = set_data.data[desc_records_start + desc_idx]; -// if (init_or_len == 0) { -// // kInstErrorBindlessUninit -// inst_bindless_stream_write_6(shader_id, line, stage_info, 2, desc_set_idx, binding_idx, desc_idx, 0, 0); -// return false; +// 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 (offset >= init_or_len) { -// // kInstErrorOOB -// inst_bindless_stream_write_6(shader_id, line, stage_info, 4, desc_set_idx, binding_idx, desc_idx, offset, -// init_or_len); +// 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; //} // clang-format on - uint32_t InstBindlessCheckPass::GenDescCheckFunctionId() { enum { kShaderId = 0, @@ -205,235 +213,427 @@ uint32_t InstBindlessCheckPass::GenDescCheckFunctionId() { 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); - Instruction* inst; + 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(); - uint32_t error_blk_id = TakeNextId(); - uint32_t merge_blk_id = TakeNextId(); - std::unique_ptr merge_label(NewLabel(merge_blk_id)); - std::unique_ptr error_label(NewLabel(error_blk_id)); - (void)builder.AddConditionalBranch(desc_cmp_id, error_blk_id, merge_blk_id, - merge_blk_id); + (void)builder.AddConditionalBranch(desc_cmp_id, check_label_id, skip_label_id, + skip_label_id); func->AddBasicBlock(std::move(new_blk_ptr)); - // error return - new_blk_ptr = MakeUnique(std::move(error_label)); + // set error + new_blk_ptr = MakeUnique(std::move(check_label)); builder.SetInsertPoint(&*new_blk_ptr); - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, false_id); + 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(merge_label)); + new_blk_ptr = MakeUnique(std::move(skip_label)); builder.SetInsertPoint(&*new_blk_ptr); - const uint32_t desc_set_ptr_ptr = type_mgr->FindPointerToType( - desc_set_ptr_id_, spv::StorageClass::StorageBuffer); - - inst = builder.AddAccessChain( - desc_set_ptr_ptr, input_buffer_id_, - {builder.GetUintConstantId(0), 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(); - - inst = - builder.AddUnaryOp(GetVecUintId(2), spv::Op::OpBitcast, desc_set_ptr_id); - const uint32_t ptr_as_uvec_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); + 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)); - inst = builder.AddCompositeExtract(GetUintId(), ptr_as_uvec_id, {0}); - const uint32_t uvec_x = inst->result_id(); + new_blk_ptr = MakeUnique(std::move(check_label)); + builder.SetInsertPoint(&*new_blk_ptr); - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, uvec_x, - builder.GetUintConstantId(0)); - const uint32_t x_is_zero_id = inst->result_id(); + { + 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)); + } - inst = builder.AddCompositeExtract(GetUintId(), ptr_as_uvec_id, {1}); - const uint32_t uvec_y = inst->result_id(); + new_blk_ptr = MakeUnique(std::move(skip_label)); + builder.SetInsertPoint(&*new_blk_ptr); - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, uvec_y, - builder.GetUintConstantId(0)); - const uint32_t y_is_zero_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.AddBinaryOp(GetBoolId(), spv::Op::OpLogicalAnd, x_is_zero_id, - y_is_zero_id); - const uint32_t is_null_id = inst->result_id(); + inst = builder.AddLoad(GetUintId(), error_var); + error_val_id = inst->result_id(); - error_blk_id = TakeNextId(); - merge_blk_id = TakeNextId(); - merge_label = NewLabel(merge_blk_id); - error_label = NewLabel(error_blk_id); - (void)builder.AddConditionalBranch(is_null_id, error_blk_id, merge_blk_id, - merge_blk_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - // error return - new_blk_ptr = MakeUnique(std::move(error_label)); - builder.SetInsertPoint(&*new_blk_ptr); - GenDebugStreamWrite( - param_ids[kShaderId], param_ids[kInstructionIndex], param_ids[kStageInfo], - {builder.GetUintConstantId(kInstErrorBindlessBounds), param_ids[kDescSet], - param_ids[kDescBinding], param_ids[kDescIndex], - builder.GetUintConstantId(0), builder.GetUintConstantId(0)}, - &builder); - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, false_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(merge_label)); + 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)); + } - const uint32_t uint_ptr = type_mgr->FindPointerToType( - GetUintId(), spv::StorageClass::PhysicalStorageBuffer); - - inst = builder.AddAccessChain(uint_ptr, desc_set_ptr_id, - {builder.GetUintConstantId(0)}); - const uint32_t binding_access_chain_id = inst->result_id(); + // read binding length + new_blk_ptr = MakeUnique(std::move(skip_label)); + builder.SetInsertPoint(&*new_blk_ptr); - inst = builder.AddLoad(GetUintId(), binding_access_chain_id, 8); - const uint32_t num_bindings_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.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual, - param_ids[kDescBinding], num_bindings_id); - const uint32_t bindings_cmp_id = inst->result_id(); + inst = builder.AddLoad(GetUintId(), error_var); + error_val_id = inst->result_id(); - error_blk_id = TakeNextId(); - merge_blk_id = TakeNextId(); - merge_label = NewLabel(merge_blk_id); - error_label = NewLabel(error_blk_id); - (void)builder.AddConditionalBranch(bindings_cmp_id, error_blk_id, - merge_blk_id, merge_blk_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - // error return - new_blk_ptr = MakeUnique(std::move(error_label)); - builder.SetInsertPoint(&*new_blk_ptr); - GenDebugStreamWrite( - param_ids[kShaderId], param_ids[kInstructionIndex], param_ids[kStageInfo], - {builder.GetUintConstantId(kInstErrorBindlessBounds), param_ids[kDescSet], - param_ids[kDescBinding], param_ids[kDescIndex], - builder.GetUintConstantId(0), builder.GetUintConstantId(0)}, - &builder); - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, false_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)); - // read binding length - new_blk_ptr = MakeUnique(std::move(merge_label)); + 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)); + } - 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(); - - error_blk_id = TakeNextId(); - merge_blk_id = TakeNextId(); - merge_label = NewLabel(merge_blk_id); - error_label = NewLabel(error_blk_id); - (void)builder.AddConditionalBranch(desc_idx_range_id, error_blk_id, - merge_blk_id, merge_blk_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - // Error return - new_blk_ptr = MakeUnique(std::move(error_label)); + new_blk_ptr = MakeUnique(std::move(skip_label)); builder.SetInsertPoint(&*new_blk_ptr); - GenDebugStreamWrite( - param_ids[kShaderId], param_ids[kInstructionIndex], param_ids[kStageInfo], - {builder.GetUintConstantId(kInstErrorBindlessBounds), param_ids[kDescSet], - param_ids[kDescBinding], param_ids[kDescIndex], length_id, - builder.GetUintConstantId(0)}, - &builder); - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, false_id); + 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(merge_label)); + 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)); + } - 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(); - - // Check for uninitialized descriptor - inst = builder.AddBinaryOp(GetBoolId(), spv::Op::OpIEqual, init_status_id, - builder.GetUintConstantId(0)); - const uint32_t uninit_check_id = inst->result_id(); - error_blk_id = TakeNextId(); - merge_blk_id = TakeNextId(); - merge_label = NewLabel(merge_blk_id); - error_label = NewLabel(error_blk_id); - (void)builder.AddConditionalBranch(uninit_check_id, error_blk_id, - merge_blk_id, merge_blk_id); - func->AddBasicBlock(std::move(new_blk_ptr)); - new_blk_ptr = MakeUnique(std::move(error_label)); + // Check for OOB. + new_blk_ptr = MakeUnique(std::move(skip_label)); builder.SetInsertPoint(&*new_blk_ptr); - GenDebugStreamWrite( - param_ids[kShaderId], param_ids[kInstructionIndex], param_ids[kStageInfo], - {builder.GetUintConstantId(kInstErrorBindlessUninit), param_ids[kDescSet], - param_ids[kDescBinding], param_ids[kDescIndex], - builder.GetUintConstantId(0), builder.GetUintConstantId(0)}, - &builder); - (void)builder.AddUnaryOp(0, spv::Op::OpReturnValue, false_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, 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 for OOB. - new_blk_ptr = MakeUnique(std::move(merge_label)); + 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.AddBinaryOp(GetBoolId(), spv::Op::OpUGreaterThanEqual, - param_ids[kByteOffset], init_status_id); - const uint32_t buf_offset_range_id = inst->result_id(); - - error_blk_id = TakeNextId(); - merge_blk_id = TakeNextId(); - merge_label = NewLabel(merge_blk_id); - error_label = NewLabel(error_blk_id); - (void)builder.AddConditionalBranch(buf_offset_range_id, error_blk_id, - merge_blk_id, merge_blk_id); + 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)); - // Error return + 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], - {builder.GetUintConstantId(kInstErrorOOB), param_ids[kDescSet], - param_ids[kDescBinding], param_ids[kDescIndex], param_ids[kByteOffset], - init_status_id}, + {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)); diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp index d18a33046e..1c192c4366 100644 --- a/test/opt/inst_bindless_check_test.cpp +++ b/test/opt/inst_bindless_check_test.cpp @@ -135,19 +135,32 @@ static const std::string kCheckDesc = R"( ; CHECK: [[di_shader_id:%\w+]] = OpFunctionParameter %uint ; CHECK: [[di_line:%\w+]] = OpFunctionParameter %uint ; CHECK: [[di_stage_info:%\w+]] = OpFunctionParameter %v4uint -; CHECK: [[di_desc_set_idx:%\w+]] = OpFunctionParameter %uint -; CHECK: [[di_binding_idx:%\w+]] = OpFunctionParameter %uint +; 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: {{%\w+}} = OpUGreaterThanEqual %bool [[di_desc_set_idx]] %uint_32 +; 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: OpReturnValue %false +; 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_idx]] +; 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 @@ -157,44 +170,96 @@ static const std::string kCheckDesc = R"( ; CHECK: OpSelectionMerge {{%\w+}} None ; CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 [[di_shader_id]] [[di_line]] [[di_stage_info]] %uint_1 [[di_desc_set_idx]] [[di_binding_idx]] [[di_desc_idx]] %uint_0 %uint_0 -; CHECK: OpReturnValue %false +; 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: [[di_num_bindings:%\w+]] = OpLoad %uint {{%\w+}} Aligned 8 -; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_binding_idx]] [[di_num_bindings]] +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 [[di_shader_id]] [[di_line]] [[di_stage_info]] %uint_1 [[di_desc_set_idx]] [[di_binding_idx]] [[di_desc_idx]] %uint_0 %uint_0 -; CHECK: OpReturnValue %false +; CHECK: OpStore [[di_error]] %uint_1 +; CHECK: OpBranch {{%\w+}} +; CHECK: {{%\w+}} = OpLabel +; CHECK: OpBranch {{%\w+}} ; CHECK: {{%\w+}} = OpLabel -; CHECK: {{%\w+}} = OpAccessChain %_ptr_PhysicalStorageBuffer_uint {{%\w+}} %uint_1 [[di_binding_idx]] -; CHECK: [[di_desc_array_len:%\w+]] = OpLoad %uint {{%\w+}} Aligned 4 -; CHECK: {{%\w+}} = OpUGreaterThanEqual %bool [[di_desc_idx]] [[di_desc_array_len]] +; 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+}} = OpFunctionCall %void %inst_bindless_stream_write_6 [[di_shader_id]] [[di_line]] [[di_stage_info]] %uint_1 [[di_desc_set_idx]] [[di_binding_idx]] [[di_desc_idx]] [[di_desc_array_len]] %uint_0 -; CHECK: OpReturnValue %false +; 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: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}} +; 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: [[di_init_status:%\w+]] = OpLoad %uint {{%\w+}} Aligned 4 -; CHECK: {{%\w+}} = OpIEqual %bool [[di_init_status]] %uint_0 +; 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: {{%\w+}} = OpFunctionCall %void %inst_bindless_stream_write_6 [[di_shader_id]] [[di_line]] [[di_stage_info]] %uint_2 [[di_desc_set_idx]] [[di_binding_idx]] [[di_desc_idx]] %uint_0 %uint_0 -; CHECK: OpReturnValue %false +; 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+}} = OpUGreaterThanEqual %bool {{%\w+}} {{%\w+}} +; 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+}} = OpFunctionCall %void %inst_bindless_stream_write_6 [[di_shader_id]] [[di_line]] [[di_stage_info]] %uint_4 [[di_desc_set_idx]] [[di_binding_idx]] [[di_desc_idx]] [[di_byte_offset]] [[di_init_status]] +; 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 @@ -4377,7 +4442,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { ;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-NOT: OpStore %v_vtxResult %21$ ;CHECK: OpStore %v_vtxResult [[phi_result]] OpReturn OpFunctionEnd @@ -4493,7 +4558,7 @@ TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { ;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-NOT: OpStore %v_vtxResult %21$ ;CHECK: OpStore %v_vtxResult [[phi_result]] OpReturn OpFunctionEnd From 1d14d84f291805ce845a0e5b9775e5e0ab11995b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Wed, 2 Aug 2023 11:52:53 +0200 Subject: [PATCH 242/523] opt: fix missing CreateTrimCapabilitiesPass definition (#5353) --- source/opt/optimizer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index 0e31f26140..6301be6ca1 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -1071,6 +1071,11 @@ Optimizer::PassToken CreateFixFuncCallArgumentsPass() { return MakeUnique( MakeUnique()); } + +Optimizer::PassToken CreateTrimCapabilitiesPass() { + return MakeUnique( + MakeUnique()); +} } // namespace spvtools extern "C" { From 09b76c23ea46f400941867602ee8686694567c10 Mon Sep 17 00:00:00 2001 From: David Neto Date: Fri, 4 Aug 2023 14:50:54 -0400 Subject: [PATCH 243/523] Update SPIRV-Headers; test some coop matrix enums (#5361) Test: MatrixASignedComponentsKHR MatrixBSignedComponentsKHR MatrixCSignedComponentsKHR ResultSignedComponentsKHR --- DEPS | 2 +- test/val/val_arithmetics_test.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 2b99d59545..1d9f0ba1bd 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': '960c861764ff54c9a12ff683ba55ccaad1a8f73b', - 'spirv_headers_revision': 'ae89923fa781650569ca15e5b498a9e4e46ee9c9', + 'spirv_headers_revision': '124a9665e464ef98b8b718d572d5f329311061eb', } deps = { diff --git a/test/val/val_arithmetics_test.cpp b/test/val/val_arithmetics_test.cpp index 06c4e3984a..58ac4423e9 100644 --- a/test/val/val_arithmetics_test.cpp +++ b/test/val/val_arithmetics_test.cpp @@ -1555,7 +1555,10 @@ TEST_F(ValidateArithmetics, CoopMatKHRSuccess) { %val14 = OpMatrixTimesScalar %u32matA %u32mat_A_1 %u32_1 %val15 = OpMatrixTimesScalar %s32matA %s32mat_A_1 %s32_1 %val16 = OpCooperativeMatrixMulAddKHR %f32matC %f16mat_A_1 %f16mat_B_1 %f16mat_C_1 -%val17 = OpCooperativeMatrixMulAddKHR %s32matC %s32mat_A_1 %s32mat_B_1 %s32mat_C_1)"; +%val17 = OpCooperativeMatrixMulAddKHR %s32matC %s32mat_A_1 %s32mat_B_1 %s32mat_C_1 + MatrixASignedComponentsKHR|MatrixBSignedComponentsKHR|MatrixCSignedComponentsKHR|MatrixResultSignedComponentsKHR +%val18 = OpCooperativeMatrixMulAddKHR %u32matC %u32mat_A_1 %u32mat_B_1 %u32mat_C_1 +)"; CompileSuccessfully(GenerateCoopMatKHRCode("", body).c_str()); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); From 4a9881fe9b32086d4ceac89a498b0dd34084b574 Mon Sep 17 00:00:00 2001 From: Natalie Chouinard <1953083+sudonatalie@users.noreply.github.com> Date: Fri, 4 Aug 2023 18:01:50 -0400 Subject: [PATCH 244/523] Use absolute path to depot_tools (#5360) The autoroll workflow is currently failing due to being unable to find some depot_tools executables. This is due to a limitation in Go os/exec which effectively rejects all relative paths in PATH, and is exposed by a recent update to depot_tools (https://crrev.com/43083529de5802a83f53f1d53d7f5f9615999996). --- .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 4520309d45..6a7a814df2 100644 --- a/.github/workflows/autoroll.yml +++ b/.github/workflows/autoroll.yml @@ -23,7 +23,7 @@ jobs: run: git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git - name: Update PATH - run: echo "./depot_tools" >> $GITHUB_PATH + run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH - name: Download dependencies run: python3 utils/git-sync-deps From e553b884c7c9febaa4e52334f683641fb5f196a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 8 Aug 2023 15:41:26 +0200 Subject: [PATCH 245/523] Prepare release for v2023.4.rc2 (#5362) --- CHANGES | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES b/CHANGES index c3d46a13d8..97caaee192 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,8 @@ Revision history for SPIRV-Tools v2023.4 2023-07-17 - General + - Set cmake_policy CMP0128 (#5341) + - Add python3 requirement for the script (#5326) - Add support for LiteralFloat type (#5323) - SPV_KHR_cooperative_matrix (#5286) - Allow OpTypeBool in UniformConstant (#5237) @@ -12,9 +14,12 @@ v2023.4 2023-07-17 - Fold negation of integer vectors (#5269) - Add folding rule for OpTranspose (#5241) - Add SPV_NV_bindless_texture to spirv optimizations (#5231) + - Fix incorrect half float conversion (#5349) + - Add SPV_EXT_shader_atomic_float_add to allow lists (#5348) - Instrument - instrument: Cast gl_VertexIndex and InstanceIndex to uint (#5319) - instrument: Fix buffer address length calculations (#5257) + - instrument: Reduce number of inst_bindless_stream_write_6 calls (#5327) - Validator - Validate GroupNonUniform instructions (#5296) - spirv-val: Label SPV_KHR_cooperative_matrix VUID (#5301) From 727f4346db0ba7356ccf87a2716d96ffd9b18b44 Mon Sep 17 00:00:00 2001 From: Sven van Haastregt Date: Tue, 8 Aug 2023 16:53:33 +0100 Subject: [PATCH 246/523] 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 247/523] 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 248/523] 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 249/523] 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 250/523] 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 251/523] 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 252/523] 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 253/523] 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 254/523] 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 255/523] 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 256/523] 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 257/523] 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 258/523] 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 259/523] 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 260/523] 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 261/523] 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 262/523] 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 263/523] 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 264/523] 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 265/523] 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 266/523] 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 267/523] 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 268/523] 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 269/523] 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 270/523] 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 271/523] 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 272/523] 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 273/523] 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 274/523] 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 275/523] 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 276/523] 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 277/523] 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 278/523] 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 279/523] 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 280/523] 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 281/523] 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 282/523] 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 283/523] 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 284/523] 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 285/523] 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 286/523] 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 287/523] 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 288/523] 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 289/523] 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 290/523] 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 291/523] 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 292/523] 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 293/523] 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 294/523] 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 295/523] 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 296/523] 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 297/523] 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 298/523] 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 299/523] 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 300/523] 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 301/523] 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 302/523] 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 303/523] 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 304/523] 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 305/523] 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 306/523] 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 307/523] 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 308/523] 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 309/523] 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 310/523] 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 311/523] 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 312/523] 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 313/523] 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 314/523] 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 315/523] 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 316/523] 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 317/523] 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 318/523] 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 319/523] 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 320/523] 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 321/523] 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 322/523] 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 323/523] 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 324/523] 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 325/523] 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 326/523] 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 327/523] 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 328/523] 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 329/523] 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 330/523] 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 331/523] 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 332/523] 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 333/523] 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 334/523] 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 335/523] 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 336/523] 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 337/523] 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 338/523] 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 339/523] 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 340/523] 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) From 7d2429594d84f09d0aef2c0a36d1a7234941a040 Mon Sep 17 00:00:00 2001 From: technateNG Date: Tue, 2 Jan 2024 15:07:47 +0000 Subject: [PATCH 341/523] Fix(cmake): CMake doesn't find system installed SPIRV-Headers (#5422) To build repository version from sources current cmake require to explicitly clone SPIRV-Headers repository to directory named 'external' with fixed name 'spirv-headers'. This is a behavior which doesn't support searching global headers and also CMAKE_PREFIX_PATH which makes development in some environments less convenient than it should be. The commit fixes this issue with keeping previous clone option intact. --- external/CMakeLists.txt | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 5d8a3dab09..153676e41d 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -27,26 +27,26 @@ function(pop_variable var) endfunction() if (DEFINED SPIRV-Headers_SOURCE_DIR) - # This allows flexible position of the SPIRV-Headers repo. - set(SPIRV_HEADER_DIR ${SPIRV-Headers_SOURCE_DIR}) + add_subdirectory(${SPIRV-Headers_SOURCE_DIR}) + set(SPIRV-Headers_INCLUDE_DIRS ${SPIRV-Headers_SOURCE_DIR}/include) +elseif (IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/spirv-headers/) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/spirv-headers/) + set(SPIRV-Headers_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/spirv-headers/include) +elseif(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Headers/) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Headers/) + set(SPIRV-Headers_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Headers/include) +elseif() else() - set(SPIRV_HEADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/spirv-headers) -endif() - -if (IS_DIRECTORY ${SPIRV_HEADER_DIR}) - # TODO(dneto): We should not be modifying the parent scope. - set(SPIRV_HEADER_INCLUDE_DIR ${SPIRV_HEADER_DIR}/include PARENT_SCOPE) - - # Add SPIRV-Headers as a sub-project if it isn't already defined. - # Do this so enclosing projects can use SPIRV-Headers_SOURCE_DIR to find - # headers to include. - if (NOT DEFINED SPIRV-Headers_SOURCE_DIR) - add_subdirectory(${SPIRV_HEADER_DIR}) + find_package(SPIRV-Headers QUIET) + if (SPIRV-Headers_FOUND) + get_target_property(SPIRV-Headers_INCLUDE_DIRS SPIRV-Headers::SPIRV-Headers INTERFACE_INCLUDE_DIRECTORIES) + else () + message(FATAL_ERROR + "SPIRV-Headers was not found - please checkout a copy under external/.") endif() -else() - message(FATAL_ERROR - "SPIRV-Headers was not found - please checkout a copy under external/.") endif() +set(SPIRV_HEADER_INCLUDE_DIR ${SPIRV-Headers_INCLUDE_DIRS} PARENT_SCOPE) +message(STATUS "Found SPIRV-Headers: ${SPIRV-Headers_INCLUDE_DIRS}") if (NOT ${SPIRV_SKIP_TESTS}) # Find gmock if we can. If it's not already configured, then try finding From 0a9f3d1f2a8dd660bec005206a1b86136357d41c Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 3 Jan 2024 09:55:24 -0500 Subject: [PATCH 342/523] Revert "Fix(cmake): CMake doesn't find system installed SPIRV-Headers (#5422)" (#5517) This reverts commit 7d2429594d84f09d0aef2c0a36d1a7234941a040. --- external/CMakeLists.txt | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 153676e41d..5d8a3dab09 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -27,26 +27,26 @@ function(pop_variable var) endfunction() if (DEFINED SPIRV-Headers_SOURCE_DIR) - add_subdirectory(${SPIRV-Headers_SOURCE_DIR}) - set(SPIRV-Headers_INCLUDE_DIRS ${SPIRV-Headers_SOURCE_DIR}/include) -elseif (IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/spirv-headers/) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/spirv-headers/) - set(SPIRV-Headers_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/spirv-headers/include) -elseif(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Headers/) - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Headers/) - set(SPIRV-Headers_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Headers/include) -elseif() + # This allows flexible position of the SPIRV-Headers repo. + set(SPIRV_HEADER_DIR ${SPIRV-Headers_SOURCE_DIR}) else() - find_package(SPIRV-Headers QUIET) - if (SPIRV-Headers_FOUND) - get_target_property(SPIRV-Headers_INCLUDE_DIRS SPIRV-Headers::SPIRV-Headers INTERFACE_INCLUDE_DIRECTORIES) - else () - message(FATAL_ERROR - "SPIRV-Headers was not found - please checkout a copy under external/.") + set(SPIRV_HEADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/spirv-headers) +endif() + +if (IS_DIRECTORY ${SPIRV_HEADER_DIR}) + # TODO(dneto): We should not be modifying the parent scope. + set(SPIRV_HEADER_INCLUDE_DIR ${SPIRV_HEADER_DIR}/include PARENT_SCOPE) + + # Add SPIRV-Headers as a sub-project if it isn't already defined. + # Do this so enclosing projects can use SPIRV-Headers_SOURCE_DIR to find + # headers to include. + if (NOT DEFINED SPIRV-Headers_SOURCE_DIR) + add_subdirectory(${SPIRV_HEADER_DIR}) endif() +else() + message(FATAL_ERROR + "SPIRV-Headers was not found - please checkout a copy under external/.") endif() -set(SPIRV_HEADER_INCLUDE_DIR ${SPIRV-Headers_INCLUDE_DIRS} PARENT_SCOPE) -message(STATUS "Found SPIRV-Headers: ${SPIRV-Headers_INCLUDE_DIRS}") if (NOT ${SPIRV_SKIP_TESTS}) # Find gmock if we can. If it's not already configured, then try finding From c7affa1707b9c517ea028bf9070c97e6842a6749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 4 Jan 2024 20:01:03 +0100 Subject: [PATCH 343/523] opt: add Int16 and Float16 to capability trim pass (#5519) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for Int16 and Float16 trim. Signed-off-by: Nathan Gauër --- source/opt/trim_capabilities_pass.cpp | 24 +++++- source/opt/trim_capabilities_pass.h | 2 + test/opt/trim_capabilities_pass_test.cpp | 98 ++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 1 deletion(-) diff --git a/source/opt/trim_capabilities_pass.cpp b/source/opt/trim_capabilities_pass.cpp index 05499471d4..19f8569e09 100644 --- a/source/opt/trim_capabilities_pass.cpp +++ b/source/opt/trim_capabilities_pass.cpp @@ -137,6 +137,16 @@ static bool Has16BitCapability(const FeatureManager* feature_manager) { // Handler names follow the following convention: // Handler__() +static std::optional Handler_OpTypeFloat_Float16( + const Instruction* instruction) { + assert(instruction->opcode() == spv::Op::OpTypeFloat && + "This handler only support OpTypeFloat opcodes."); + + const uint32_t size = + instruction->GetSingleWordInOperand(kOpTypeFloatSizeIndex); + return size == 16 ? std::optional(spv::Capability::Float16) : std::nullopt; +} + static std::optional Handler_OpTypeFloat_Float64( const Instruction* instruction) { assert(instruction->opcode() == spv::Op::OpTypeFloat && @@ -274,6 +284,16 @@ static std::optional Handler_OpTypePointer_StorageUniform16( : std::nullopt; } +static std::optional Handler_OpTypeInt_Int16( + const Instruction* instruction) { + assert(instruction->opcode() == spv::Op::OpTypeInt && + "This handler only support OpTypeInt opcodes."); + + const uint32_t size = + instruction->GetSingleWordInOperand(kOpTypeIntSizeIndex); + return size == 16 ? std::optional(spv::Capability::Int16) : std::nullopt; +} + static std::optional Handler_OpTypeInt_Int64( const Instruction* instruction) { assert(instruction->opcode() == spv::Op::OpTypeInt && @@ -341,12 +361,14 @@ Handler_OpImageSparseRead_StorageImageReadWithoutFormat( } // Opcode of interest to determine capabilities requirements. -constexpr std::array, 10> kOpcodeHandlers{{ +constexpr std::array, 12> kOpcodeHandlers{{ // clang-format off {spv::Op::OpImageRead, Handler_OpImageRead_StorageImageReadWithoutFormat}, {spv::Op::OpImageSparseRead, Handler_OpImageSparseRead_StorageImageReadWithoutFormat}, + {spv::Op::OpTypeFloat, Handler_OpTypeFloat_Float16 }, {spv::Op::OpTypeFloat, Handler_OpTypeFloat_Float64 }, {spv::Op::OpTypeImage, Handler_OpTypeImage_ImageMSArray}, + {spv::Op::OpTypeInt, Handler_OpTypeInt_Int16 }, {spv::Op::OpTypeInt, Handler_OpTypeInt_Int64 }, {spv::Op::OpTypePointer, Handler_OpTypePointer_StorageInputOutput16}, {spv::Op::OpTypePointer, Handler_OpTypePointer_StoragePushConstant16}, diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index 73d5dc80d5..9f23732997 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -76,12 +76,14 @@ class TrimCapabilitiesPass : public Pass { // clang-format off spv::Capability::ComputeDerivativeGroupLinearNV, spv::Capability::ComputeDerivativeGroupQuadsNV, + spv::Capability::Float16, spv::Capability::Float64, spv::Capability::FragmentShaderPixelInterlockEXT, spv::Capability::FragmentShaderSampleInterlockEXT, spv::Capability::FragmentShaderShadingRateInterlockEXT, spv::Capability::Groups, spv::Capability::ImageMSArray, + spv::Capability::Int16, spv::Capability::Int64, 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 14a8aa3a56..c90afb4c66 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -2486,6 +2486,104 @@ TEST_F(TrimCapabilitiesPassTest, EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); } +TEST_F(TrimCapabilitiesPassTest, Float16_RemovedWhenUnused) { + const std::string kTest = R"( + OpCapability Float16 +; CHECK-NOT: OpCapability Float16 + 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, Float16_RemainsWhenUsed) { + const std::string kTest = R"( + OpCapability Float16 +; CHECK: OpCapability Float16 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %float = OpTypeFloat 16 + %3 = OpTypeFunction %void + %1 = OpFunction %void None %3 + %6 = OpLabel + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, Int16_RemovedWhenUnused) { + const std::string kTest = R"( + OpCapability Int16 +; CHECK-NOT: OpCapability Int16 + 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, Int16_RemainsWhenUsed) { + const std::string kTest = R"( + OpCapability Int16 +; CHECK: OpCapability Int16 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %int = OpTypeInt 16 1 + %3 = OpTypeFunction %void + %1 = OpFunction %void None %3 + %6 = OpLabel + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(TrimCapabilitiesPassTest, UInt16_RemainsWhenUsed) { + const std::string kTest = R"( + OpCapability Int16 +; CHECK: OpCapability Int16 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" + %void = OpTypeVoid + %uint = OpTypeInt 16 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 36be541ee3f6592ddecffa295c37f72b17fb15d1 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 11 Jan 2024 10:55:04 -0500 Subject: [PATCH 344/523] Remove unnecessary debug code (#5523) --- test/opt/type_manager_test.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/opt/type_manager_test.cpp b/test/opt/type_manager_test.cpp index cb30171158..946f06cc08 100644 --- a/test/opt/type_manager_test.cpp +++ b/test/opt/type_manager_test.cpp @@ -944,15 +944,12 @@ OpMemoryModel Logical GLSL450 std::vector> types = GenerateAllTypes(); uint32_t id = 1u; for (auto& t : types) { - std::cout << ". id " << id << std::endl; context->get_type_mgr()->RegisterType(id, *t); EXPECT_EQ(*t, *context->get_type_mgr()->GetType(id)); } - std::cout << "clear" << id << std::endl; types.clear(); for (; id > 0; --id) { - std::cout << ". remove id " << id << std::endl; context->get_type_mgr()->RemoveId(id); EXPECT_EQ(nullptr, context->get_type_mgr()->GetType(id)); } From 01ee1bf317611f52c8d3f2eb0fc451d266f826ee Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 11 Jan 2024 16:59:38 +0000 Subject: [PATCH 345/523] Roll external/googletest/ b10fad38c..76bb2afb8 (1 commit) (#5485) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Roll external/googletest/ b10fad38c..7c07a8636 (12 commits) https://github.com/google/googletest/compare/b10fad38c402...7c07a863693b $ git log b10fad38c..7c07a8636 --date=short --no-merges --format='%ad %ae %s' 2024-01-09 dmauro Update CI builds to use Bazel 7.0.0 2024-01-09 absl-team Add a note about argv requiring NULL termination. 2024-01-09 krzysio Disable -Wfloat-equal in AppropriateResolution(). 2023-12-28 absl-team Accept move-only callables in `InvokeArguments` 2023-12-22 absl-team Minor documentation correction. 2023-12-19 dmauro Fix broken links in primer.md 2023-12-18 absl-team Fix data race in leak detection 2023-12-12 absl-team Add `FAIL_AT` macro variant of `FAIL` matching `ADD_FAILURE`, `ADD_FAILURE_AT` 2023-12-11 tomhughes Remove unnecessary conversion 2023-12-04 dmauro Skip find_package(Python3) when not building tests 2023-12-01 tamas.kenez Allow using external absl and re2. 2023-11-27 absl-team Implement `testing::Rethrow` to throw exceptions more easily via `std::exception_ptr` Created with: roll-dep external/googletest * Roll external/re2/ 7e0c1a9e2..c042630ed (5 commits) https://github.com/google/re2/compare/7e0c1a9e2417...c042630ed8f9 $ git log 7e0c1a9e2..c042630ed --date=short --no-merges --format='%ad %ae %s' 2023-12-22 junyer Report `kRegexpBadPerlOp` for look-behind assertions. 2023-12-14 junyer Delete the `AUTHORS` and `CONTRIBUTORS` files. 2023-12-14 junyer We don't need to set `--enable_bzlmod` anymore. 2023-12-12 junyer Fix an old bug that can manifest during factoring. 2023-12-11 olivier.mengue doc/mksyntaxgo: add Go doc links Created with: roll-dep external/re2 * Roll external/spirv-headers/ 1c6bb2743..bdd1b2ab1 (5 commits) https://github.com/KhronosGroup/SPIRV-Headers/compare/1c6bb2743599...bdd1b2ab1f03 $ git log 1c6bb2743..bdd1b2ab1 --date=short --no-merges --format='%ad %ae %s' 2024-01-10 gleese Reserve an FPFastMathMode bit (#401) 2024-01-10 49699333+dependabot[bot] Bump the github-actions group with 1 update (#400) 2024-01-10 89833130+rjodinchr Publish the header for the vulkan-shader-profiler embedded reflection… (#398) 2024-01-03 dmitry.sidorov Upstream tokens for SPV_INTEL_masked_gather_scatter (#391) 2024-01-03 joycebrum feat: Create dependabot.yml (#397) 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 a27f4fca18..883d6b6445 100644 --- a/DEPS +++ b/DEPS @@ -7,13 +7,13 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': 'b10fad38c4026a29ea6561ab15fc4818170d1c10', + 'googletest_revision': '7c07a863693b0c831f80473f7c6905d7e458682c', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '7e0c1a9e2417e70e5f0efc323267ac71d1fa0685', - 'spirv_headers_revision': '1c6bb2743599e6eb6f37b2969acc0aef812e32e3', + 're2_revision': 'c042630ed8f94c32106d92a6a8deb192dabe558d', + 'spirv_headers_revision': 'bdd1b2ab1f03e616047bbcf8971157dccd50c792', } deps = { From 155728b2e9951b7d22c777c343d41ceed8343364 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Fri, 12 Jan 2024 14:45:17 -0500 Subject: [PATCH 346/523] Add preserver-interface option to spirv-opt (#5524) The optimizer is able to preserve the interface variables of the shaders, but that feature has not been exposed to the command line tool. This commit adds an option `--preserve-interface` to spirv-opt that will cause all calls to ADCE to leave the input and output variables, even if the variable is unused. It will apply regardless of where the option appears on the command line. Fixes #5522 --- include/spirv-tools/libspirv.h | 7 +++++ include/spirv-tools/optimizer.hpp | 15 ++++++---- source/opt/optimizer.cpp | 47 +++++++++++++++++++++++-------- tools/opt/opt.cpp | 10 ++++++- 4 files changed, 61 insertions(+), 18 deletions(-) diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index b70f084a8e..abdfc15d4f 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -966,9 +966,16 @@ SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassFromFlag( spv_optimizer_t* optimizer, const char* flag); // Registers passes specified by length number of flags in an optimizer object. +// Passes may remove interface variables that are unused. SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassesFromFlags( spv_optimizer_t* optimizer, const char** flags, const size_t flag_count); +// Registers passes specified by length number of flags in an optimizer object. +// Passes will not remove interface variables. +SPIRV_TOOLS_EXPORT bool +spvOptimizerRegisterPassesFromFlagsWhilePreservingTheInterface( + spv_optimizer_t* optimizer, const char** flags, const size_t flag_count); + // Optimizes the SPIR-V code of size |word_count| pointed to by |binary| and // returns an optimized spv_binary in |optimized_binary|. // diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp index 53ebc59f00..bc4f5bee89 100644 --- a/include/spirv-tools/optimizer.hpp +++ b/include/spirv-tools/optimizer.hpp @@ -100,8 +100,6 @@ class Optimizer { // // If |preserve_interface| is true, all non-io variables in the entry point // interface are considered live and are not eliminated. - // |preserve_interface| should be true if HLSL is generated - // from the SPIR-V bytecode. Optimizer& RegisterPerformancePasses(); Optimizer& RegisterPerformancePasses(bool preserve_interface); @@ -111,8 +109,6 @@ class Optimizer { // // If |preserve_interface| is true, all non-io variables in the entry point // interface are considered live and are not eliminated. - // |preserve_interface| should be true if HLSL is generated - // from the SPIR-V bytecode. Optimizer& RegisterSizePasses(); Optimizer& RegisterSizePasses(bool preserve_interface); @@ -127,8 +123,6 @@ class Optimizer { // // If |preserve_interface| is true, all non-io variables in the entry point // interface are considered live and are not eliminated. - // |preserve_interface| should be true if HLSL is generated - // from the SPIR-V bytecode. Optimizer& RegisterLegalizationPasses(); Optimizer& RegisterLegalizationPasses(bool preserve_interface); @@ -139,8 +133,13 @@ class Optimizer { // error message is emitted to the MessageConsumer object (use // Optimizer::SetMessageConsumer to define a message consumer, if needed). // + // If |preserve_interface| is true, all non-io variables in the entry point + // interface are considered live and are not eliminated. + // // If all the passes are registered successfully, it returns true. bool RegisterPassesFromFlags(const std::vector& flags); + bool RegisterPassesFromFlags(const std::vector& flags, + bool preserve_interface); // Registers the optimization pass associated with |flag|. This only accepts // |flag| values of the form "--pass_name[=pass_args]". If no such pass @@ -157,7 +156,11 @@ class Optimizer { // // --legalize-hlsl: Registers all passes that legalize SPIR-V generated by an // HLSL front-end. + // + // If |preserve_interface| is true, all non-io variables in the entry point + // interface are considered live and are not eliminated. bool RegisterPassFromFlag(const std::string& flag); + bool RegisterPassFromFlag(const std::string& flag, bool preserve_interface); // Validates that |flag| has a valid format. Strings accepted: // diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index d865cf1d47..7cfc89f754 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -33,6 +33,15 @@ namespace spvtools { +std::vector GetVectorOfStrings(const char** strings, + const size_t string_count) { + std::vector result; + for (uint32_t i = 0; i < string_count; i++) { + result.emplace_back(strings[i]); + } + return result; +} + struct Optimizer::PassToken::Impl { Impl(std::unique_ptr p) : pass(std::move(p)) {} @@ -256,8 +265,13 @@ Optimizer& Optimizer::RegisterSizePasses(bool preserve_interface) { Optimizer& Optimizer::RegisterSizePasses() { return RegisterSizePasses(false); } bool Optimizer::RegisterPassesFromFlags(const std::vector& flags) { + return RegisterPassesFromFlags(flags, false); +} + +bool Optimizer::RegisterPassesFromFlags(const std::vector& flags, + bool preserve_interface) { for (const auto& flag : flags) { - if (!RegisterPassFromFlag(flag)) { + if (!RegisterPassFromFlag(flag, preserve_interface)) { return false; } } @@ -281,6 +295,11 @@ bool Optimizer::FlagHasValidForm(const std::string& flag) const { } bool Optimizer::RegisterPassFromFlag(const std::string& flag) { + return RegisterPassFromFlag(flag, false); +} + +bool Optimizer::RegisterPassFromFlag(const std::string& flag, + bool preserve_interface) { if (!FlagHasValidForm(flag)) { return false; } @@ -342,7 +361,7 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { } else if (pass_name == "descriptor-scalar-replacement") { RegisterPass(CreateDescriptorScalarReplacementPass()); } else if (pass_name == "eliminate-dead-code-aggressive") { - RegisterPass(CreateAggressiveDCEPass()); + RegisterPass(CreateAggressiveDCEPass(preserve_interface)); } else if (pass_name == "eliminate-insert-extract") { RegisterPass(CreateInsertExtractElimPass()); } else if (pass_name == "eliminate-local-single-block") { @@ -513,11 +532,11 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { } else if (pass_name == "fix-storage-class") { RegisterPass(CreateFixStorageClassPass()); } else if (pass_name == "O") { - RegisterPerformancePasses(); + RegisterPerformancePasses(preserve_interface); } else if (pass_name == "Os") { - RegisterSizePasses(); + RegisterSizePasses(preserve_interface); } else if (pass_name == "legalize-hlsl") { - RegisterLegalizationPasses(); + RegisterLegalizationPasses(preserve_interface); } else if (pass_name == "remove-unused-interface-variables") { RegisterPass(CreateRemoveUnusedInterfaceVariablesPass()); } else if (pass_name == "graphics-robust-access") { @@ -1170,13 +1189,19 @@ SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassFromFlag( SPIRV_TOOLS_EXPORT bool spvOptimizerRegisterPassesFromFlags( spv_optimizer_t* optimizer, const char** flags, const size_t flag_count) { - std::vector opt_flags; - for (uint32_t i = 0; i < flag_count; i++) { - opt_flags.emplace_back(flags[i]); - } + std::vector opt_flags = + spvtools::GetVectorOfStrings(flags, flag_count); + return reinterpret_cast(optimizer) + ->RegisterPassesFromFlags(opt_flags, false); +} - return reinterpret_cast(optimizer)-> - RegisterPassesFromFlags(opt_flags); +SPIRV_TOOLS_EXPORT bool +spvOptimizerRegisterPassesFromFlagsWhilePreservingTheInterface( + spv_optimizer_t* optimizer, const char** flags, const size_t flag_count) { + std::vector opt_flags = + spvtools::GetVectorOfStrings(flags, flag_count); + return reinterpret_cast(optimizer) + ->RegisterPassesFromFlags(opt_flags, true); } SPIRV_TOOLS_EXPORT diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 3dfa021fdd..24724e59fa 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -392,6 +392,11 @@ Options (in lexicographical order):)", Ensure that the optimizer preserves all bindings declared within the module, even when those bindings are unused.)"); printf(R"( + --preserve-interface + Ensure that input and output variables are not removed from the + shader, even if they are unused. Note that this option applies to + all passes that will be run regardless of the order of the flags.)"); + printf(R"( --preserve-spec-constants Ensure that the optimizer preserves all specialization constants declared within the module, even when those constants are unused.)"); @@ -701,6 +706,7 @@ OptStatus ParseFlags(int argc, const char** argv, spvtools::ValidatorOptions* validator_options, spvtools::OptimizerOptions* optimizer_options) { std::vector pass_flags; + bool preserve_interface = true; for (int argi = 1; argi < argc; ++argi) { const char* cur_arg = argv[argi]; if ('-' == cur_arg[0]) { @@ -790,6 +796,8 @@ OptStatus ParseFlags(int argc, const char** argv, validator_options->SetSkipBlockLayout(true); } else if (0 == strcmp(cur_arg, "--relax-struct-store")) { validator_options->SetRelaxStructStore(true); + } else if (0 == strcmp(cur_arg, "--preserve-interface")) { + preserve_interface = true; } else { // Some passes used to accept the form '--pass arg', canonicalize them // to '--pass=arg'. @@ -812,7 +820,7 @@ OptStatus ParseFlags(int argc, const char** argv, } } - if (!optimizer->RegisterPassesFromFlags(pass_flags)) { + if (!optimizer->RegisterPassesFromFlags(pass_flags, preserve_interface)) { return {OPT_STOP, 1}; } From 5dbdc7b60b9b4f0402d35ca65259d4f3e5ecab7c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jan 2024 10:57:32 -0500 Subject: [PATCH 347/523] build(deps): bump the github-actions group with 4 updates (#5531) Bumps the github-actions group with 4 updates: [actions/cache](https://github.com/actions/cache), [lukka/get-cmake](https://github.com/lukka/get-cmake), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [github/codeql-action](https://github.com/github/codeql-action). Updates `actions/cache` from 3.3.2 to 3.3.3 - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/704facf57e6136b1bc63b828d79edcd491f0ee84...e12d46a63a90f2fae62d114769bbf2a179198b5c) Updates `lukka/get-cmake` from 3.27.9 to 3.28.1 - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/4865386b66955d11be0abf8c112d0230023e742a...2654d8ee382b9b6cbbfe6487653b8629b4e062c8) Updates `actions/upload-artifact` from 3.1.3 to 4.1.0 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/a8a3f3ad30e3422c9c7b888a15615d19a852ae32...1eb3cb2b3e0f29609092a73eb033bb759a334595) Updates `github/codeql-action` from 2.22.8 to 3.23.0 - [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/407ffafae6a767df3e0230c3df91b6443ae8df75...e5f05b81d5b6ff8cfa111c80c22c5fd02a384118) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: lukka/get-cmake 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-major dependency-group: github-actions - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/bazel.yml | 2 +- .github/workflows/ios.yml | 2 +- .github/workflows/scorecard.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 347f884ff5..d13a16b53f 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -24,7 +24,7 @@ jobs: - name: Download dependencies run: python3 utils/git-sync-deps - name: Mount Bazel cache - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + uses: actions/cache@e12d46a63a90f2fae62d114769bbf2a179198b5c # v3.3.3 with: path: ~/.bazel/cache key: bazel-cache-${{ runner.os }} diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 68bf59b6ef..8b8cca918b 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@4865386b66955d11be0abf8c112d0230023e742a # v3.27.9 + - uses: lukka/get-cmake@2654d8ee382b9b6cbbfe6487653b8629b4e062c8 # v3.28.1 - name: Download dependencies run: python3 utils/git-sync-deps # NOTE: The MacOS SDK ships universal binaries. CI should reflect this. diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 455e6f14c8..cfb5510ec1 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -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@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + uses: actions/upload-artifact@1eb3cb2b3e0f29609092a73eb033bb759a334595 # v4.1.0 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@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8 + uses: github/codeql-action/upload-sarif@e5f05b81d5b6ff8cfa111c80c22c5fd02a384118 # v3.23.0 with: sarif_file: results.sarif From c96fe8b943564fbab3424219d924d21cac2e877a Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Thu, 18 Jan 2024 01:18:23 +0900 Subject: [PATCH 348/523] spirv-val: Re-enable OpControlBarrier VU (#5527) --- source/val/validate_memory_semantics.cpp | 5 +--- source/val/validation_state.cpp | 2 ++ test/val/val_barriers_test.cpp | 38 ++++++++++++------------ 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/source/val/validate_memory_semantics.cpp b/source/val/validate_memory_semantics.cpp index c4f22a611e..dab7b5a194 100644 --- a/source/val/validate_memory_semantics.cpp +++ b/source/val/validate_memory_semantics.cpp @@ -203,15 +203,12 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _, "storage class"; } -#if 0 - // TODO(atgoo@github.com): this check fails Vulkan CTS, reenable once fixed. if (opcode == spv::Op::OpControlBarrier && value && !includes_storage_class) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) + << _.VkErrorID(4650) << spvOpcodeString(opcode) << ": expected Memory Semantics to include a Vulkan-supported " "storage class if Memory Semantics is not None"; } -#endif } if (opcode == spv::Op::OpAtomicFlagClear && diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 6685985b6e..13c07eec38 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -2125,6 +2125,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-None-04644); case 4645: return VUID_WRAP(VUID-StandaloneSpirv-None-04645); + case 4650: + return VUID_WRAP(VUID-StandaloneSpirv-OpControlBarrier-04650); case 4651: return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-04651); case 4652: diff --git a/test/val/val_barriers_test.cpp b/test/val/val_barriers_test.cpp index f160904078..ba8ac7d46b 100644 --- a/test/val/val_barriers_test.cpp +++ b/test/val/val_barriers_test.cpp @@ -410,7 +410,7 @@ OpControlBarrier %subgroup %cross_device %none TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupNonComputeMemoryFailure) { const std::string body = R"( -OpControlBarrier %subgroup %workgroup %acquire +OpControlBarrier %subgroup %workgroup %acquire_release_workgroup )"; CompileSuccessfully(GenerateVulkanVertexShaderCode(body), SPV_ENV_VULKAN_1_1); @@ -427,7 +427,7 @@ OpControlBarrier %subgroup %workgroup %acquire TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupNonComputeExecutionFailure) { const std::string body = R"( -OpControlBarrier %workgroup %subgroup %acquire +OpControlBarrier %workgroup %subgroup %acquire_release_workgroup )"; CompileSuccessfully(GenerateVulkanVertexShaderCode(body), SPV_ENV_VULKAN_1_1); @@ -442,7 +442,7 @@ OpControlBarrier %workgroup %subgroup %acquire TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupComputeSuccess) { const std::string body = R"( -OpControlBarrier %workgroup %workgroup %acquire +OpControlBarrier %workgroup %workgroup %acquire_uniform_workgroup )"; CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_1); @@ -451,7 +451,7 @@ OpControlBarrier %workgroup %workgroup %acquire TEST_F(ValidateBarriers, OpControlBarrierVulkan1p1WorkgroupNonComputeSuccess) { const std::string body = R"( -OpControlBarrier %subgroup %subgroup %acquire +OpControlBarrier %subgroup %subgroup %acquire_uniform_workgroup )"; CompileSuccessfully(GenerateVulkanVertexShaderCode(body), SPV_ENV_VULKAN_1_1); @@ -495,15 +495,15 @@ OpControlBarrier %device %device %acquire_and_release_uniform "AcquireRelease or SequentiallyConsistent")); } -// TODO(atgoo@github.com): the corresponding check fails Vulkan CTS, -// reenable once fixed. -TEST_F(ValidateBarriers, DISABLED_OpControlBarrierVulkanSubgroupStorageClass) { +TEST_F(ValidateBarriers, OpControlBarrierVulkanSubgroupStorageClass) { const std::string body = R"( OpControlBarrier %workgroup %device %acquire_release_subgroup )"; CompileSuccessfully(GenerateShaderCode(body), SPV_ENV_VULKAN_1_0); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpControlBarrier-04650")); EXPECT_THAT( getDiagnosticString(), HasSubstr( @@ -513,7 +513,7 @@ OpControlBarrier %workgroup %device %acquire_release_subgroup TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionFragment1p1) { const std::string body = R"( -OpControlBarrier %subgroup %subgroup %acquire_release_subgroup +OpControlBarrier %subgroup %subgroup %acquire_release_workgroup )"; CompileSuccessfully(GenerateShaderCode(body, "", "Fragment"), @@ -523,7 +523,7 @@ OpControlBarrier %subgroup %subgroup %acquire_release_subgroup TEST_F(ValidateBarriers, OpControlBarrierWorkgroupExecutionFragment1p1) { const std::string body = R"( -OpControlBarrier %workgroup %workgroup %acquire_release +OpControlBarrier %workgroup %workgroup %acquire_release_workgroup )"; CompileSuccessfully(GenerateShaderCode(body, "", "Fragment"), @@ -541,7 +541,7 @@ OpControlBarrier %workgroup %workgroup %acquire_release TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionFragment1p0) { const std::string body = R"( -OpControlBarrier %subgroup %workgroup %acquire_release +OpControlBarrier %subgroup %workgroup %acquire_release_workgroup )"; CompileSuccessfully(GenerateShaderCode(body, "", "Fragment"), @@ -556,7 +556,7 @@ OpControlBarrier %subgroup %workgroup %acquire_release TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionVertex1p1) { const std::string body = R"( -OpControlBarrier %subgroup %subgroup %acquire_release_subgroup +OpControlBarrier %subgroup %subgroup %acquire_release_workgroup )"; CompileSuccessfully(GenerateShaderCode(body, "", "Vertex"), @@ -566,7 +566,7 @@ OpControlBarrier %subgroup %subgroup %acquire_release_subgroup TEST_F(ValidateBarriers, OpControlBarrierWorkgroupExecutionVertex1p1) { const std::string body = R"( -OpControlBarrier %workgroup %workgroup %acquire_release +OpControlBarrier %workgroup %workgroup %acquire_release_workgroup )"; CompileSuccessfully(GenerateShaderCode(body, "", "Vertex"), @@ -584,7 +584,7 @@ OpControlBarrier %workgroup %workgroup %acquire_release TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionVertex1p0) { const std::string body = R"( -OpControlBarrier %subgroup %workgroup %acquire_release +OpControlBarrier %subgroup %workgroup %acquire_release_workgroup )"; CompileSuccessfully(GenerateShaderCode(body, "", "Vertex"), @@ -599,7 +599,7 @@ OpControlBarrier %subgroup %workgroup %acquire_release TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionGeometry1p1) { const std::string body = R"( -OpControlBarrier %subgroup %subgroup %acquire_release_subgroup +OpControlBarrier %subgroup %subgroup %acquire_release_workgroup )"; CompileSuccessfully( @@ -610,7 +610,7 @@ OpControlBarrier %subgroup %subgroup %acquire_release_subgroup TEST_F(ValidateBarriers, OpControlBarrierWorkgroupExecutionGeometry1p1) { const std::string body = R"( -OpControlBarrier %workgroup %workgroup %acquire_release +OpControlBarrier %workgroup %workgroup %acquire_release_workgroup )"; CompileSuccessfully( @@ -629,7 +629,7 @@ OpControlBarrier %workgroup %workgroup %acquire_release TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionGeometry1p0) { const std::string body = R"( -OpControlBarrier %subgroup %workgroup %acquire_release +OpControlBarrier %subgroup %workgroup %acquire_release_workgroup )"; CompileSuccessfully( @@ -646,7 +646,7 @@ OpControlBarrier %subgroup %workgroup %acquire_release TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionTessellationEvaluation1p1) { const std::string body = R"( -OpControlBarrier %subgroup %subgroup %acquire_release_subgroup +OpControlBarrier %subgroup %subgroup %acquire_release_workgroup )"; CompileSuccessfully(GenerateShaderCode(body, "OpCapability Tessellation\n", @@ -658,7 +658,7 @@ OpControlBarrier %subgroup %subgroup %acquire_release_subgroup TEST_F(ValidateBarriers, OpControlBarrierWorkgroupExecutionTessellationEvaluation1p1) { const std::string body = R"( -OpControlBarrier %workgroup %workgroup %acquire_release +OpControlBarrier %workgroup %workgroup %acquire_release_workgroup )"; CompileSuccessfully(GenerateShaderCode(body, "OpCapability Tessellation\n", @@ -678,7 +678,7 @@ OpControlBarrier %workgroup %workgroup %acquire_release TEST_F(ValidateBarriers, OpControlBarrierSubgroupExecutionTessellationEvaluation1p0) { const std::string body = R"( -OpControlBarrier %subgroup %workgroup %acquire_release +OpControlBarrier %subgroup %workgroup %acquire_release_workgroup )"; CompileSuccessfully(GenerateShaderCode(body, "OpCapability Tessellation\n", From ed6835aff7162cbc50c9721c4c3b8c16be7e64d8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 19 Jan 2024 10:05:04 -0500 Subject: [PATCH 349/523] Roll external/re2/ c042630ed..32c181e0a (1 commit) (#5532) * Roll external/googletest/ 7c07a8636..96cd50c08 (3 commits) https://github.com/google/googletest/compare/7c07a863693b...96cd50c082d8 $ git log 7c07a8636..96cd50c08 --date=short --no-merges --format='%ad %ae %s' 2024-01-18 absl-team If GTEST_NO_ABSL_FLAGS is #defined, then the Abseil flag library will not be used by googletest, even if GTEST_HAS_ABSL is #defined. 2024-01-16 absl-team Make posix::FileNo available under !GTEST_HAS_FILE_SYSTEM 2024-01-16 absl-team Do not emit stack traces for messages generated by GTEST_SKIP() Created with: roll-dep external/googletest * Roll external/re2/ c042630ed..264e71e88 (13 commits) https://github.com/google/re2/compare/c042630ed8f9...264e71e88e1c $ git log c042630ed..264e71e88 --date=short --no-merges --format='%ad %ae %s' 2024-01-18 junyer Make @local_config_cc visible as a temporary hack. 2024-01-18 junyer Register the local 32-bit C++ toolchain with highest priority. 2024-01-18 junyer Alas, `--extra_execution_platforms` didn't help. 2024-01-18 junyer Attempt to convince Bazel 7 that X64 can build for X86. 2024-01-18 junyer Update @pybind11_bazel to version 2.11.1.bzl.1. 2024-01-16 junyer Print debug information during toolchain resolution. 2024-01-16 junyer Register the local Python toolchain with highest priority. 2024-01-16 junyer Try updating @rules_python to version 0.28.0. 2024-01-16 junyer Revert "Try dropping the CPU constraint values on Windows." 2024-01-16 junyer Try using @apple_support for toolchains on macOS. 2024-01-16 junyer Try dropping the CPU constraint values on Windows. 2024-01-16 junyer Try to get things working again with Bazel 7. 2024-01-15 junyer Try to lock down workflow permissions. Created with: roll-dep external/re2 * Roll external/spirv-headers/ bdd1b2ab1..7b0309708 (2 commits) https://github.com/KhronosGroup/SPIRV-Headers/compare/bdd1b2ab1f03...7b0309708da5 $ git log bdd1b2ab1..7b0309708 --date=short --no-merges --format='%ad %ae %s' 2024-01-17 robin Register Zig Compiler tool (#405) 2024-01-17 robin Add a Source Language for Zig (#403) 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 883d6b6445..866f98e91a 100644 --- a/DEPS +++ b/DEPS @@ -7,13 +7,13 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '7c07a863693b0c831f80473f7c6905d7e458682c', + 'googletest_revision': '96cd50c082d880a9aab6455dcc5817cfbf0ea45f', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': 'c042630ed8f94c32106d92a6a8deb192dabe558d', - 'spirv_headers_revision': 'bdd1b2ab1f03e616047bbcf8971157dccd50c792', + 're2_revision': '264e71e88e1c8a4b5ec326e70e9cf1d476f58a58', + 'spirv_headers_revision': '7b0309708da5126b89e4ce6f19835f36dc912f2f', } deps = { From 3e6bdd0f99655b1bc6a54aa73e5bfaaa4252198b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Jan 2024 10:27:11 -0500 Subject: [PATCH 350/523] build(deps): bump the github-actions group with 3 updates (#5537) Bumps the github-actions group with 3 updates: [actions/cache](https://github.com/actions/cache), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [github/codeql-action](https://github.com/github/codeql-action). Updates `actions/cache` from 3.3.3 to 4.0.0 - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/e12d46a63a90f2fae62d114769bbf2a179198b5c...13aacd865c20de90d75de3b17ebe84f7a17d57d2) Updates `actions/upload-artifact` from 4.1.0 to 4.2.0 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/1eb3cb2b3e0f29609092a73eb033bb759a334595...694cdabd8bdb0f10b2cea11669e1bf5453eed0a6) Updates `github/codeql-action` from 3.23.0 to 3.23.1 - [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/e5f05b81d5b6ff8cfa111c80c22c5fd02a384118...0b21cf2492b6b02c465a3e5d7c473717ad7721ba) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-minor 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/bazel.yml | 2 +- .github/workflows/scorecard.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index d13a16b53f..bd90e82e9c 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -24,7 +24,7 @@ jobs: - name: Download dependencies run: python3 utils/git-sync-deps - name: Mount Bazel cache - uses: actions/cache@e12d46a63a90f2fae62d114769bbf2a179198b5c # v3.3.3 + uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ~/.bazel/cache key: bazel-cache-${{ runner.os }} diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index cfb5510ec1..35bc0cb321 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -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@1eb3cb2b3e0f29609092a73eb033bb759a334595 # v4.1.0 + uses: actions/upload-artifact@694cdabd8bdb0f10b2cea11669e1bf5453eed0a6 # v4.2.0 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@e5f05b81d5b6ff8cfa111c80c22c5fd02a384118 # v3.23.0 + uses: github/codeql-action/upload-sarif@0b21cf2492b6b02c465a3e5d7c473717ad7721ba # v3.23.1 with: sarif_file: results.sarif From 359012927808c5aeb447b52d46cc0971b3b7e107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 22 Jan 2024 22:06:09 +0100 Subject: [PATCH 351/523] workflow: add vulkan-sdk tags as release tags (#5518) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This workflow creates a new release on the github page. When LunarG is done with the release, tags are added to the repo. When this happens, we should publish a release. Signed-off-by: Nathan Gauër --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 50e32a9047..f3b3de9199 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,6 +6,7 @@ on: push: tags: - 'v[0-9]+.[0-9]+' + - 'vulkan-sdk-[0-9]+.[0-9]+.[0-9]+.[0-9]+' - '!v[0-9]+.[0-9]+.rc*' jobs: From 14000ad47a4d758166a320be5c399cae5ba00839 Mon Sep 17 00:00:00 2001 From: David Neto Date: Tue, 23 Jan 2024 15:42:34 -0500 Subject: [PATCH 352/523] Use python3 explicitly. (#5540) Some Linux images don't ship with a plain 'python' --- test/scripts/test_compact_ids.py | 4 ++-- utils/check_copyright.py | 2 +- utils/check_symbol_exports.py | 2 +- utils/fixup_fuzz_result.py | 2 +- utils/generate_changelog.py | 2 +- utils/generate_grammar_tables.py | 2 +- utils/generate_registry_tables.py | 2 +- utils/generate_vim_syntax.py | 2 +- utils/update_build_version.py | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/test/scripts/test_compact_ids.py b/test/scripts/test_compact_ids.py index 6ca6e67b2c..b1d53870d7 100644 --- a/test/scripts/test_compact_ids.py +++ b/test/scripts/test_compact_ids.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2017 Google Inc. # Licensed under the Apache License, Version 2.0 (the "License"); @@ -47,7 +47,7 @@ def print_usage(): template= \ """{script} tests correctness of opt pass tools/opt --compact-ids -USAGE: python {script} [] +USAGE: python3 {script} [] Requires tools/spirv-dis, tools/spirv-as and tools/spirv-opt to be in path (call the script from the SPIRV-Tools build output directory). diff --git a/utils/check_copyright.py b/utils/check_copyright.py index e3e74bc9d2..a849d04672 100755 --- a/utils/check_copyright.py +++ b/utils/check_copyright.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # coding=utf-8 # Copyright (c) 2016 Google Inc. # diff --git a/utils/check_symbol_exports.py b/utils/check_symbol_exports.py index e1ca0b7888..e44294fe8b 100755 --- a/utils/check_symbol_exports.py +++ b/utils/check_symbol_exports.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2017 Google Inc. # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/fixup_fuzz_result.py b/utils/fixup_fuzz_result.py index 9fe54a3cc4..5b14a7db9b 100755 --- a/utils/fixup_fuzz_result.py +++ b/utils/fixup_fuzz_result.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2018 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/generate_changelog.py b/utils/generate_changelog.py index 54db728285..348bc50a6a 100644 --- a/utils/generate_changelog.py +++ b/utils/generate_changelog.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2023 Google Inc. # diff --git a/utils/generate_grammar_tables.py b/utils/generate_grammar_tables.py index e6a145583f..48f83c33ab 100755 --- a/utils/generate_grammar_tables.py +++ b/utils/generate_grammar_tables.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2016 Google Inc. # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/generate_registry_tables.py b/utils/generate_registry_tables.py index 14d4909fa6..69628faada 100755 --- a/utils/generate_registry_tables.py +++ b/utils/generate_registry_tables.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2016 Google Inc. # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/generate_vim_syntax.py b/utils/generate_vim_syntax.py index da7e99ba77..5c9c6b21ae 100755 --- a/utils/generate_vim_syntax.py +++ b/utils/generate_vim_syntax.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2016 Google Inc. # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/utils/update_build_version.py b/utils/update_build_version.py index f3d05b5d31..bb66e18a5a 100755 --- a/utils/update_build_version.py +++ b/utils/update_build_version.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (c) 2016 Google Inc. # From de3d5acc04fd203e3e5120a00f168465ecb2e4e4 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Thu, 25 Jan 2024 09:39:49 -0500 Subject: [PATCH 353/523] Add tooling support for SPV_KHR_maximal_reconvergence (#5542) * Validation for SPV_KHR_maximal_reconvergence * Add pass to add/remove maximal reconvergence execution mode --------- Co-authored-by: David Neto --- Android.mk | 1 + BUILD.gn | 2 + DEPS | 2 +- include/spirv-tools/optimizer.hpp | 4 + source/opt/CMakeLists.txt | 2 + source/opt/modify_maximal_reconvergence.cpp | 103 ++++++ source/opt/modify_maximal_reconvergence.h | 53 +++ source/opt/optimizer.cpp | 22 ++ source/opt/passes.h | 1 + source/val/validate_cfg.cpp | 96 ++++++ test/operand_capabilities_test.cpp | 3 +- test/opt/CMakeLists.txt | 1 + .../opt/modify_maximal_reconvergence_test.cpp | 312 +++++++++++++++++ test/text_to_binary.extension_test.cpp | 17 + test/val/val_cfg_test.cpp | 315 ++++++++++++++++++ test/val/val_modes_test.cpp | 22 ++ 16 files changed, 954 insertions(+), 2 deletions(-) create mode 100644 source/opt/modify_maximal_reconvergence.cpp create mode 100644 source/opt/modify_maximal_reconvergence.h create mode 100644 test/opt/modify_maximal_reconvergence_test.cpp diff --git a/Android.mk b/Android.mk index afa0403933..3cf3f19b1d 100644 --- a/Android.mk +++ b/Android.mk @@ -157,6 +157,7 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/loop_utils.cpp \ source/opt/mem_pass.cpp \ source/opt/merge_return_pass.cpp \ + source/opt/modify_maximal_reconvergence.cpp \ source/opt/module.cpp \ source/opt/optimizer.cpp \ source/opt/pass.cpp \ diff --git a/BUILD.gn b/BUILD.gn index 9ff36d83db..7c42a99a53 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -737,6 +737,8 @@ static_library("spvtools_opt") { "source/opt/mem_pass.h", "source/opt/merge_return_pass.cpp", "source/opt/merge_return_pass.h", + "source/opt/modify_maximal_reconvergence.cpp", + "source/opt/modify_maximal_reconvergence.h", "source/opt/module.cpp", "source/opt/module.h", "source/opt/null_pass.h", diff --git a/DEPS b/DEPS index 866f98e91a..7ba5521ae0 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': '264e71e88e1c8a4b5ec326e70e9cf1d476f58a58', - 'spirv_headers_revision': '7b0309708da5126b89e4ce6f19835f36dc912f2f', + 'spirv_headers_revision': 'ae6a8b39717523d96683bc0d20b541944e28072f', } deps = { diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp index bc4f5bee89..926e438fe2 100644 --- a/include/spirv-tools/optimizer.hpp +++ b/include/spirv-tools/optimizer.hpp @@ -1003,6 +1003,10 @@ Optimizer::PassToken CreateSwitchDescriptorSetPass(uint32_t ds_from, // OpBeginInterlockInvocationEXT and one OpEndInterlockInvocationEXT, in that // order. Optimizer::PassToken CreateInvocationInterlockPlacementPass(); + +// Creates a pass to add/remove maximal reconvergence execution mode. +// This pass either adds or removes maximal reconvergence from all entry points. +Optimizer::PassToken CreateModifyMaximalReconvergencePass(bool add); } // namespace spvtools #endif // INCLUDE_SPIRV_TOOLS_OPTIMIZER_HPP_ diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt index 6ebbfbf005..4e7d92d5ea 100644 --- a/source/opt/CMakeLists.txt +++ b/source/opt/CMakeLists.txt @@ -94,6 +94,7 @@ set(SPIRV_TOOLS_OPT_SOURCES loop_unswitch_pass.h mem_pass.h merge_return_pass.h + modify_maximal_reconvergence.h module.h null_pass.h passes.h @@ -214,6 +215,7 @@ set(SPIRV_TOOLS_OPT_SOURCES loop_unswitch_pass.cpp mem_pass.cpp merge_return_pass.cpp + modify_maximal_reconvergence.cpp module.cpp optimizer.cpp pass.cpp diff --git a/source/opt/modify_maximal_reconvergence.cpp b/source/opt/modify_maximal_reconvergence.cpp new file mode 100644 index 0000000000..dd79b6283f --- /dev/null +++ b/source/opt/modify_maximal_reconvergence.cpp @@ -0,0 +1,103 @@ +// Copyright (c) 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "modify_maximal_reconvergence.h" + +#include "source/opt/ir_context.h" +#include "source/util/make_unique.h" + +namespace spvtools { +namespace opt { + +Pass::Status ModifyMaximalReconvergence::Process() { + bool changed = false; + if (add_) { + changed = AddMaximalReconvergence(); + } else { + changed = RemoveMaximalReconvergence(); + } + return changed ? Pass::Status::SuccessWithChange + : Pass::Status::SuccessWithoutChange; +} + +bool ModifyMaximalReconvergence::AddMaximalReconvergence() { + bool changed = false; + bool has_extension = false; + bool has_shader = + context()->get_feature_mgr()->HasCapability(spv::Capability::Shader); + for (auto extension : context()->extensions()) { + if (extension.GetOperand(0).AsString() == "SPV_KHR_maximal_reconvergence") { + has_extension = true; + break; + } + } + + std::unordered_set entry_points_with_mode; + for (auto mode : get_module()->execution_modes()) { + if (spv::ExecutionMode(mode.GetSingleWordInOperand(1)) == + spv::ExecutionMode::MaximallyReconvergesKHR) { + entry_points_with_mode.insert(mode.GetSingleWordInOperand(0)); + } + } + + for (auto entry_point : get_module()->entry_points()) { + const uint32_t id = entry_point.GetSingleWordInOperand(1); + if (!entry_points_with_mode.count(id)) { + changed = true; + if (!has_extension) { + context()->AddExtension("SPV_KHR_maximal_reconvergence"); + has_extension = true; + } + if (!has_shader) { + context()->AddCapability(spv::Capability::Shader); + has_shader = true; + } + context()->AddExecutionMode(MakeUnique( + context(), spv::Op::OpExecutionMode, 0, 0, + std::initializer_list{ + {SPV_OPERAND_TYPE_ID, {id}}, + {SPV_OPERAND_TYPE_EXECUTION_MODE, + {static_cast( + spv::ExecutionMode::MaximallyReconvergesKHR)}}})); + entry_points_with_mode.insert(id); + } + } + + return changed; +} + +bool ModifyMaximalReconvergence::RemoveMaximalReconvergence() { + bool changed = false; + std::vector to_remove; + Instruction* mode = &*get_module()->execution_mode_begin(); + while (mode) { + if (mode->opcode() != spv::Op::OpExecutionMode && + mode->opcode() != spv::Op::OpExecutionModeId) { + break; + } + if (spv::ExecutionMode(mode->GetSingleWordInOperand(1)) == + spv::ExecutionMode::MaximallyReconvergesKHR) { + mode = context()->KillInst(mode); + changed = true; + } else { + mode = mode->NextNode(); + } + } + + changed |= + context()->RemoveExtension(Extension::kSPV_KHR_maximal_reconvergence); + return changed; +} +} // namespace opt +} // namespace spvtools diff --git a/source/opt/modify_maximal_reconvergence.h b/source/opt/modify_maximal_reconvergence.h new file mode 100644 index 0000000000..8d9a698e9e --- /dev/null +++ b/source/opt/modify_maximal_reconvergence.h @@ -0,0 +1,53 @@ +// Copyright (c) 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef LIBSPIRV_OPT_MODIFY_MAXIMAL_RECONVERGENCE_H_ +#define LIBSPIRV_OPT_MODIFY_MAXIMAL_RECONVERGENCE_H_ + +#include "pass.h" + +namespace spvtools { +namespace opt { + +// Modifies entry points to either add or remove MaximallyReconvergesKHR +// +// This pass will either add or remove MaximallyReconvergesKHR to all entry +// points in the module. When adding the execution mode, it does not attempt to +// determine whether any ray tracing invocation repack instructions might be +// executed because it is a runtime restriction. That is left to the user. +class ModifyMaximalReconvergence : public Pass { + public: + const char* name() const override { return "modify-maximal-reconvergence"; } + Status Process() override; + + explicit ModifyMaximalReconvergence(bool add = true) : Pass(), add_(add) {} + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisDefUse | + IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | + IRContext::kAnalysisCFG | IRContext::kAnalysisNameMap | + IRContext::kAnalysisConstants | IRContext::kAnalysisTypes; + } + + private: + bool AddMaximalReconvergence(); + bool RemoveMaximalReconvergence(); + + bool add_; +}; +} // namespace opt +} // namespace spvtools + +#endif // LIBSPIRV_OPT_MODIFY_MAXIMAL_RECONVERGENCE_H_ diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index 7cfc89f754..4d089f6a20 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -606,6 +606,23 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag, return false; } RegisterPass(CreateSwitchDescriptorSetPass(from_set, to_set)); + } else if (pass_name == "modify-maximal-reconvergence") { + if (pass_args.size() == 0) { + Error(consumer(), nullptr, {}, + "--modify-maximal-reconvergence requires an argument"); + return false; + } + if (pass_args == "add") { + RegisterPass(CreateModifyMaximalReconvergencePass(true)); + } else if (pass_args == "remove") { + RegisterPass(CreateModifyMaximalReconvergencePass(false)); + } else { + Errorf(consumer(), nullptr, {}, + "Invalid argument for --modify-maximal-reconvergence: %s (must be " + "'add' or 'remove')", + pass_args.c_str()); + return false; + } } else { Errorf(consumer(), nullptr, {}, "Unknown flag '--%s'. Use --help for a list of valid flags", @@ -1141,6 +1158,11 @@ Optimizer::PassToken CreateInvocationInterlockPlacementPass() { return MakeUnique( MakeUnique()); } + +Optimizer::PassToken CreateModifyMaximalReconvergencePass(bool add) { + return MakeUnique( + MakeUnique(add)); +} } // namespace spvtools extern "C" { diff --git a/source/opt/passes.h b/source/opt/passes.h index 305f578279..9d027fbf4c 100644 --- a/source/opt/passes.h +++ b/source/opt/passes.h @@ -65,6 +65,7 @@ #include "source/opt/loop_unroller.h" #include "source/opt/loop_unswitch_pass.h" #include "source/opt/merge_return_pass.h" +#include "source/opt/modify_maximal_reconvergence.h" #include "source/opt/null_pass.h" #include "source/opt/private_to_local_pass.h" #include "source/opt/reduce_load_size.h" diff --git a/source/val/validate_cfg.cpp b/source/val/validate_cfg.cpp index 7b3f7480f2..9b7161fc44 100644 --- a/source/val/validate_cfg.cpp +++ b/source/val/validate_cfg.cpp @@ -190,6 +190,8 @@ spv_result_t ValidateBranchConditional(ValidationState_t& _, "ID of an OpLabel instruction"; } + // A similar requirement for SPV_KHR_maximal_reconvergence is deferred until + // entry point call trees have been reconrded. if (_.version() >= SPV_SPIRV_VERSION_WORD(1, 6) && true_id == false_id) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "In SPIR-V 1.6 or later, True Label and False Label must be " @@ -875,6 +877,95 @@ spv_result_t StructuredControlFlowChecks( return SPV_SUCCESS; } +spv_result_t MaximalReconvergenceChecks(ValidationState_t& _) { + // Find all the entry points with the MaximallyReconvergencesKHR execution + // mode. + std::unordered_set maximal_funcs; + std::unordered_set maximal_entry_points; + for (auto entry_point : _.entry_points()) { + const auto* exec_modes = _.GetExecutionModes(entry_point); + if (exec_modes && + exec_modes->count(spv::ExecutionMode::MaximallyReconvergesKHR)) { + maximal_entry_points.insert(entry_point); + maximal_funcs.insert(entry_point); + } + } + + if (maximal_entry_points.empty()) { + return SPV_SUCCESS; + } + + // Find all the functions reachable from a maximal reconvergence entry point. + for (const auto& func : _.functions()) { + const auto& entry_points = _.EntryPointReferences(func.id()); + for (auto id : entry_points) { + if (maximal_entry_points.count(id)) { + maximal_funcs.insert(func.id()); + break; + } + } + } + + // Check for conditional branches with the same true and false targets. + for (const auto& inst : _.ordered_instructions()) { + if (inst.opcode() == spv::Op::OpBranchConditional) { + const auto true_id = inst.GetOperandAs(1); + const auto false_id = inst.GetOperandAs(2); + if (true_id == false_id && maximal_funcs.count(inst.function()->id())) { + return _.diag(SPV_ERROR_INVALID_ID, &inst) + << "In entry points using the MaximallyReconvergesKHR execution " + "mode, True Label and False Label must be different labels"; + } + } + } + + // Check for invalid multiple predecessors. Only loop headers, continue + // targets, merge targets or switch targets or defaults may have multiple + // unique predecessors. + for (const auto& func : _.functions()) { + if (!maximal_funcs.count(func.id())) continue; + + for (const auto* block : func.ordered_blocks()) { + std::unordered_set unique_preds; + const auto* preds = block->predecessors(); + if (!preds) continue; + + for (const auto* pred : *preds) { + unique_preds.insert(pred->id()); + } + if (unique_preds.size() < 2) continue; + + const auto* terminator = block->terminator(); + const auto index = terminator - &_.ordered_instructions()[0]; + const auto* pre_terminator = &_.ordered_instructions()[index - 1]; + if (pre_terminator->opcode() == spv::Op::OpLoopMerge) continue; + + const auto* label = _.FindDef(block->id()); + bool ok = false; + for (const auto& pair : label->uses()) { + const auto* use_inst = pair.first; + switch (use_inst->opcode()) { + case spv::Op::OpSelectionMerge: + case spv::Op::OpLoopMerge: + case spv::Op::OpSwitch: + ok = true; + break; + default: + break; + } + } + if (!ok) { + return _.diag(SPV_ERROR_INVALID_CFG, label) + << "In entry points using the MaximallyReconvergesKHR " + "execution mode, this basic block must not have multiple " + "unique predecessors"; + } + } + } + + return SPV_SUCCESS; +} + spv_result_t PerformCfgChecks(ValidationState_t& _) { for (auto& function : _.functions()) { // Check all referenced blocks are defined within a function @@ -999,6 +1090,11 @@ spv_result_t PerformCfgChecks(ValidationState_t& _) { return error; } } + + if (auto error = MaximalReconvergenceChecks(_)) { + return error; + } + return SPV_SUCCESS; } diff --git a/test/operand_capabilities_test.cpp b/test/operand_capabilities_test.cpp index 4872228170..6c4042dc2b 100644 --- a/test/operand_capabilities_test.cpp +++ b/test/operand_capabilities_test.cpp @@ -486,7 +486,8 @@ INSTANTIATE_TEST_SUITE_P( CASE1(DECORATION, Decoration::XfbBuffer, TransformFeedback), CASE1(DECORATION, Decoration::XfbStride, TransformFeedback), CASE1(DECORATION, Decoration::FuncParamAttr, Kernel), - CASE1(DECORATION, Decoration::FPFastMathMode, Kernel), + CASE2(DECORATION, Decoration::FPFastMathMode, Kernel, + FloatControls2), CASE1(DECORATION, Decoration::LinkageAttributes, Linkage), CASE1(DECORATION, Decoration::NoContraction, Shader), CASE1(DECORATION, Decoration::InputAttachmentIndex, diff --git a/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt index ceada132b3..92d266bba3 100644 --- a/test/opt/CMakeLists.txt +++ b/test/opt/CMakeLists.txt @@ -78,6 +78,7 @@ add_spvtools_unittest(TARGET opt local_single_block_elim.cpp local_single_store_elim_test.cpp local_ssa_elim_test.cpp + modify_maximal_reconvergence_test.cpp module_test.cpp module_utils.h optimizer_test.cpp diff --git a/test/opt/modify_maximal_reconvergence_test.cpp b/test/opt/modify_maximal_reconvergence_test.cpp new file mode 100644 index 0000000000..bef9237cf3 --- /dev/null +++ b/test/opt/modify_maximal_reconvergence_test.cpp @@ -0,0 +1,312 @@ +// Copyright (c) 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "assembly_builder.h" +#include "pass_fixture.h" +#include "pass_utils.h" + +namespace { + +using namespace spvtools; + +using ModifyMaximalReconvergenceTest = opt::PassTest<::testing::Test>; + +TEST_F(ModifyMaximalReconvergenceTest, AddNoEntryPoint) { + const std::string text = R"( +; CHECK-NOT: OpExtension +OpCapability Kernel +OpCapability Linkage +OpMemoryModel Logical OpenCL +)"; + + SinglePassRunAndMatch(text, true, true); +} + +TEST_F(ModifyMaximalReconvergenceTest, AddSingleEntryPoint) { + const std::string text = R"( +; CHECK: OpExtension "SPV_KHR_maximal_reconvergence" +; CHECK: OpExecutionMode %main MaximallyReconvergesKHR + +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpName %main "main" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true, true); +} + +TEST_F(ModifyMaximalReconvergenceTest, AddExtensionExists) { + const std::string text = R"( +; CHECK: OpExtension "SPV_KHR_maximal_reconvergence" +; CHECK-NOT: OpExtension "SPV_KHR_maximal_reconvergence" +; CHECK: OpExecutionMode %main MaximallyReconvergesKHR + +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpName %main "main" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true, true); +} + +TEST_F(ModifyMaximalReconvergenceTest, AddExecutionModeExists) { + const std::string text = R"( +; CHECK: OpExtension "SPV_KHR_maximal_reconvergence" +; CHECK-NOT: OpExtension "SPV_KHR_maximal_reconvergence" +; CHECK: OpExecutionMode %main LocalSize 1 1 1 +; CHECK-NEXT: OpExecutionMode %main MaximallyReconvergesKHR +; CHECK-NOT: OpExecutionMode %main MaximallyReconvergesKHR + +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main MaximallyReconvergesKHR +OpName %main "main" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true, true); +} + +TEST_F(ModifyMaximalReconvergenceTest, AddTwoEntryPoints) { + const std::string text = R"( +; CHECK: OpExtension "SPV_KHR_maximal_reconvergence" +; CHECK: OpExecutionMode %comp MaximallyReconvergesKHR +; CHECK: OpExecutionMode %frag MaximallyReconvergesKHR + +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %comp "main" +OpEntryPoint Fragment %frag "main" +OpExecutionMode %comp LocalSize 1 1 1 +OpExecutionMode %frag OriginUpperLeft +OpName %comp "comp" +OpName %frag "frag" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%comp = OpFunction %void None %void_fn +%entry1 = OpLabel +OpReturn +OpFunctionEnd +%frag = OpFunction %void None %void_fn +%entry2 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true, true); +} + +TEST_F(ModifyMaximalReconvergenceTest, AddTwoEntryPointsOneFunc) { + const std::string text = R"( +; CHECK: OpExtension "SPV_KHR_maximal_reconvergence" +; CHECK: OpExecutionMode %comp MaximallyReconvergesKHR +; CHECK-NOT: OpExecutionMode %comp MaximallyReconvergesKHR + +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %comp "main1" +OpEntryPoint GLCompute %comp "main2" +OpExecutionMode %comp LocalSize 1 1 1 +OpName %comp "comp" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%comp = OpFunction %void None %void_fn +%entry1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true, true); +} + +TEST_F(ModifyMaximalReconvergenceTest, AddTwoEntryPointsOneExecutionMode) { + const std::string text = R"( +; CHECK: OpExtension "SPV_KHR_maximal_reconvergence" +; CHECK: OpExecutionMode %comp MaximallyReconvergesKHR +; CHECK-NOT: OpExecutionMode %comp MaximallyReconvergesKHR +; CHECK: OpExecutionMode %frag MaximallyReconvergesKHR +; CHECK-NOT: OpExecutionMode %comp MaximallyReconvergesKHR + +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %comp "main" +OpEntryPoint Fragment %frag "main" +OpExecutionMode %comp LocalSize 1 1 1 +OpExecutionMode %frag OriginUpperLeft +OpExecutionMode %comp MaximallyReconvergesKHR +OpName %comp "comp" +OpName %frag "frag" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%comp = OpFunction %void None %void_fn +%entry1 = OpLabel +OpReturn +OpFunctionEnd +%frag = OpFunction %void None %void_fn +%entry2 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true, true); +} + +TEST_F(ModifyMaximalReconvergenceTest, RemoveNoEntryPoint) { + const std::string text = R"(OpCapability Kernel +OpCapability Linkage +OpMemoryModel Logical OpenCL +)"; + + SinglePassRunAndCheck(text, text, false, + true, false); +} + +TEST_F(ModifyMaximalReconvergenceTest, RemoveOnlyExtension) { + const std::string text = R"( +; CHECK-NOT: OpExtension "SPV_KHR_maximal_reconvergence" +; CHECK: OpExecutionMode %main LocalSize 1 1 1 + +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpName %main "main" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true, false); +} + +TEST_F(ModifyMaximalReconvergenceTest, RemoveSingleEntryPoint) { + const std::string text = R"( +; CHECK-NOT: OpExtension "SPV_KHR_maximal_reconvergence" +; CHECK: OpExecutionMode %main LocalSize 1 1 1 +; CHECK-NOT: OpExecutionMode %main MaximallyReconvergesKHR + +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main MaximallyReconvergesKHR +OpName %main "main" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true, false); +} + +TEST_F(ModifyMaximalReconvergenceTest, RemoveTwoEntryPointsOneExecutionMode) { + const std::string text = R"( +; CHECK-NOT: OpExtension "SPV_KHR_maximal_reconvergence" +; CHECK: OpExecutionMode %comp LocalSize 1 1 1 +; CHECK-NEXT: OpExecutionMode %frag OriginUpperLeft +; CHECK-NOT: OpExecutionMode %comp MaximallyReconvergesKHR + +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %comp "main" +OpEntryPoint Fragment %frag "main" +OpExecutionMode %comp LocalSize 1 1 1 +OpExecutionMode %comp MaximallyReconvergesKHR +OpExecutionMode %frag OriginUpperLeft +OpName %comp "comp" +OpName %frag "frag" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%comp = OpFunction %void None %void_fn +%entry1 = OpLabel +OpReturn +OpFunctionEnd +%frag = OpFunction %void None %void_fn +%entry2 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true, false); +} + +TEST_F(ModifyMaximalReconvergenceTest, RemoveTwoEntryPoints) { + const std::string text = R"( +; CHECK-NOT: OpExtension "SPV_KHR_maximal_reconvergence" +; CHECK: OpExecutionMode %comp LocalSize 1 1 1 +; CHECK-NEXT: OpExecutionMode %frag OriginUpperLeft +; CHECK-NOT: OpExecutionMode {{%\w}} MaximallyReconvergesKHR + +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %comp "main" +OpEntryPoint Fragment %frag "main" +OpExecutionMode %comp LocalSize 1 1 1 +OpExecutionMode %comp MaximallyReconvergesKHR +OpExecutionMode %frag OriginUpperLeft +OpExecutionMode %frag MaximallyReconvergesKHR +OpName %comp "comp" +OpName %frag "frag" +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%comp = OpFunction %void None %void_fn +%entry1 = OpLabel +OpReturn +OpFunctionEnd +%frag = OpFunction %void None %void_fn +%entry2 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true, false); +} + +} // namespace diff --git a/test/text_to_binary.extension_test.cpp b/test/text_to_binary.extension_test.cpp index 55f8466601..17adc557d9 100644 --- a/test/text_to_binary.extension_test.cpp +++ b/test/text_to_binary.extension_test.cpp @@ -1247,5 +1247,22 @@ INSTANTIATE_TEST_SUITE_P( MakeInstruction(spv::Op::OpStencilAttachmentReadEXT, {1, 2, 3})}, }))); +// SPV_KHR_maximal_reconvergence + +INSTANTIATE_TEST_SUITE_P( + SPV_KHR_maximal_reconvergence, ExtensionRoundTripTest, + Combine( + Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_0, + SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_3), + ValuesIn(std::vector{ + {"OpExtension \"SPV_KHR_maximal_reconvergence\"\n", + MakeInstruction(spv::Op::OpExtension, + MakeVector("SPV_KHR_maximal_reconvergence"))}, + {"OpExecutionMode %1 MaximallyReconvergesKHR\n", + MakeInstruction( + spv::Op::OpExecutionMode, + {1, (uint32_t)spv::ExecutionMode::MaximallyReconvergesKHR})}, + }))); + } // namespace } // namespace spvtools diff --git a/test/val/val_cfg_test.cpp b/test/val/val_cfg_test.cpp index 3953057e1c..233aee645d 100644 --- a/test/val/val_cfg_test.cpp +++ b/test/val/val_cfg_test.cpp @@ -4803,6 +4803,321 @@ TEST_F(ValidateCFG, BadSwitch) { "via a structured exit")); } +TEST_F(ValidateCFG, + MaximalReconvergenceBranchConditionalSameTargetNotInCallTree) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main MaximallyReconvergesKHR +%void = OpTypeVoid +%bool = OpTypeBool +%cond = OpUndef %bool +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%func_entry = OpLabel +OpBranchConditional %cond %func_exit %func_exit +%func_exit = OpLabel +OpReturn +OpFunctionEnd +%main = OpFunction %void None %void_fn +%main_entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateCFG, MaximalReconvergenceBranchConditionalSameTargetInCallTree) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main MaximallyReconvergesKHR +%void = OpTypeVoid +%bool = OpTypeBool +%cond = OpUndef %bool +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%func_entry = OpLabel +OpBranchConditional %cond %func_exit %func_exit +%func_exit = OpLabel +OpReturn +OpFunctionEnd +%main = OpFunction %void None %void_fn +%main_entry = OpLabel +%call = OpFunctionCall %void %func +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("In entry points using the MaximallyReconvergesKHR " + "execution mode, True " + "Label and False Label must be different labels")); +} + +TEST_F(ValidateCFG, MaximalReconvergenceEarlyReconvergenceNotInCallTree) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main MaximallyReconvergesKHR +%void = OpTypeVoid +%bool = OpTypeBool +%cond = OpUndef %bool +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%func_entry = OpLabel +OpSelectionMerge %func_exit None +OpBranchConditional %cond %then %else +%then = OpLabel +OpBranch %merge +%else = OpLabel +OpBranch %merge +%merge = OpLabel +OpBranch %func_exit +%func_exit = OpLabel +OpReturn +OpFunctionEnd +%main = OpFunction %void None %void_fn +%main_entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, MaximalReconvergenceEarlyReconvergenceInCallTree) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main MaximallyReconvergesKHR +%void = OpTypeVoid +%bool = OpTypeBool +%cond = OpUndef %bool +%void_fn = OpTypeFunction %void +%func = OpFunction %void None %void_fn +%func_entry = OpLabel +OpSelectionMerge %func_exit None +OpBranchConditional %cond %then %else +%then = OpLabel +OpBranch %merge +%else = OpLabel +OpBranch %merge +%merge = OpLabel +OpBranch %func_exit +%func_exit = OpLabel +OpReturn +OpFunctionEnd +%main = OpFunction %void None %void_fn +%main_entry = OpLabel +%call = OpFunctionCall %void %func +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "In entry points using the MaximallyReconvergesKHR execution mode, " + "this basic block must not have multiple unique predecessors")); +} + +TEST_F(ValidateCFG, MaximalReconvergenceLoopMultiplePredsOk) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main MaximallyReconvergesKHR +%void = OpTypeVoid +%bool = OpTypeBool +%cond = OpUndef %bool +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%main_entry = OpLabel +OpBranch %loop +%loop = OpLabel +OpLoopMerge %merge %loop None +OpBranchConditional %cond %loop %merge +%merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, MaximalReconvergenceLoopMultiplePredsOk2) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main MaximallyReconvergesKHR +%void = OpTypeVoid +%bool = OpTypeBool +%cond = OpUndef %bool +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%main_entry = OpLabel +OpBranch %loop +%loop = OpLabel +OpLoopMerge %merge %cont None +OpBranch %body +%body = OpLabel +OpBranch %cont +%cont = OpLabel +OpBranchConditional %cond %loop %merge +%merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, MaximalReconvergenceSelectionMergeMultiplePredsOk) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main MaximallyReconvergesKHR +%void = OpTypeVoid +%bool = OpTypeBool +%cond = OpUndef %bool +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%main_entry = OpLabel +OpSelectionMerge %merge None +OpBranchConditional %cond %then %else +%then = OpLabel +OpBranch %merge +%else = OpLabel +OpBranch %merge +%merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, MaximalReconvergenceSelectionMergeMultiplePredsOk2) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main MaximallyReconvergesKHR +OpName %merge "merge" +%void = OpTypeVoid +%bool = OpTypeBool +%cond = OpUndef %bool +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%main_entry = OpLabel +OpSelectionMerge %merge None +OpBranchConditional %cond %then %else +%then = OpLabel +OpBranch %merge +%else = OpLabel +OpBranch %merge +%merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, MaximalReconvergenceLoopMergeMultiplePredsOk) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main MaximallyReconvergesKHR +%void = OpTypeVoid +%bool = OpTypeBool +%cond = OpUndef %bool +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%main_entry = OpLabel +OpBranch %loop +%loop = OpLabel +OpLoopMerge %merge %continue None +OpBranchConditional %cond %merge %continue +%continue = OpLabel +OpBranchConditional %cond %loop %merge +%merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateCFG, MaximalReconvergenceCaseFallthroughMultiplePredsOk) { + const std::string text = R"( +OpCapability Shader +OpExtension "SPV_KHR_maximal_reconvergence" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main MaximallyReconvergesKHR +%void = OpTypeVoid +%bool = OpTypeBool +%cond = OpUndef %bool +%int = OpTypeInt 32 0 +%val = OpUndef %int +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%main_entry = OpLabel +OpSelectionMerge %merge None +OpSwitch %val %merge 0 %case1 1 %case2 +%case1 = OpLabel +OpBranch %case2 +%case2 = OpLabel +OpBranch %merge +%merge = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/test/val/val_modes_test.cpp b/test/val/val_modes_test.cpp index 8dc0fbc5a1..97d8c397e0 100644 --- a/test/val/val_modes_test.cpp +++ b/test/val/val_modes_test.cpp @@ -1306,6 +1306,28 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3)); } +TEST_F(ValidateMode, MaximalReconvergenceRequiresExtension) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main MaximallyReconvergesKHR +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("(6023) requires one of these extensions: " + "SPV_KHR_maximal_reconvergence ")); +} + } // namespace } // namespace val } // namespace spvtools From ef2f4323640beddf3bab855c5535b0c3e8c7d878 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Thu, 25 Jan 2024 10:22:09 -0500 Subject: [PATCH 354/523] Add support for SPV_KHR_float_controls2 (#5543) * Test asm/dis for SPV_KHR_float_controls2 * SPV_KHR_float_controls2 validation --------- Co-authored-by: David Neto --- source/val/validate.cpp | 4 + source/val/validate.h | 12 + source/val/validate_annotation.cpp | 28 ++ source/val/validate_instruction.cpp | 3 +- source/val/validate_mode_setting.cpp | 173 +++++++- test/operand_capabilities_test.cpp | 17 +- test/text_to_binary.extension_test.cpp | 36 ++ test/val/val_annotation_test.cpp | 165 ++++++++ test/val/val_modes_test.cpp | 546 +++++++++++++++++++++++++ 9 files changed, 961 insertions(+), 23 deletions(-) diff --git a/source/val/validate.cpp b/source/val/validate.cpp index a5f320b9f4..ccf26fbf1d 100644 --- a/source/val/validate.cpp +++ b/source/val/validate.cpp @@ -141,6 +141,10 @@ spv_result_t ValidateEntryPoints(ValidationState_t& _) { } } + if (auto error = ValidateFloatControls2(_)) { + return error; + } + return SPV_SUCCESS; } diff --git a/source/val/validate.h b/source/val/validate.h index 6b7d7cdacf..52267c8ab6 100644 --- a/source/val/validate.h +++ b/source/val/validate.h @@ -82,6 +82,18 @@ spv_result_t ValidateAdjacency(ValidationState_t& _); /// @return SPV_SUCCESS if no errors are found. spv_result_t ValidateInterfaces(ValidationState_t& _); +/// @brief Validates entry point call tree requirements of +/// SPV_KHR_float_controls2 +/// +/// Checks that no entry point using FPFastMathDefault uses: +/// * FPFastMathMode Fast +/// * NoContraction +/// +/// @param[in] _ the validation state of the module +/// +/// @return SPV_SUCCESS if no errors are found. +spv_result_t ValidateFloatControls2(ValidationState_t& _); + /// @brief Validates memory instructions /// /// @param[in] _ the validation state of the module diff --git a/source/val/validate_annotation.cpp b/source/val/validate_annotation.cpp index 73d0285a11..106004d066 100644 --- a/source/val/validate_annotation.cpp +++ b/source/val/validate_annotation.cpp @@ -267,6 +267,34 @@ spv_result_t ValidateDecorate(ValidationState_t& _, const Instruction* inst) { } } + if (decoration == spv::Decoration::FPFastMathMode) { + if (_.HasDecoration(target_id, spv::Decoration::NoContraction)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "FPFastMathMode and NoContraction cannot decorate the same " + "target"; + } + auto mask = inst->GetOperandAs(2); + if ((mask & spv::FPFastMathModeMask::AllowTransform) != + spv::FPFastMathModeMask::MaskNone && + ((mask & (spv::FPFastMathModeMask::AllowContract | + spv::FPFastMathModeMask::AllowReassoc)) != + (spv::FPFastMathModeMask::AllowContract | + spv::FPFastMathModeMask::AllowReassoc))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "AllowReassoc and AllowContract must be specified when " + "AllowTransform is specified"; + } + } + + // This is checked from both sides since we register decorations as we go. + if (decoration == spv::Decoration::NoContraction) { + if (_.HasDecoration(target_id, spv::Decoration::FPFastMathMode)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "FPFastMathMode and NoContraction cannot decorate the same " + "target"; + } + } + if (DecorationTakesIdParameters(decoration)) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Decorations taking ID parameters may not be used with " diff --git a/source/val/validate_instruction.cpp b/source/val/validate_instruction.cpp index 8710ffa44b..5bc4d2cef4 100644 --- a/source/val/validate_instruction.cpp +++ b/source/val/validate_instruction.cpp @@ -470,7 +470,8 @@ spv_result_t InstructionPass(ValidationState_t& _, const Instruction* inst) { } _.set_addressing_model(inst->GetOperandAs(0)); _.set_memory_model(inst->GetOperandAs(1)); - } else if (opcode == spv::Op::OpExecutionMode) { + } else if (opcode == spv::Op::OpExecutionMode || + opcode == spv::Op::OpExecutionModeId) { const uint32_t entry_point = inst->word(1); _.RegisterExecutionModeForEntryPoint(entry_point, spv::ExecutionMode(inst->word(2))); diff --git a/source/val/validate_mode_setting.cpp b/source/val/validate_mode_setting.cpp index d757d4f826..10afa8298b 100644 --- a/source/val/validate_mode_setting.cpp +++ b/source/val/validate_mode_setting.cpp @@ -340,29 +340,92 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _, const auto mode = inst->GetOperandAs(1); if (inst->opcode() == spv::Op::OpExecutionModeId) { + bool valid_mode = false; + switch (mode) { + case spv::ExecutionMode::SubgroupsPerWorkgroupId: + case spv::ExecutionMode::LocalSizeHintId: + case spv::ExecutionMode::LocalSizeId: + case spv::ExecutionMode::FPFastMathDefault: + valid_mode = true; + break; + default: + valid_mode = false; + break; + } + if (!valid_mode) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpExecutionModeId is only valid when the Mode operand is an " + "execution mode that takes Extra Operands that are id " + "operands."; + } + size_t operand_count = inst->operands().size(); for (size_t i = 2; i < operand_count; ++i) { - const auto operand_id = inst->GetOperandAs(2); + const auto operand_id = inst->GetOperandAs(i); const auto* operand_inst = _.FindDef(operand_id); - if (mode == spv::ExecutionMode::SubgroupsPerWorkgroupId || - mode == spv::ExecutionMode::LocalSizeHintId || - mode == spv::ExecutionMode::LocalSizeId) { - if (!spvOpcodeIsConstant(operand_inst->opcode())) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "For OpExecutionModeId all Extra Operand ids must be " - "constant " - "instructions."; - } - } else { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpExecutionModeId is only valid when the Mode operand is an " - "execution mode that takes Extra Operands that are id " - "operands."; + switch (mode) { + case spv::ExecutionMode::SubgroupsPerWorkgroupId: + case spv::ExecutionMode::LocalSizeHintId: + case spv::ExecutionMode::LocalSizeId: + if (!spvOpcodeIsConstant(operand_inst->opcode())) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "For OpExecutionModeId all Extra Operand ids must be " + "constant instructions."; + } + break; + case spv::ExecutionMode::FPFastMathDefault: + if (i == 2) { + if (!_.IsFloatScalarType(operand_id)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "The Target Type operand must be a floating-point " + "scalar type"; + } + } else { + bool is_int32 = false; + bool is_const = false; + uint32_t value = 0; + std::tie(is_int32, is_const, value) = + _.EvalInt32IfConst(operand_id); + if (is_int32 && is_const) { + // Valid values include up to 0x00040000 (AllowTransform). + uint32_t invalid_mask = 0xfff80000; + if ((invalid_mask & value) != 0) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "The Fast Math Default operand is an invalid bitmask " + "value"; + } + if (value & + static_cast(spv::FPFastMathModeMask::Fast)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "The Fast Math Default operand must not include Fast"; + } + const auto reassoc_contract = + spv::FPFastMathModeMask::AllowContract | + spv::FPFastMathModeMask::AllowReassoc; + if ((value & static_cast( + spv::FPFastMathModeMask::AllowTransform)) != 0 && + ((value & static_cast(reassoc_contract)) != + static_cast(reassoc_contract))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "The Fast Math Default operand must include " + "AllowContract and AllowReassoc when AllowTransform " + "is specified"; + } + } else { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "The Fast Math Default operand must be a " + "non-specialization constant"; + } + } + break; + default: + break; } } } else if (mode == spv::ExecutionMode::SubgroupsPerWorkgroupId || mode == spv::ExecutionMode::LocalSizeHintId || - mode == spv::ExecutionMode::LocalSizeId) { + mode == spv::ExecutionMode::LocalSizeId || + mode == spv::ExecutionMode::FPFastMathDefault) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "OpExecutionMode is only valid when the Mode operand is an " "execution mode that takes no Extra Operands, or takes Extra " @@ -579,6 +642,20 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _, break; } + if (mode == spv::ExecutionMode::FPFastMathDefault) { + const auto* modes = _.GetExecutionModes(entry_point_id); + if (modes && modes->count(spv::ExecutionMode::ContractionOff)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "FPFastMathDefault and ContractionOff execution modes cannot " + "be applied to the same entry point"; + } + if (modes && modes->count(spv::ExecutionMode::SignedZeroInfNanPreserve)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "FPFastMathDefault and SignedZeroInfNanPreserve execution " + "modes cannot be applied to the same entry point"; + } + } + if (spvIsVulkanEnv(_.context()->target_env)) { if (mode == spv::ExecutionMode::OriginLowerLeft) { return _.diag(SPV_ERROR_INVALID_DATA, inst) @@ -636,6 +713,70 @@ spv_result_t ValidateMemoryModel(ValidationState_t& _, } // namespace +spv_result_t ValidateFloatControls2(ValidationState_t& _) { + std::unordered_set fp_fast_math_default_entry_points; + for (auto entry_point : _.entry_points()) { + const auto* exec_modes = _.GetExecutionModes(entry_point); + if (exec_modes && + exec_modes->count(spv::ExecutionMode::FPFastMathDefault)) { + fp_fast_math_default_entry_points.insert(entry_point); + } + } + + std::vector> worklist; + for (const auto& inst : _.ordered_instructions()) { + if (inst.opcode() != spv::Op::OpDecorate) { + continue; + } + + const auto decoration = inst.GetOperandAs(1); + const auto target_id = inst.GetOperandAs(0); + const auto target = _.FindDef(target_id); + if (decoration == spv::Decoration::NoContraction) { + worklist.push_back(std::make_pair(target, decoration)); + } else if (decoration == spv::Decoration::FPFastMathMode) { + auto mask = inst.GetOperandAs(2); + if ((mask & spv::FPFastMathModeMask::Fast) != + spv::FPFastMathModeMask::MaskNone) { + worklist.push_back(std::make_pair(target, decoration)); + } + } + } + + std::unordered_set visited; + while (!worklist.empty()) { + const auto inst = worklist.back().first; + const auto decoration = worklist.back().second; + worklist.pop_back(); + + if (!visited.insert(inst).second) { + continue; + } + + const auto function = inst->function(); + if (function) { + const auto& entry_points = _.FunctionEntryPoints(function->id()); + for (auto entry_point : entry_points) { + if (fp_fast_math_default_entry_points.count(entry_point)) { + const std::string dec = decoration == spv::Decoration::NoContraction + ? "NoContraction" + : "FPFastMathMode Fast"; + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << dec + << " cannot be used by an entry point with the " + "FPFastMathDefault execution mode"; + } + } + } else { + for (const auto& pair : inst->uses()) { + worklist.push_back(std::make_pair(pair.first, decoration)); + } + } + } + + return SPV_SUCCESS; +} + spv_result_t ModeSettingPass(ValidationState_t& _, const Instruction* inst) { switch (inst->opcode()) { case spv::Op::OpEntryPoint: diff --git a/test/operand_capabilities_test.cpp b/test/operand_capabilities_test.cpp index 6c4042dc2b..6f2ac9f77f 100644 --- a/test/operand_capabilities_test.cpp +++ b/test/operand_capabilities_test.cpp @@ -21,6 +21,9 @@ #include "source/assembly_grammar.h" #include "source/enum_set.h" #include "source/operand.h" +#include "source/spirv_target_env.h" +#include "source/table.h" +#include "spirv-tools/libspirv.h" #include "test/unit_spirv.h" namespace spvtools { @@ -58,15 +61,17 @@ struct EnumCapabilityCase { 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 << "}"; + +// Emits an EnumCapabilityCase to the given output stream. This is used +// to emit failure cases when they occur, which helps debug tests. +inline std::ostream& operator<<(std::ostream& out, EnumCapabilityCase e) { + out << "{" << spvOperandTypeStr(e.type) << " " << e.value << " " + << e.expected_capabilities << " }"; return out; } +using EnvEnumCapabilityCase = std::tuple; + // Test fixture for testing EnumCapabilityCases. using EnumCapabilityTest = TestWithParam>; diff --git a/test/text_to_binary.extension_test.cpp b/test/text_to_binary.extension_test.cpp index 17adc557d9..8e78312e6e 100644 --- a/test/text_to_binary.extension_test.cpp +++ b/test/text_to_binary.extension_test.cpp @@ -1264,5 +1264,41 @@ INSTANTIATE_TEST_SUITE_P( {1, (uint32_t)spv::ExecutionMode::MaximallyReconvergesKHR})}, }))); +// SPV_KHR_float_controls2 + +INSTANTIATE_TEST_SUITE_P( + SPV_KHR_float_controls2, ExtensionRoundTripTest, + Combine( + Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_5, SPV_ENV_VULKAN_1_0, + SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2, SPV_ENV_VULKAN_1_3), + ValuesIn(std::vector{ + {"OpExtension \"SPV_KHR_float_controls2\"\n", + MakeInstruction(spv::Op::OpExtension, + MakeVector("SPV_KHR_float_controls2"))}, + {"OpCapability FloatControls2\n", + MakeInstruction(spv::Op::OpCapability, + {(uint32_t)spv::Capability::FloatControls2})}, + {"OpExecutionMode %1 FPFastMathDefault %2 %3\n", + // The operands are: target type, flags constant + MakeInstruction( + spv::Op::OpExecutionMode, + {1, (uint32_t)spv::ExecutionMode::FPFastMathDefault, 2, 3})}, + {"OpDecorate %1 FPFastMathMode AllowContract\n", + MakeInstruction( + spv::Op::OpDecorate, + {1, (uint32_t)spv::Decoration::FPFastMathMode, + (uint32_t)spv::FPFastMathModeMask::AllowContract})}, + {"OpDecorate %1 FPFastMathMode AllowReassoc\n", + MakeInstruction( + spv::Op::OpDecorate, + {1, (uint32_t)spv::Decoration::FPFastMathMode, + (uint32_t)spv::FPFastMathModeMask::AllowReassoc})}, + {"OpDecorate %1 FPFastMathMode AllowTransform\n", + MakeInstruction( + spv::Op::OpDecorate, + {1, (uint32_t)spv::Decoration::FPFastMathMode, + (uint32_t)spv::FPFastMathModeMask::AllowTransform})}, + }))); + } // namespace } // namespace spvtools diff --git a/test/val/val_annotation_test.cpp b/test/val/val_annotation_test.cpp index 9f85a30bbb..97dde2df4a 100644 --- a/test/val/val_annotation_test.cpp +++ b/test/val/val_annotation_test.cpp @@ -65,6 +65,171 @@ OpDecorate %var BuiltIn WorkgroupSize EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(DecorationTest, FPFastMathModeInvalidMask) { + const std::string text = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %add FPFastMathMode !524288 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%undef = OpUndef %float +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%add = OpFAdd %float %undef %undef +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Invalid floating-point fast math mode operand")); +} + +TEST_F(DecorationTest, FPFastMathModeAllowTransformMissingAllowContract) { + const std::string text = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %add FPFastMathMode AllowTransform|AllowReassoc +%void = OpTypeVoid +%float = OpTypeFloat 32 +%undef = OpUndef %float +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%add = OpFAdd %float %undef %undef +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("AllowReassoc and AllowContract must be specified when " + "AllowTransform is specified")); +} + +TEST_F(DecorationTest, FPFastMathModeAllowTransformMissingAllowReassoc) { + const std::string text = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %add FPFastMathMode AllowTransform|AllowContract +%void = OpTypeVoid +%float = OpTypeFloat 32 +%undef = OpUndef %float +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%add = OpFAdd %float %undef %undef +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("AllowReassoc and AllowContract must be specified when " + "AllowTransform is specified")); +} + +TEST_F(DecorationTest, FPFastMathModeAllowTransformMissingContractAndReassoc) { + const std::string text = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %add FPFastMathMode AllowTransform +%void = OpTypeVoid +%float = OpTypeFloat 32 +%undef = OpUndef %float +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%add = OpFAdd %float %undef %undef +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("AllowReassoc and AllowContract must be specified when " + "AllowTransform is specified")); +} + +TEST_F(DecorationTest, FPFastMathModeAndNoContraction) { + const std::string text = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %add FPFastMathMode None +OpDecorate %add NoContraction +%void = OpTypeVoid +%float = OpTypeFloat 32 +%undef = OpUndef %float +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%add = OpFAdd %float %undef %undef +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "FPFastMathMode and NoContraction cannot decorate the same target")); +} + +TEST_F(DecorationTest, FPFastMathModeAndNoContraction2) { + const std::string text = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %add NoContraction +OpDecorate %add FPFastMathMode None +%void = OpTypeVoid +%float = OpTypeFloat 32 +%undef = OpUndef %float +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%add = OpFAdd %float %undef %undef +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "FPFastMathMode and NoContraction cannot decorate the same target")); +} + using MemberOnlyDecorations = spvtest::ValidateBase; TEST_P(MemberOnlyDecorations, MemberDecoration) { diff --git a/test/val/val_modes_test.cpp b/test/val/val_modes_test.cpp index 97d8c397e0..f17497747c 100644 --- a/test/val/val_modes_test.cpp +++ b/test/val/val_modes_test.cpp @@ -1328,6 +1328,552 @@ OpFunctionEnd "SPV_KHR_maximal_reconvergence ")); } +TEST_F(ValidateMode, FPFastMathDefaultNotExecutionModeId) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main FPFastMathDefault %int_0 %int_0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpExecutionMode is only valid when the Mode operand " + "is an execution mode that takes no Extra Operands, or " + "takes Extra Operands that are not id operands")); +} + +TEST_F(ValidateMode, FPFastMathDefaultNotAType) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionModeId %main FPFastMathDefault %int_0 %int_0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "The Target Type operand must be a floating-point scalar type")); +} + +TEST_F(ValidateMode, FPFastMathDefaultNotAFloatType) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionModeId %main FPFastMathDefault %int %int_0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "The Target Type operand must be a floating-point scalar type")); +} + +TEST_F(ValidateMode, FPFastMathDefaultNotAFloatScalarType) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionModeId %main FPFastMathDefault %float2 %int_0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%float = OpTypeFloat 32 +%float2 = OpTypeVector %float 2 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "The Target Type operand must be a floating-point scalar type")); +} + +TEST_F(ValidateMode, FPFastMathDefaultSpecConstant) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionModeId %main FPFastMathDefault %float %int_0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpSpecConstant %int 0 +%float = OpTypeFloat 32 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("The Fast Math Default operand must be a " + "non-specialization constant")); +} + +TEST_F(ValidateMode, FPFastMathDefaultInvalidMask) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionModeId %main FPFastMathDefault %float %constant +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%constant = OpConstant %int 524288 +%float = OpTypeFloat 32 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("The Fast Math Default operand is an invalid bitmask value")); +} + +TEST_F(ValidateMode, FPFastMathDefaultContainsFast) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionModeId %main FPFastMathDefault %float %constant +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%constant = OpConstant %int 16 +%float = OpTypeFloat 32 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("The Fast Math Default operand must not include Fast")); +} + +TEST_F(ValidateMode, FPFastMathDefaultAllowTransformMissingAllowReassoc) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionModeId %main FPFastMathDefault %float %constant +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%constant = OpConstant %int 327680 +%float = OpTypeFloat 32 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("The Fast Math Default operand must include AllowContract and " + "AllowReassoc when AllowTransform is specified")); +} + +TEST_F(ValidateMode, FPFastMathDefaultAllowTransformMissingAllowContract) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionModeId %main FPFastMathDefault %float %constant +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%constant = OpConstant %int 393216 +%float = OpTypeFloat 32 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("The Fast Math Default operand must include AllowContract and " + "AllowReassoc when AllowTransform is specified")); +} + +TEST_F(ValidateMode, FPFastMathDefaultAllowTransformMissingContractAndReassoc) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionModeId %main FPFastMathDefault %float %constant +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%constant = OpConstant %int 262144 +%float = OpTypeFloat 32 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("The Fast Math Default operand must include AllowContract and " + "AllowReassoc when AllowTransform is specified")); +} + +TEST_F(ValidateMode, FPFastMathDefaultSignedZeroInfNanPreserve) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FloatControls2 +OpCapability SignedZeroInfNanPreserve +OpExtension "SPV_KHR_float_controls2" +OpExtension "SPV_KHR_float_controls" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionModeId %main FPFastMathDefault %float %constant +OpExecutionMode %main SignedZeroInfNanPreserve 32 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%constant = OpConstant %int 0 +%float = OpTypeFloat 32 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("FPFastMathDefault and SignedZeroInfNanPreserve execution " + "modes cannot be applied to the same entry point")); +} + +TEST_F(ValidateMode, FPFastMathDefaultConractionOff) { + const std::string spirv = R"( +OpCapability Kernel +OpCapability Addresses +OpCapability FloatControls2 +OpCapability SignedZeroInfNanPreserve +OpExtension "SPV_KHR_float_controls2" +OpExtension "SPV_KHR_float_controls" +OpMemoryModel Physical64 OpenCL +OpEntryPoint Kernel %main "main" +OpExecutionModeId %main FPFastMathDefault %float %constant +OpExecutionMode %main ContractionOff +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%constant = OpConstant %int 0 +%float = OpTypeFloat 32 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("FPFastMathDefault and ContractionOff execution modes " + "cannot be applied to the same entry point")); +} + +TEST_F(ValidateMode, FPFastMathDefaultNoContractionNotInCallTree) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionModeId %main FPFastMathDefault %float %constant +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %add NoContraction +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%constant = OpConstant %int 0 +%float = OpTypeFloat 32 +%zero = OpConstant %float 0 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +%func = OpFunction %void None %void_fn +%func_entry = OpLabel +%add = OpFAdd %float %zero %zero +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateMode, FPFastMathDefaultNoContractionInCallTree) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionModeId %main FPFastMathDefault %float %constant +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %add NoContraction +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%constant = OpConstant %int 0 +%float = OpTypeFloat 32 +%zero = OpConstant %float 0 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%call = OpFunctionCall %void %func +OpReturn +OpFunctionEnd +%func = OpFunction %void None %void_fn +%func_entry = OpLabel +%add = OpFAdd %float %zero %zero +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NoContraction cannot be used by an entry point with " + "the FPFastMathDefault execution mode")); +} + +TEST_F(ValidateMode, FPFastMathDefaultNoContractionInCallTree2) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Kernel +OpCapability Addresses +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Physical64 OpenCL +OpEntryPoint Kernel %main "main" +OpExecutionModeId %main FPFastMathDefault %float %constant +OpDecorate %const NoContraction +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%constant = OpConstant %int 0 +%float = OpTypeFloat 32 +%zero = OpConstant %float 0 +%const = OpSpecConstantOp %float FAdd %zero %zero +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%call = OpFunctionCall %void %func +OpReturn +OpFunctionEnd +%func = OpFunction %void None %void_fn +%func_entry = OpLabel +%add = OpFAdd %float %const %zero +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NoContraction cannot be used by an entry point with " + "the FPFastMathDefault execution mode")); +} + +TEST_F(ValidateMode, FPFastMathDefaultFastMathFastNotInCallTree) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionModeId %main FPFastMathDefault %float %constant +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %add FPFastMathMode Fast +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%constant = OpConstant %int 0 +%float = OpTypeFloat 32 +%zero = OpConstant %float 0 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +%func = OpFunction %void None %void_fn +%func_entry = OpLabel +%add = OpFAdd %float %zero %zero +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateMode, FPFastMathDefaultFastMathFastInCallTree) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionModeId %main FPFastMathDefault %float %constant +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %add FPFastMathMode Fast +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%constant = OpConstant %int 0 +%float = OpTypeFloat 32 +%zero = OpConstant %float 0 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%call = OpFunctionCall %void %func +OpReturn +OpFunctionEnd +%func = OpFunction %void None %void_fn +%func_entry = OpLabel +%add = OpFAdd %float %zero %zero +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("FPFastMathMode Fast cannot be used by an entry point " + "with the FPFastMathDefault execution mode")); +} + +TEST_F(ValidateMode, FPFastMathDefaultFastMathFastInCallTree2) { + const std::string spirv = R"( +OpCapability Kernel +OpCapability Addresses +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Physical64 OpenCL +OpEntryPoint Kernel %main "main" +OpExecutionModeId %main FPFastMathDefault %float %constant +OpDecorate %const FPFastMathMode Fast +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%constant = OpConstant %int 0 +%float = OpTypeFloat 32 +%zero = OpConstant %float 0 +%const = OpSpecConstantOp %float FAdd %zero %zero +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%call = OpFunctionCall %void %func +OpReturn +OpFunctionEnd +%func = OpFunction %void None %void_fn +%func_entry = OpLabel +%add = OpFAdd %float %const %zero +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("FPFastMathMode Fast cannot be used by an entry point " + "with the FPFastMathDefault execution mode")); +} + } // namespace } // namespace val } // namespace spvtools From 0045b01ff9648eeef1781282f0454ae584f3ace7 Mon Sep 17 00:00:00 2001 From: Natalie Chouinard Date: Thu, 25 Jan 2024 14:05:04 -0500 Subject: [PATCH 355/523] opt: Add VulkanMemoryModelDeviceScope to trim (#5544) Add the VulkanMemoryModelDeviceScope capability to the capability trimming pass. According the the spec, "If the Vulkan memory model is declared and any instruction uses Device scope, the VulkanMemoryModelDeviceScope capability must be declared." Since this case, based on the type of an operand, is not covered by the JSON grammar, it is added explicitly. --- source/opt/ir_context.h | 6 ++ source/opt/trim_capabilities_pass.cpp | 11 ++++ source/opt/trim_capabilities_pass.h | 3 +- test/opt/trim_capabilities_pass_test.cpp | 76 ++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 1 deletion(-) diff --git a/source/opt/ir_context.h b/source/opt/ir_context.h index de3c410665..5685db809d 100644 --- a/source/opt/ir_context.h +++ b/source/opt/ir_context.h @@ -229,6 +229,8 @@ class IRContext { inline void AddExtInstImport(std::unique_ptr&& e); // Set the memory model for this module. inline void SetMemoryModel(std::unique_ptr&& m); + // Get the memory model for this module. + inline const Instruction* GetMemoryModel() const; // Appends an entry point instruction to this module. inline void AddEntryPoint(std::unique_ptr&& e); // Appends an execution mode instruction to this module. @@ -1156,6 +1158,10 @@ void IRContext::SetMemoryModel(std::unique_ptr&& m) { module()->SetMemoryModel(std::move(m)); } +const Instruction* IRContext::GetMemoryModel() const { + return module()->GetMemoryModel(); +} + void IRContext::AddEntryPoint(std::unique_ptr&& e) { module()->AddEntryPoint(std::move(e)); } diff --git a/source/opt/trim_capabilities_pass.cpp b/source/opt/trim_capabilities_pass.cpp index 19f8569e09..24f9e4670e 100644 --- a/source/opt/trim_capabilities_pass.cpp +++ b/source/opt/trim_capabilities_pass.cpp @@ -448,6 +448,17 @@ void TrimCapabilitiesPass::addInstructionRequirementsForOperand( return; } + // If the Vulkan memory model is declared and any instruction uses Device + // scope, the VulkanMemoryModelDeviceScope capability must be declared. This + // rule cannot be covered by the grammar, so must be checked explicitly. + if (operand.type == SPV_OPERAND_TYPE_SCOPE_ID) { + const Instruction* memory_model = context()->GetMemoryModel(); + if (memory_model && memory_model->GetSingleWordInOperand(1u) == + uint32_t(spv::MemoryModel::Vulkan)) { + capabilities->insert(spv::Capability::VulkanMemoryModelDeviceScope); + } + } + // case 1: Operand is a single value, can directly lookup. if (!spvOperandIsConcreteMask(operand.type)) { const spv_operand_desc_t* desc = {}; diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index 9f23732997..3a8460f3b2 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -97,7 +97,8 @@ class TrimCapabilitiesPass : public Pass { spv::Capability::StorageInputOutput16, spv::Capability::StoragePushConstant16, spv::Capability::StorageUniform16, - spv::Capability::StorageUniformBufferBlock16 + spv::Capability::StorageUniformBufferBlock16, + spv::Capability::VulkanMemoryModelDeviceScope // clang-format on }; diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index c90afb4c66..d74ccdf2f8 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -2584,6 +2584,82 @@ TEST_F(TrimCapabilitiesPassTest, UInt16_RemainsWhenUsed) { EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); } +TEST_F(TrimCapabilitiesPassTest, + VulkanMemoryModelDeviceScope_RemovedWhenUnused) { + const std::string kTest = R"( + OpCapability VulkanMemoryModelDeviceScope +; CHECK-NOT: OpCapability VulkanMemoryModelDeviceScope + 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, + VulkanMemoryModelDeviceScope_RemovedWhenUsedWithGLSL450) { + const std::string kTest = R"( + OpCapability VulkanMemoryModelDeviceScope +; CHECK-NOT: OpCapability VulkanMemoryModelDeviceScope + OpCapability Shader + OpCapability ShaderClockKHR + OpCapability Int64 + OpExtension "SPV_KHR_shader_clock" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %ulong = OpTypeInt 64 0 + %uint_1 = OpConstant %uint 1 + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + %22 = OpReadClockKHR %ulong %uint_1 ; Device Scope + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch(kTest, /* skip_nop= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + VulkanMemoryModelDeviceScope_RemainsWhenUsedWithVulkan) { + const std::string kTest = R"( + OpCapability VulkanMemoryModelDeviceScope +; CHECK: OpCapability VulkanMemoryModelDeviceScope + OpCapability Shader + OpCapability ShaderClockKHR + OpCapability Int64 + OpExtension "SPV_KHR_shader_clock" + OpMemoryModel Logical Vulkan + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %ulong = OpTypeInt 64 0 + %uint_1 = OpConstant %uint 1 + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + %22 = OpReadClockKHR %ulong %uint_1 ; Device Scope + 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 69197ba90b2bf1358e49e0f77ffbc33b4dc44c5d Mon Sep 17 00:00:00 2001 From: alan-baker Date: Thu, 25 Jan 2024 15:53:11 -0500 Subject: [PATCH 356/523] Add modify-maximal-reconvergence to spirv-opt help (#5546) --- tools/opt/opt.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 24724e59fa..f320baf923 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -335,6 +335,12 @@ Options (in lexicographical order):)", These conditions are guaranteed to be met after running dead-branch elimination.)"); printf(R"( + --modify-maximal-reconvergence=[add|remove] + Add or remove the MaximallyReconvergesKHR execution mode to all + entry points in the module. + Note: when adding the execution mode, no attempt is made to + determine if any ray tracing repack instructions are used.)"); + printf(R"( --loop-unswitch Hoists loop-invariant conditionals out of loops by duplicating the loop on each branch of the conditional and adjusting each From b951948eaa75b51466eaa22e8a89223966f300e4 Mon Sep 17 00:00:00 2001 From: ruiminzhao Date: Sat, 27 Jan 2024 04:49:56 +0800 Subject: [PATCH 357/523] SPV_KHR_quad_control (#5547) * SPV_KHR_quad_control 1. Add two new execute modes: RequireFullQuadsKHR and QuadDerivativesKHR 2. Add two opCodes: OpGroupNonUniformQuadAllKHR and OpGroupNonUniformQuadAnyKHR 3. Add one Capability: QuadControlKHR * update DEPS * Fixes * Build fixes * Formatting fixes * Test fixes * formatting --------- Co-authored-by: Alan Baker --- DEPS | 2 +- source/opcode.cpp | 2 + source/val/validate_mode_setting.cpp | 12 ++ source/val/validate_non_uniform.cpp | 11 +- source/val/validate_scopes.cpp | 8 +- test/val/val_modes_test.cpp | 178 +++++++++++++++++++++++++++ test/val/val_non_uniform_test.cpp | 24 +++- tools/sva/src/spirv.data.js | 3 + 8 files changed, 232 insertions(+), 8 deletions(-) diff --git a/DEPS b/DEPS index 7ba5521ae0..1856d3c7e7 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': '264e71e88e1c8a4b5ec326e70e9cf1d476f58a58', - 'spirv_headers_revision': 'ae6a8b39717523d96683bc0d20b541944e28072f', + 'spirv_headers_revision': '5aa1dd8a11182ea9a6a0eabd6a9edc639d5dbecd', } deps = { diff --git a/source/opcode.cpp b/source/opcode.cpp index ffbb2e8bae..38d1a1be6e 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -534,6 +534,8 @@ bool spvOpcodeIsNonUniformGroupOperation(spv::Op opcode) { case spv::Op::OpGroupNonUniformQuadBroadcast: case spv::Op::OpGroupNonUniformQuadSwap: case spv::Op::OpGroupNonUniformRotateKHR: + case spv::Op::OpGroupNonUniformQuadAllKHR: + case spv::Op::OpGroupNonUniformQuadAnyKHR: return true; default: return false; diff --git a/source/val/validate_mode_setting.cpp b/source/val/validate_mode_setting.cpp index 10afa8298b..82c6c3f0e8 100644 --- a/source/val/validate_mode_setting.cpp +++ b/source/val/validate_mode_setting.cpp @@ -557,6 +557,17 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _, "model."; } break; + case spv::ExecutionMode::QuadDerivativesKHR: + if (!std::all_of(models->begin(), models->end(), + [](const spv::ExecutionModel& model) { + return (model == spv::ExecutionModel::Fragment || + model == spv::ExecutionModel::GLCompute); + })) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Execution mode can only be used with the Fragment or " + "GLCompute execution model."; + } + break; case spv::ExecutionMode::PixelCenterInteger: case spv::ExecutionMode::OriginUpperLeft: case spv::ExecutionMode::OriginLowerLeft: @@ -581,6 +592,7 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _, case spv::ExecutionMode::StencilRefUnchangedBackAMD: case spv::ExecutionMode::StencilRefGreaterBackAMD: case spv::ExecutionMode::StencilRefLessBackAMD: + case spv::ExecutionMode::RequireFullQuadsKHR: if (!std::all_of(models->begin(), models->end(), [](const spv::ExecutionModel& model) { return model == spv::ExecutionModel::Fragment; diff --git a/source/val/validate_non_uniform.cpp b/source/val/validate_non_uniform.cpp index 2c36ce3324..74449e9dc0 100644 --- a/source/val/validate_non_uniform.cpp +++ b/source/val/validate_non_uniform.cpp @@ -422,9 +422,14 @@ spv_result_t NonUniformPass(ValidationState_t& _, const Instruction* inst) { const spv::Op opcode = inst->opcode(); if (spvOpcodeIsNonUniformGroupOperation(opcode)) { - const uint32_t execution_scope = inst->GetOperandAs(2); - if (auto error = ValidateExecutionScope(_, inst, execution_scope)) { - return error; + // OpGroupNonUniformQuadAllKHR and OpGroupNonUniformQuadAnyKHR don't have + // scope paramter + if ((opcode != spv::Op::OpGroupNonUniformQuadAllKHR) && + (opcode != spv::Op::OpGroupNonUniformQuadAnyKHR)) { + const uint32_t execution_scope = inst->GetOperandAs(2); + if (auto error = ValidateExecutionScope(_, inst, execution_scope)) { + return error; + } } } diff --git a/source/val/validate_scopes.cpp b/source/val/validate_scopes.cpp index 40c49d1ff2..6b493538a5 100644 --- a/source/val/validate_scopes.cpp +++ b/source/val/validate_scopes.cpp @@ -97,8 +97,10 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _, // Vulkan 1.1 specific rules if (_.context()->target_env != SPV_ENV_VULKAN_1_0) { // Scope for Non Uniform Group Operations must be limited to Subgroup - if (spvOpcodeIsNonUniformGroupOperation(opcode) && - value != spv::Scope::Subgroup) { + if ((spvOpcodeIsNonUniformGroupOperation(opcode) && + (opcode != spv::Op::OpGroupNonUniformQuadAllKHR) && + (opcode != spv::Op::OpGroupNonUniformQuadAnyKHR)) && + (value != spv::Scope::Subgroup)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << _.VkErrorID(4642) << spvOpcodeString(opcode) << ": in Vulkan environment Execution scope is limited to " @@ -178,6 +180,8 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _, // Scope for execution must be limited to Workgroup or Subgroup for // non-uniform operations if (spvOpcodeIsNonUniformGroupOperation(opcode) && + opcode != spv::Op::OpGroupNonUniformQuadAllKHR && + opcode != spv::Op::OpGroupNonUniformQuadAnyKHR && value != spv::Scope::Subgroup && value != spv::Scope::Workgroup) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << spvOpcodeString(opcode) diff --git a/test/val/val_modes_test.cpp b/test/val/val_modes_test.cpp index f17497747c..a0ea4288dc 100644 --- a/test/val/val_modes_test.cpp +++ b/test/val/val_modes_test.cpp @@ -1874,6 +1874,184 @@ OpFunctionEnd "with the FPFastMathDefault execution mode")); } +TEST_F(ValidateMode, FragmentShaderRequireFullQuadsKHR) { + const std::string spirv = R"( +OpCapability Shader +OpCapability GroupNonUniform +OpCapability GroupNonUniformVote +OpCapability GroupNonUniformBallot +OpCapability QuadControlKHR +OpExtension "SPV_KHR_quad_control" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %4 "main" +OpExecutionMode %4 OriginUpperLeft +OpExecutionMode %4 RequireFullQuadsKHR +OpDecorate %17 Location 0 +OpDecorate %31 BuiltIn HelperInvocation +OpDecorate %40 Location 0 +OpDecorate %44 DescriptorSet 0 +OpDecorate %44 Binding 0 +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%6 = OpTypeInt 32 0 +%7 = OpTypeVector %6 4 +%8 = OpTypePointer Function %7 +%10 = OpTypeBool +%11 = OpConstantTrue %10 +%12 = OpConstant %6 7 +%14 = OpTypeFloat 32 +%15 = OpTypeVector %14 4 +%16 = OpTypePointer Output %15 +%17 = OpVariable %16 Output +%18 = OpConstant %14 1 +%19 = OpConstant %14 0 +%20 = OpConstantComposite %15 %18 %19 %19 %18 +%23 = OpConstant %6 4 +%27 = OpConstant %6 1 +%28 = OpTypePointer Output %14 +%30 = OpTypePointer Input %10 +%31 = OpVariable %30 Input +%36 = OpConstant %6 2 +%38 = OpTypeVector %14 2 +%39 = OpTypePointer Input %38 +%40 = OpVariable %39 Input +%41 = OpTypeImage %14 2D 0 0 0 1 Unknown +%42 = OpTypeSampledImage %41 +%43 = OpTypePointer UniformConstant %42 +%44 = OpVariable %43 UniformConstant +%4 = OpFunction %2 None %3 +%5 = OpLabel +%9 = OpVariable %8 Function +%13 = OpGroupNonUniformBallot %7 %12 %11 +OpStore %9 %13 +OpStore %17 %20 +%21 = OpLoad %7 %9 +%22 = OpGroupNonUniformBallotBitCount %6 %12 Reduce %21 +%24 = OpIEqual %10 %22 %23 +OpSelectionMerge %26 None +OpBranchConditional %24 %25 %26 +%25 = OpLabel +%29 = OpAccessChain %28 %17 %27 +OpStore %29 %18 +OpBranch %26 +%26 = OpLabel +%32 = OpLoad %10 %31 +%33 = OpGroupNonUniformAny %10 %12 %32 +OpSelectionMerge %35 None +OpBranchConditional %33 %34 %35 +%34 = OpLabel +%37 = OpAccessChain %28 %17 %36 +OpStore %37 %18 +OpBranch %35 +%35 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Execution mode can only be used with the Fragment execution model")); +} + +TEST_F(ValidateMode, FragmentShaderQuadDerivativesKHR) { + const std::string spirv = R"( +OpCapability Shader +OpCapability GroupNonUniform +OpCapability GroupNonUniformVote +OpCapability QuadControlKHR +OpExtension "SPV_KHR_quad_control" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %4 "main" +OpExecutionMode %4 OriginUpperLeft +OpExecutionMode %4 QuadDerivativesKHR +OpDecorate %12 BuiltIn FragCoord +OpDecorate %41 Location 0 +OpDecorate %45 DescriptorSet 0 +OpDecorate %45 Binding 0 +OpDecorate %49 Location 0 +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%6 = OpTypeBool +%7 = OpTypePointer Function %6 +%9 = OpTypeFloat 32 +%10 = OpTypeVector %9 4 +%11 = OpTypePointer Input %10 +%12 = OpVariable %11 Input +%13 = OpTypeInt 32 0 +%14 = OpConstant %13 1 +%15 = OpTypePointer Input %9 +%18 = OpConstant %9 8.5 +%21 = OpConstant %9 0.100000001 +%25 = OpConstant %13 0 +%28 = OpConstant %9 3.5 +%30 = OpConstant %9 6 +%36 = OpConstant %13 7 +%40 = OpTypePointer Output %10 +%41 = OpVariable %40 Output +%42 = OpTypeImage %9 2D 0 0 0 1 Unknown +%43 = OpTypeSampledImage %42 +%44 = OpTypePointer UniformConstant %43 +%45 = OpVariable %44 UniformConstant +%47 = OpTypeVector %9 2 +%48 = OpTypePointer Input %47 +%49 = OpVariable %48 Input +%53 = OpConstant %9 0.899999976 +%54 = OpConstant %9 0.200000003 +%55 = OpConstant %9 1 +%56 = OpConstantComposite %10 %53 %54 %54 %55 +%4 = OpFunction %2 None %3 +%5 = OpLabel +%8 = OpVariable %7 Function +%16 = OpAccessChain %15 %12 %14 +%17 = OpLoad %9 %16 +%19 = OpFSub %9 %17 %18 +%20 = OpExtInst %9 %1 FAbs %19 +%22 = OpFOrdLessThan %6 %20 %21 +OpSelectionMerge %24 None +OpBranchConditional %22 %23 %24 +%23 = OpLabel +%26 = OpAccessChain %15 %12 %25 +%27 = OpLoad %9 %26 +%29 = OpFSub %9 %27 %28 +%31 = OpFMod %9 %29 %30 +%33 = OpFOrdLessThan %6 %31 %21 +OpBranch %24 +%24 = OpLabel +%34 = OpPhi %6 %22 %5 %33 %23 +OpStore %8 %34 +%35 = OpLoad %6 %8 +%37 = OpGroupNonUniformAny %6 %36 %35 +OpSelectionMerge %39 None +OpBranchConditional %37 %38 %52 +%38 = OpLabel +%46 = OpLoad %43 %45 +%50 = OpLoad %47 %49 +%51 = OpImageSampleImplicitLod %10 %46 %50 +OpStore %41 %51 +OpBranch %39 +%52 = OpLabel +OpStore %41 %56 +OpBranch %39 +%39 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_THAT(SPV_ERROR_INVALID_DATA, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Execution mode can only be used with the Fragment execution model")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/test/val/val_non_uniform_test.cpp b/test/val/val_non_uniform_test.cpp index a020500d66..530676d5e4 100644 --- a/test/val/val_non_uniform_test.cpp +++ b/test/val/val_non_uniform_test.cpp @@ -45,7 +45,9 @@ OpCapability GroupNonUniformArithmetic OpCapability GroupNonUniformClustered OpCapability GroupNonUniformQuad OpCapability GroupNonUniformPartitionedNV +OpCapability QuadControlKHR OpExtension "SPV_NV_shader_subgroup_partitioned" +OpExtension "SPV_KHR_quad_control" )"; ss << capabilities_and_extensions; @@ -178,7 +180,10 @@ TEST_P(GroupNonUniform, Vulkan1p1) { std::ostringstream sstr; sstr << "%result = " << opcode << " "; sstr << type << " "; - sstr << ConvertScope(execution_scope) << " "; + if (opcode != "OpGroupNonUniformQuadAllKHR" && + opcode != "OpGroupNonUniformQuadAnyKHR") { + sstr << ConvertScope(execution_scope) << " "; + } sstr << args << "\n"; CompileSuccessfully(GenerateShaderCode(sstr.str()), SPV_ENV_VULKAN_1_1); @@ -218,7 +223,10 @@ TEST_P(GroupNonUniform, Spirv1p3) { std::ostringstream sstr; sstr << "%result = " << opcode << " "; sstr << type << " "; - sstr << ConvertScope(execution_scope) << " "; + if (opcode != "OpGroupNonUniformQuadAllKHR" && + opcode != "OpGroupNonUniformQuadAnyKHR") { + sstr << ConvertScope(execution_scope) << " "; + } sstr << args << "\n"; CompileSuccessfully(GenerateShaderCode(sstr.str()), SPV_ENV_UNIVERSAL_1_3); @@ -869,6 +877,18 @@ INSTANTIATE_TEST_SUITE_P( Values("ClusteredReduce match_res %u32_undef"), Values("ClusterSize must be a constant instruction"))); +// Subgroup scope is not actual parameter, but used for test expectations, +INSTANTIATE_TEST_SUITE_P(GroupNonUniformQuadAllKHR, GroupNonUniform, + Combine(Values("OpGroupNonUniformQuadAllKHR"), + Values("%bool"), Values(spv::Scope::Subgroup), + Values("%true"), Values(""))); + +// Subgroup scope is not actual parameter, but used for test expectations, +INSTANTIATE_TEST_SUITE_P(GroupNonUniformQuadAnyKHR, GroupNonUniform, + Combine(Values("OpGroupNonUniformQuadAnyKHR"), + Values("%bool"), Values(spv::Scope::Subgroup), + Values("%true"), Values(""))); + TEST_F(ValidateGroupNonUniform, VulkanGroupNonUniformBallotBitCountOperation) { std::string test = R"( OpCapability Shader diff --git a/tools/sva/src/spirv.data.js b/tools/sva/src/spirv.data.js index ba969d86b3..67c0966cdc 100644 --- a/tools/sva/src/spirv.data.js +++ b/tools/sva/src/spirv.data.js @@ -4376,6 +4376,9 @@ export default { "ShaderClockKHR": { "value": 5055 }, + "QuadControlKHR": { + "value": 5087 + }, "FragmentFullyCoveredEXT": { "value": 5265 }, From 0a6f0d1893fe6de870e5f504fd6253b3595d4d23 Mon Sep 17 00:00:00 2001 From: Natalie Chouinard Date: Fri, 26 Jan 2024 16:15:29 -0500 Subject: [PATCH 358/523] opt: Add TrimCapabilities pass to spirv-opt tool (#5545) Add an option to the spirv-opt tool to run the TrimCapabilitiesPass. --- source/opt/optimizer.cpp | 2 ++ tools/opt/opt.cpp | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index 4d089f6a20..429a6cba85 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -623,6 +623,8 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag, pass_args.c_str()); return false; } + } else if (pass_name == "trim-capabilities") { + RegisterPass(CreateTrimCapabilitiesPass()); } else { Errorf(consumer(), nullptr, {}, "Unknown flag '--%s'. Use --help for a list of valid flags", diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index f320baf923..f8456d7144 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -525,6 +525,10 @@ Options (in lexicographical order):)", USR/SYS time are returned by getrusage() and can have a small error.)"); printf(R"( + --trim-capabilities + Remove unnecessary capabilities and extensions declared within the + module.)"); + printf(R"( --upgrade-memory-model Upgrades the Logical GLSL450 memory model to Logical VulkanKHR. Transforms memory, image, atomic and barrier operations to conform From 80bc99c3d4a33fe07ae5dc93147bdd9495688b10 Mon Sep 17 00:00:00 2001 From: Scott Todd Date: Fri, 26 Jan 2024 13:47:13 -0800 Subject: [PATCH 359/523] Skip entire test/ folder if SPIRV_SKIP_TESTS is set. (#5548) Without this (or similar filtering), the `spirv-tools_expect_unittests` and `spirv-tools_spirv_test_framework_unittests` Python tests at `test/tools/` get defined even when `SPIRV_SKIP_TESTS` is set. --- test/CMakeLists.txt | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 662c0bf4cb..40c64f8066 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -12,22 +12,23 @@ # See the License for the specific language governing permissions and # limitations under the License. +if (${SPIRV_SKIP_TESTS}) + return() +endif() + +if (TARGET gmock_main) + message(STATUS "Found Google Mock, building tests.") +else() + message(STATUS "Did not find googletest, tests will not be built. " + "To enable tests place googletest in '/external/googletest'.") +endif() + # Add a SPIR-V Tools unit test. Signature: # add_spvtools_unittest( # TARGET target_name # SRCS src_file.h src_file.cpp # LIBS lib1 lib2 # ) - -if (NOT "${SPIRV_SKIP_TESTS}") - if (TARGET gmock_main) - message(STATUS "Found Google Mock, building tests.") - else() - message(STATUS "Did not find googletest, tests will not be built. " - "To enable tests place googletest in '/external/googletest'.") - endif() -endif() - function(add_spvtools_unittest) if (NOT "${SPIRV_SKIP_TESTS}" AND TARGET gmock_main) set(one_value_args TARGET PCH_FILE) From e5fcb7facf1c891cb30630ea8784da5493d78c22 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 29 Jan 2024 16:01:06 +0000 Subject: [PATCH 360/523] Roll external/re2/ 264e71e88..826ad10e5 (1 commit) (#5538) * Roll external/googletest/ 96cd50c08..6a5938233 (4 commits) https://github.com/google/googletest/compare/96cd50c082d8...6a5938233b65 $ git log 96cd50c08..6a5938233 --date=short --no-merges --format='%ad %ae %s' 2024-01-25 dmauro Add support for Bzlmod for the next release https://bazel.build/external/overview#bzlmod 2024-01-23 absl-team Fix double-promotion warnings in AppropriateResolution() 2024-01-22 dinor googletest: Fix incorrect comment about `value_param` of `internal::MakeAndRegisterTestInfo` 2024-01-10 michael.128.leslie only apply -lregex for qnx710 and newer Created with: roll-dep external/googletest * Roll external/re2/ 264e71e88..826ad10e5 (1 commit) https://github.com/google/re2/compare/264e71e88e1c...826ad10e58a0 $ git log 264e71e88..826ad10e5 --date=short --no-merges --format='%ad %ae %s' 2024-01-19 junyer Delete an unused function. Created with: roll-dep external/re2 * Roll external/spirv-headers/ 5aa1dd8a1..1c9115b56 (1 commit) https://github.com/KhronosGroup/SPIRV-Headers/compare/5aa1dd8a1118...1c9115b562ba $ git log 5aa1dd8a1..1c9115b56 --date=short --no-merges --format='%ad %ae %s' 2024-01-26 dneto List all licenses in the root LICENSE file. (#410) 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 1856d3c7e7..e639859b39 100644 --- a/DEPS +++ b/DEPS @@ -7,13 +7,13 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '96cd50c082d880a9aab6455dcc5817cfbf0ea45f', + 'googletest_revision': '6a5938233b6519ba99ddb7c7314d45d3fa877969', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '264e71e88e1c8a4b5ec326e70e9cf1d476f58a58', - 'spirv_headers_revision': '5aa1dd8a11182ea9a6a0eabd6a9edc639d5dbecd', + 're2_revision': '826ad10e58a042faf57d7c329b0fd0a04b797e0b', + 'spirv_headers_revision': '1c9115b562bab79ee2160fbd845f41b815b9f21f', } deps = { From 27ffe976e0a35b885ad96f6e63eeac14fb0a0225 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jan 2024 10:29:19 -0500 Subject: [PATCH 361/523] build(deps): bump the github-actions group with 2 updates (#5549) Bumps the github-actions group with 2 updates: [actions/upload-artifact](https://github.com/actions/upload-artifact) and [github/codeql-action](https://github.com/github/codeql-action). Updates `actions/upload-artifact` from 4.2.0 to 4.3.0 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/694cdabd8bdb0f10b2cea11669e1bf5453eed0a6...26f96dfa697d77e81fd5907df203aa23a56210a8) Updates `github/codeql-action` from 3.23.1 to 3.23.2 - [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/0b21cf2492b6b02c465a3e5d7c473717ad7721ba...b7bf0a3ed3ecfa44160715d7c442788f65f0f923) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-minor 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 35bc0cb321..572491025d 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -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@694cdabd8bdb0f10b2cea11669e1bf5453eed0a6 # v4.2.0 + uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0 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@0b21cf2492b6b02c465a3e5d7c473717ad7721ba # v3.23.1 + uses: github/codeql-action/upload-sarif@b7bf0a3ed3ecfa44160715d7c442788f65f0f923 # v3.23.2 with: sarif_file: results.sarif From ad11927e6cb251624f884327ede64a642be11f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 30 Jan 2024 18:13:46 +0100 Subject: [PATCH 362/523] opt: add SPV_EXT_mesh_shader to opt allowlist (#5551) Add this extension to the allowlist, allowing DCE and other optimizations on modules exposing this. Note: NV equivalent is already allowed. --- source/opt/aggressive_dead_code_elim_pass.cpp | 1 + source/opt/local_access_chain_convert_pass.cpp | 4 ++-- source/opt/local_single_block_elim_pass.cpp | 1 + source/opt/local_single_store_elim_pass.cpp | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp index b372571f51..4737da5f9c 100644 --- a/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/source/opt/aggressive_dead_code_elim_pass.cpp @@ -985,6 +985,7 @@ void AggressiveDCEPass::InitExtensions() { "SPV_NV_shader_image_footprint", "SPV_NV_shading_rate", "SPV_NV_mesh_shader", + "SPV_EXT_mesh_shader", "SPV_NV_ray_tracing", "SPV_KHR_ray_tracing", "SPV_KHR_ray_query", diff --git a/source/opt/local_access_chain_convert_pass.cpp b/source/opt/local_access_chain_convert_pass.cpp index ea1bdeeb3b..7ba75cb7a4 100644 --- a/source/opt/local_access_chain_convert_pass.cpp +++ b/source/opt/local_access_chain_convert_pass.cpp @@ -420,8 +420,8 @@ void LocalAccessChainConvertPass::InitExtensions() { "SPV_EXT_demote_to_helper_invocation", "SPV_EXT_descriptor_indexing", "SPV_NV_fragment_shader_barycentric", "SPV_NV_compute_shader_derivatives", "SPV_NV_shader_image_footprint", - "SPV_NV_shading_rate", "SPV_NV_mesh_shader", "SPV_NV_ray_tracing", - "SPV_KHR_ray_tracing", "SPV_KHR_ray_query", + "SPV_NV_shading_rate", "SPV_NV_mesh_shader", "SPV_EXT_mesh_shader", + "SPV_NV_ray_tracing", "SPV_KHR_ray_tracing", "SPV_KHR_ray_query", "SPV_EXT_fragment_invocation_density", "SPV_KHR_terminate_invocation", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_integer_dot_product", "SPV_EXT_shader_image_int64", "SPV_KHR_non_semantic_info", diff --git a/source/opt/local_single_block_elim_pass.cpp b/source/opt/local_single_block_elim_pass.cpp index 7502d0497e..d7a9295e84 100644 --- a/source/opt/local_single_block_elim_pass.cpp +++ b/source/opt/local_single_block_elim_pass.cpp @@ -273,6 +273,7 @@ void LocalSingleBlockLoadStoreElimPass::InitExtensions() { "SPV_NV_shader_image_footprint", "SPV_NV_shading_rate", "SPV_NV_mesh_shader", + "SPV_EXT_mesh_shader", "SPV_NV_ray_tracing", "SPV_KHR_ray_tracing", "SPV_KHR_ray_query", diff --git a/source/opt/local_single_store_elim_pass.cpp b/source/opt/local_single_store_elim_pass.cpp index f6fc2760e0..7cd6b0eb47 100644 --- a/source/opt/local_single_store_elim_pass.cpp +++ b/source/opt/local_single_store_elim_pass.cpp @@ -124,6 +124,7 @@ void LocalSingleStoreElimPass::InitExtensionAllowList() { "SPV_NV_shader_image_footprint", "SPV_NV_shading_rate", "SPV_NV_mesh_shader", + "SPV_EXT_mesh_shader", "SPV_NV_ray_tracing", "SPV_KHR_ray_query", "SPV_EXT_fragment_invocation_density", From de65e81740ddaef7613a0ebb6af3274c1f26e8fb Mon Sep 17 00:00:00 2001 From: Natalie Chouinard Date: Thu, 1 Feb 2024 09:47:42 -0500 Subject: [PATCH 363/523] [NFC] Remove unused code (#5554) --- source/opt/def_use_manager.h | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/source/opt/def_use_manager.h b/source/opt/def_use_manager.h index a8dbbc60b6..13cf9bd3ed 100644 --- a/source/opt/def_use_manager.h +++ b/source/opt/def_use_manager.h @@ -27,28 +27,6 @@ namespace spvtools { namespace opt { namespace analysis { -// Class for representing a use of id. Note that: -// * Result type id is a use. -// * Ids referenced in OpSectionMerge & OpLoopMerge are considered as use. -// * Ids referenced in OpPhi's in operands are considered as use. -struct Use { - Instruction* inst; // Instruction using the id. - uint32_t operand_index; // logical operand index of the id use. This can be - // the index of result type id. -}; - -inline bool operator==(const Use& lhs, const Use& rhs) { - return lhs.inst == rhs.inst && lhs.operand_index == rhs.operand_index; -} - -inline bool operator!=(const Use& lhs, const Use& rhs) { return !(lhs == rhs); } - -inline bool operator<(const Use& lhs, const Use& rhs) { - if (lhs.inst < rhs.inst) return true; - if (lhs.inst > rhs.inst) return false; - return lhs.operand_index < rhs.operand_index; -} - // Definition should never be null. User can be null, however, such an entry // should be used only for searching (e.g. all users of a particular definition) // and never stored in a container. From 5d3c8b73f70aecedbdeccbacdc4872507429f8b9 Mon Sep 17 00:00:00 2001 From: Natalie Chouinard Date: Thu, 1 Feb 2024 09:50:36 -0500 Subject: [PATCH 364/523] opt: Add OpEntryPoint to DescriptorScalarReplacement pass (#5553) Add OpEntryPoint to the list of instructions processed by the DescriptorScalarReplacement pass. This is necessary for SPIR-V 1.4 and above where global variables must be included in the interface. Fixes microsoft/DirectXShaderCompiler#5962 --- source/opt/desc_sroa.cpp | 49 ++++++++++++++++++++++++-- source/opt/desc_sroa.h | 5 +++ test/opt/desc_sroa_test.cpp | 68 +++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 2 deletions(-) diff --git a/source/opt/desc_sroa.cpp b/source/opt/desc_sroa.cpp index 8da0c864fe..2c0f4829f2 100644 --- a/source/opt/desc_sroa.cpp +++ b/source/opt/desc_sroa.cpp @@ -54,9 +54,10 @@ Pass::Status DescriptorScalarReplacement::Process() { bool DescriptorScalarReplacement::ReplaceCandidate(Instruction* var) { std::vector access_chain_work_list; std::vector load_work_list; + std::vector entry_point_work_list; bool failed = !get_def_use_mgr()->WhileEachUser( - var->result_id(), - [this, &access_chain_work_list, &load_work_list](Instruction* use) { + var->result_id(), [this, &access_chain_work_list, &load_work_list, + &entry_point_work_list](Instruction* use) { if (use->opcode() == spv::Op::OpName) { return true; } @@ -73,6 +74,9 @@ bool DescriptorScalarReplacement::ReplaceCandidate(Instruction* var) { case spv::Op::OpLoad: load_work_list.push_back(use); return true; + case spv::Op::OpEntryPoint: + entry_point_work_list.push_back(use); + return true; default: context()->EmitErrorMessage( "Variable cannot be replaced: invalid instruction", use); @@ -95,6 +99,11 @@ bool DescriptorScalarReplacement::ReplaceCandidate(Instruction* var) { return false; } } + for (Instruction* use : entry_point_work_list) { + if (!ReplaceEntryPoint(var, use)) { + return false; + } + } return true; } @@ -147,6 +156,42 @@ bool DescriptorScalarReplacement::ReplaceAccessChain(Instruction* var, return true; } +bool DescriptorScalarReplacement::ReplaceEntryPoint(Instruction* var, + Instruction* use) { + // Build a new |OperandList| for |use| that removes |var| and adds its + // replacement variables. + Instruction::OperandList new_operands; + + // Copy all operands except |var|. + bool found = false; + for (uint32_t idx = 0; idx < use->NumOperands(); idx++) { + Operand& op = use->GetOperand(idx); + if (op.type == SPV_OPERAND_TYPE_ID && op.words[0] == var->result_id()) { + found = true; + } else { + new_operands.emplace_back(op); + } + } + + if (!found) { + context()->EmitErrorMessage( + "Variable cannot be replaced: invalid instruction", use); + return false; + } + + // Add all new replacement variables. + uint32_t num_replacement_vars = + descsroautil::GetNumberOfElementsForArrayOrStruct(context(), var); + for (uint32_t i = 0; i < num_replacement_vars; i++) { + new_operands.push_back( + {SPV_OPERAND_TYPE_ID, {GetReplacementVariable(var, i)}}); + } + + use->ReplaceOperands(new_operands); + context()->UpdateDefUse(use); + return true; +} + uint32_t DescriptorScalarReplacement::GetReplacementVariable(Instruction* var, uint32_t idx) { auto replacement_vars = replacement_variables_.find(var); diff --git a/source/opt/desc_sroa.h b/source/opt/desc_sroa.h index 6a24fd8714..901be3e98b 100644 --- a/source/opt/desc_sroa.h +++ b/source/opt/desc_sroa.h @@ -64,6 +64,11 @@ class DescriptorScalarReplacement : public Pass { // otherwise. bool ReplaceLoadedValue(Instruction* var, Instruction* value); + // Replaces the given composite variable |var| in the OpEntryPoint with the + // new replacement variables, one for each element of the array |var|. Returns + // |true| if successful, and |false| otherwise. + bool ReplaceEntryPoint(Instruction* var, Instruction* use); + // Replaces the given OpCompositeExtract |extract| and all of its references // with an OpLoad of a replacement variable. |var| is the variable with // composite type whose value is being used by |extract|. Assumes that diff --git a/test/opt/desc_sroa_test.cpp b/test/opt/desc_sroa_test.cpp index 7a118f988e..5c166d83f7 100644 --- a/test/opt/desc_sroa_test.cpp +++ b/test/opt/desc_sroa_test.cpp @@ -918,6 +918,74 @@ TEST_F(DescriptorScalarReplacementTest, DecorateStringForReflect) { SinglePassRunAndMatch(shader, true); } +TEST_F(DescriptorScalarReplacementTest, ExpandArrayInOpEntryPoint) { + const std::string text = R"(; SPIR-V +; Version: 1.6 +; Bound: 31 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + +; CHECK: OpEntryPoint GLCompute %main "main" %output_0_ %output_1_ + + OpEntryPoint GLCompute %main "main" %output + OpExecutionMode %main LocalSize 1 1 1 + OpSource HLSL 670 + OpName %type_RWByteAddressBuffer "type.RWByteAddressBuffer" + OpName %output "output" + OpName %main "main" + OpName %src_main "src.main" + OpName %bb_entry "bb.entry" + +; CHECK: OpDecorate %output_1_ DescriptorSet 0 +; CHECK: OpDecorate %output_1_ Binding 1 +; CHECK: OpDecorate %output_0_ DescriptorSet 0 +; CHECK: OpDecorate %output_0_ Binding 0 + + OpDecorate %output DescriptorSet 0 + OpDecorate %output Binding 0 + + OpDecorate %_runtimearr_uint ArrayStride 4 + OpMemberDecorate %type_RWByteAddressBuffer 0 Offset 0 + OpDecorate %type_RWByteAddressBuffer Block + %int = OpTypeInt 32 1 + %int_1 = OpConstant %int 1 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_2 = OpConstant %uint 2 + %uint_32 = OpConstant %uint 32 +%_runtimearr_uint = OpTypeRuntimeArray %uint +%type_RWByteAddressBuffer = OpTypeStruct %_runtimearr_uint +%_arr_type_RWByteAddressBuffer_uint_2 = OpTypeArray %type_RWByteAddressBuffer %uint_2 +%_ptr_StorageBuffer__arr_type_RWByteAddressBuffer_uint_2 = OpTypePointer StorageBuffer %_arr_type_RWByteAddressBuffer_uint_2 + %void = OpTypeVoid + %23 = OpTypeFunction %void +%_ptr_StorageBuffer_type_RWByteAddressBuffer = OpTypePointer StorageBuffer %type_RWByteAddressBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint + +; CHECK: %output_1_ = OpVariable %_ptr_StorageBuffer_type_RWByteAddressBuffer StorageBuffer +; CHECK: %output_0_ = OpVariable %_ptr_StorageBuffer_type_RWByteAddressBuffer StorageBuffer + + %output = OpVariable %_ptr_StorageBuffer__arr_type_RWByteAddressBuffer_uint_2 StorageBuffer + + %main = OpFunction %void None %23 + %26 = OpLabel + %27 = OpFunctionCall %void %src_main + OpReturn + OpFunctionEnd + %src_main = OpFunction %void None %23 + %bb_entry = OpLabel + %28 = OpAccessChain %_ptr_StorageBuffer_type_RWByteAddressBuffer %output %int_1 + %29 = OpShiftRightLogical %uint %uint_0 %uint_2 + %30 = OpAccessChain %_ptr_StorageBuffer_uint %28 %uint_0 %29 + OpStore %30 %uint_32 + OpReturn + OpFunctionEnd + )"; + + SinglePassRunAndMatch(text, false); +} + } // namespace } // namespace opt } // namespace spvtools From 61c51d4bafaba2ef8ecdf86247ddb7266e49138d Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Fri, 2 Feb 2024 04:20:42 +0900 Subject: [PATCH 365/523] spirv-val: Add Mesh Primitive Built-In validaiton (#5529) --- source/val/validate_builtins.cpp | 180 +++++++++++++++++++++- source/val/validation_state.cpp | 18 +++ test/val/val_builtins_test.cpp | 254 +++++++++++++++++++++++++++++++ 3 files changed, 449 insertions(+), 3 deletions(-) diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp index 3e81712506..42fbc52a78 100644 --- a/source/val/validate_builtins.cpp +++ b/source/val/validate_builtins.cpp @@ -118,13 +118,15 @@ typedef enum VUIDError_ { VUIDErrorMax, } VUIDError; -const static uint32_t NumVUIDBuiltins = 36; +const static uint32_t NumVUIDBuiltins = 39; typedef struct { spv::BuiltIn builtIn; uint32_t vuid[VUIDErrorMax]; // execution mode, storage class, type VUIDs } BuiltinVUIDMapping; +// Many built-ins have the same checks (Storage Class, Type, etc) +// This table provides a nice LUT for the VUIDs std::array builtinVUIDInfo = {{ // clang-format off {spv::BuiltIn::SubgroupEqMask, {0, 4370, 4371}}, @@ -163,8 +165,11 @@ std::array builtinVUIDInfo = {{ {spv::BuiltIn::CullMaskKHR, {6735, 6736, 6737}}, {spv::BuiltIn::BaryCoordKHR, {4154, 4155, 4156}}, {spv::BuiltIn::BaryCoordNoPerspKHR, {4160, 4161, 4162}}, - // clang-format off -} }; + {spv::BuiltIn::PrimitivePointIndicesEXT, {7041, 7043, 7044}}, + {spv::BuiltIn::PrimitiveLineIndicesEXT, {7047, 7049, 7050}}, + {spv::BuiltIn::PrimitiveTriangleIndicesEXT, {7053, 7055, 7056}}, + // clang-format on +}}; uint32_t GetVUIDForBuiltin(spv::BuiltIn builtIn, VUIDError type) { uint32_t vuid = 0; @@ -356,6 +361,9 @@ class BuiltInsValidator { spv_result_t ValidateRayTracingBuiltinsAtDefinition( const Decoration& decoration, const Instruction& inst); + spv_result_t ValidateMeshShadingEXTBuiltinsAtDefinition( + const Decoration& decoration, const Instruction& inst); + // The following section contains functions which are called when id defined // by |referenced_inst| is // 1. referenced by |referenced_from_inst| @@ -546,6 +554,11 @@ class BuiltInsValidator { const Instruction& referenced_inst, const Instruction& referenced_from_inst); + spv_result_t ValidateMeshShadingEXTBuiltinsAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst); + // Validates that |built_in_inst| is not (even indirectly) referenced from // within a function which can be called with |execution_model|. // @@ -581,6 +594,10 @@ class BuiltInsValidator { spv_result_t ValidateI32Arr( const Decoration& decoration, const Instruction& inst, const std::function& diag); + spv_result_t ValidateArrayedI32Vec( + const Decoration& decoration, const Instruction& inst, + uint32_t num_components, + const std::function& diag); spv_result_t ValidateOptionalArrayedI32( const Decoration& decoration, const Instruction& inst, const std::function& diag); @@ -909,6 +926,45 @@ spv_result_t BuiltInsValidator::ValidateI32Vec( return SPV_SUCCESS; } +spv_result_t BuiltInsValidator::ValidateArrayedI32Vec( + const Decoration& decoration, const Instruction& inst, + uint32_t num_components, + const std::function& diag) { + uint32_t underlying_type = 0; + if (spv_result_t error = + GetUnderlyingType(_, decoration, inst, &underlying_type)) { + return error; + } + + const Instruction* const type_inst = _.FindDef(underlying_type); + if (type_inst->opcode() != spv::Op::OpTypeArray) { + return diag(GetDefinitionDesc(decoration, inst) + " is not an array."); + } + + const uint32_t component_type = type_inst->word(2); + if (!_.IsIntVectorType(component_type)) { + return diag(GetDefinitionDesc(decoration, inst) + " is not an int vector."); + } + + const uint32_t actual_num_components = _.GetDimension(component_type); + if (_.GetDimension(component_type) != num_components) { + std::ostringstream ss; + ss << GetDefinitionDesc(decoration, inst) << " has " + << actual_num_components << " components."; + return diag(ss.str()); + } + + const uint32_t bit_width = _.GetBitWidth(component_type); + if (bit_width != 32) { + std::ostringstream ss; + ss << GetDefinitionDesc(decoration, inst) + << " has components with bit width " << bit_width << "."; + return diag(ss.str()); + } + + return SPV_SUCCESS; +} + spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32Vec( const Decoration& decoration, const Instruction& inst, uint32_t num_components, @@ -4108,6 +4164,119 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference( return SPV_SUCCESS; } +spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition( + const Decoration& decoration, const Instruction& inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); + if (builtin == spv::BuiltIn::PrimitivePointIndicesEXT) { + if (spv_result_t error = ValidateI32Arr( + decoration, inst, + [this, &inst, &decoration, + &vuid](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) + << " variable needs to be a 32-bit int array." + << message; + })) { + return error; + } + } + if (builtin == spv::BuiltIn::PrimitiveLineIndicesEXT) { + if (spv_result_t error = ValidateArrayedI32Vec( + decoration, inst, 2, + [this, &inst, &decoration, + &vuid](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) + << " variable needs to be a 2-component 32-bit int " + "array." + << message; + })) { + return error; + } + } + if (builtin == spv::BuiltIn::PrimitiveTriangleIndicesEXT) { + if (spv_result_t error = ValidateArrayedI32Vec( + decoration, inst, 3, + [this, &inst, &decoration, + &vuid](const std::string& message) -> spv_result_t { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << _.VkErrorID(vuid) << "According to the " + << spvLogStringForEnv(_.context()->target_env) + << " spec BuiltIn " + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) + << " variable needs to be a 3-component 32-bit int " + "array." + << message; + })) { + return error; + } + } + } + // Seed at reference checks with this built-in. + return ValidateMeshShadingEXTBuiltinsAtReference(decoration, inst, inst, + inst); +} + +spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference( + const Decoration& decoration, const Instruction& built_in_inst, + const Instruction& referenced_inst, + const Instruction& referenced_from_inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::StorageClass storage_class = + GetStorageClass(referenced_from_inst); + if (storage_class != spv::StorageClass::Max && + storage_class != spv::StorageClass::Output) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorStorageClass); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + uint32_t(builtin)) + << " to be only used for variables with Output storage class. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst) + << " " << GetStorageClassDesc(referenced_from_inst); + } + + for (const spv::ExecutionModel execution_model : execution_models_) { + if (execution_model != spv::ExecutionModel::MeshEXT) { + uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorExecutionModel); + return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) + << _.VkErrorID(vuid) + << spvLogStringForEnv(_.context()->target_env) + << " spec allows BuiltIn " + << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, + uint32_t(builtin)) + << " to be used only with MeshEXT execution model. " + << GetReferenceDesc(decoration, built_in_inst, referenced_inst, + referenced_from_inst, execution_model); + } + } + } + + if (function_id_ == 0) { + // Propagate this rule to all dependant ids in the global scope. + id_to_at_reference_checks_[referenced_from_inst.id()].push_back( + std::bind(&BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference, + this, decoration, built_in_inst, referenced_from_inst, + std::placeholders::_1)); + } + + return SPV_SUCCESS; +} + spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( const Decoration& decoration, const Instruction& inst) { const spv::BuiltIn label = spv::BuiltIn(decoration.params()[0]); @@ -4283,6 +4452,11 @@ spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( case spv::BuiltIn::CullMaskKHR: { return ValidateRayTracingBuiltinsAtDefinition(decoration, inst); } + case spv::BuiltIn::PrimitivePointIndicesEXT: + case spv::BuiltIn::PrimitiveLineIndicesEXT: + case spv::BuiltIn::PrimitiveTriangleIndicesEXT: { + return ValidateMeshShadingEXTBuiltinsAtDefinition(decoration, inst); + } case spv::BuiltIn::PrimitiveShadingRateKHR: { return ValidatePrimitiveShadingRateAtDefinition(decoration, inst); } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 13c07eec38..852860e171 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -2259,6 +2259,24 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-PushConstant-06808); case 6925: return VUID_WRAP(VUID-StandaloneSpirv-Uniform-06925); + case 7041: + return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07041); + case 7043: + return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07043); + case 7044: + return VUID_WRAP(VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07044); + case 7047: + return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07047); + case 7049: + return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07049); + case 7050: + return VUID_WRAP(VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07050); + case 7053: + return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07053); + case 7055: + return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07055); + case 7056: + return VUID_WRAP(VUID-PrimitiveTriangleIndicesEXT-PrimitiveTriangleIndicesEXT-07056); case 7102: return VUID_WRAP(VUID-StandaloneSpirv-MeshEXT-07102); case 7320: diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp index 4f9fc97631..01049692da 100644 --- a/test/val/val_builtins_test.cpp +++ b/test/val/val_builtins_test.cpp @@ -4261,6 +4261,260 @@ INSTANTIATE_TEST_SUITE_P( Values(TestResult(SPV_ERROR_INVALID_DATA, "needs to be a 3-component 32-bit float vector")))); +std::string GenerateMeshShadingCode(const std::string& built_in, + const std::string& execution_mode, + const std::string& body, + const std::string& declarations = "") { + std::ostringstream ss; + ss << R"( +OpCapability MeshShadingEXT +OpExtension "SPV_EXT_mesh_shader" +OpMemoryModel Logical GLSL450 +OpEntryPoint MeshEXT %main "main" %var +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main OutputVertices 1 +OpExecutionMode %main OutputPrimitivesEXT 16 +)"; + ss << "OpExecutionMode %main " << execution_mode << "\n"; + ss << "OpDecorate %var BuiltIn " << built_in << "\n"; + + ss << R"( +%void = OpTypeVoid +%func = OpTypeFunction %void +%bool = OpTypeBool +%int = OpTypeInt 32 1 +%uint = OpTypeInt 32 0 +%v2uint = OpTypeVector %uint 2 +%v3uint = OpTypeVector %uint 3 + +%int_0 = OpConstant %int 0 +%uint_16 = OpConstant %uint 16 +)"; + + ss << declarations; + + ss << R"( +%main = OpFunction %void None %func +%main_entry = OpLabel +)"; + + ss << body; + + ss << R"( +OpReturn +OpFunctionEnd)"; + return ss.str(); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTSuccess) { + const std::string declarations = R"( +%array = OpTypeArray %v3uint %uint_16 +%array_ptr = OpTypePointer Output %array +%var = OpVariable %array_ptr Output +%ptr = OpTypePointer Output %v3uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT", + "OutputTrianglesEXT", body, declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2)); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTStorageClass) { + const std::string declarations = R"( +%array = OpTypeArray %v3uint %uint_16 +%array_ptr = OpTypePointer Input %array +%var = OpVariable %array_ptr Input +%ptr = OpTypePointer Input %v3uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT", + "OutputTrianglesEXT", body, declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-PrimitiveTriangleIndicesEXT-" + "PrimitiveTriangleIndicesEXT-07055")); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTVectorSize) { + const std::string declarations = R"( +%array = OpTypeArray %v2uint %uint_16 +%array_ptr = OpTypePointer Output %array +%var = OpVariable %array_ptr Output +%ptr = OpTypePointer Output %v2uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT", + "OutputTrianglesEXT", body, declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-PrimitiveTriangleIndicesEXT-" + "PrimitiveTriangleIndicesEXT-07056")); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitiveTriangleIndicesEXTNonArray) { + const std::string declarations = R"( +%ptr = OpTypePointer Output %v3uint +%var = OpVariable %ptr Output +)"; + const std::string body = R"( +%load = OpLoad %v3uint %var +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitiveTriangleIndicesEXT", + "OutputTrianglesEXT", body, declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-PrimitiveTriangleIndicesEXT-" + "PrimitiveTriangleIndicesEXT-07056")); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTSuccess) { + const std::string declarations = R"( +%array = OpTypeArray %v2uint %uint_16 +%array_ptr = OpTypePointer Output %array +%var = OpVariable %array_ptr Output +%ptr = OpTypePointer Output %v2uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitiveLineIndicesEXT", "OutputLinesEXT", body, + declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2)); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTStorageClass) { + const std::string declarations = R"( +%array = OpTypeArray %v2uint %uint_16 +%array_ptr = OpTypePointer Input %array +%var = OpVariable %array_ptr Input +%ptr = OpTypePointer Input %v2uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitiveLineIndicesEXT", "OutputLinesEXT", body, + declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT( + getDiagnosticString(), + AnyVUID("VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07049")); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitiveLineIndicesEXTType) { + const std::string declarations = R"( +%array = OpTypeArray %v3uint %uint_16 +%array_ptr = OpTypePointer Input %array +%var = OpVariable %array_ptr Input +%ptr = OpTypePointer Input %v3uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitiveLineIndicesEXT", "OutputLinesEXT", body, + declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT( + getDiagnosticString(), + AnyVUID("VUID-PrimitiveLineIndicesEXT-PrimitiveLineIndicesEXT-07050")); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTSuccess) { + const std::string declarations = R"( +%array = OpTypeArray %uint %uint_16 +%array_ptr = OpTypePointer Output %array +%var = OpVariable %array_ptr Output +%ptr = OpTypePointer Output %uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitivePointIndicesEXT", "OutputPoints", body, + declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2)); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTStorageClass) { + const std::string declarations = R"( +%array = OpTypeArray %uint %uint_16 +%array_ptr = OpTypePointer Input %array +%var = OpVariable %array_ptr Input +%ptr = OpTypePointer Input %uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitivePointIndicesEXT", "OutputPoints", body, + declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT( + getDiagnosticString(), + AnyVUID("VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07043")); +} + +TEST_F(ValidateBuiltIns, VulkanPrimitivePointIndicesEXTType) { + const std::string declarations = R"( +%array = OpTypeArray %v3uint %uint_16 +%array_ptr = OpTypePointer Output %array +%var = OpVariable %array_ptr Output +%ptr = OpTypePointer Output %v3uint +)"; + const std::string body = R"( +%access = OpAccessChain %ptr %var %int_0 +)"; + + CompileSuccessfully( + GenerateMeshShadingCode("PrimitivePointIndicesEXT", "OutputPoints", body, + declarations) + .c_str(), + SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT( + getDiagnosticString(), + AnyVUID("VUID-PrimitivePointIndicesEXT-PrimitivePointIndicesEXT-07044")); +} + } // namespace } // namespace val } // namespace spvtools From 8d3ee2e8f0775687ed0965190a8a214c0a77bbb7 Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Thu, 1 Feb 2024 14:19:02 -0800 Subject: [PATCH 366/523] spirv-opt: Fix OpCompositeExtract relaxation with struct operands (#5536) --- source/opt/convert_to_half_pass.cpp | 24 +++++++- test/opt/convert_relaxed_to_half_test.cpp | 69 +++++++++++++++++++++++ 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/source/opt/convert_to_half_pass.cpp b/source/opt/convert_to_half_pass.cpp index cb0065d2d3..e243bedf0c 100644 --- a/source/opt/convert_to_half_pass.cpp +++ b/source/opt/convert_to_half_pass.cpp @@ -171,6 +171,19 @@ bool ConvertToHalfPass::RemoveRelaxedDecoration(uint32_t id) { bool ConvertToHalfPass::GenHalfArith(Instruction* inst) { bool modified = false; + // If this is a OpCompositeExtract instruction and has a struct operand, we + // should not relax this instruction. Doing so could cause a mismatch between + // the result type and the struct member type. + bool hasStructOperand = false; + if (inst->opcode() == spv::Op::OpCompositeExtract) { + inst->ForEachInId([&hasStructOperand, this](uint32_t* idp) { + Instruction* op_inst = get_def_use_mgr()->GetDef(*idp); + if (IsStruct(op_inst)) hasStructOperand = true; + }); + if (hasStructOperand) { + return false; + } + } // Convert all float32 based operands to float16 equivalent and change // instruction type to float16 equivalent. inst->ForEachInId([&inst, &modified, this](uint32_t* idp) { @@ -303,12 +316,19 @@ bool ConvertToHalfPass::CloseRelaxInst(Instruction* inst) { if (closure_ops_.count(inst->opcode()) == 0) return false; // Can relax if all float operands are relaxed bool relax = true; - inst->ForEachInId([&relax, this](uint32_t* idp) { + bool hasStructOperand = false; + inst->ForEachInId([&relax, &hasStructOperand, this](uint32_t* idp) { Instruction* op_inst = get_def_use_mgr()->GetDef(*idp); - if (IsStruct(op_inst)) relax = false; + if (IsStruct(op_inst)) hasStructOperand = true; if (!IsFloat(op_inst, 32)) return; if (!IsRelaxed(*idp)) relax = false; }); + // If the instruction has a struct operand, we should not relax it, even if + // all its uses are relaxed. Doing so could cause a mismatch between the + // result type and the struct member type. + if (hasStructOperand) { + return false; + } if (relax) { AddRelaxed(inst->result_id()); return true; diff --git a/test/opt/convert_relaxed_to_half_test.cpp b/test/opt/convert_relaxed_to_half_test.cpp index 62b9ae4535..c5774045c3 100644 --- a/test/opt/convert_relaxed_to_half_test.cpp +++ b/test/opt/convert_relaxed_to_half_test.cpp @@ -1713,6 +1713,75 @@ TEST_F(ConvertToHalfTest, PreserveImageOperandPrecision) { SinglePassRunAndMatch(test, true); } +TEST_F(ConvertToHalfTest, DontRelaxDecoratedOpCompositeExtract) { + // This test checks that a OpCompositeExtract with a Struct operand won't be + // relaxed, even if it is explicitly decorated with RelaxedPrecision. + const std::string test = + R"(OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "main" +OpExecutionMode %1 OriginUpperLeft +OpDecorate %9 RelaxedPrecision +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_struct_6 = OpTypeStruct %v4float +%7 = OpUndef %_struct_6 +%1 = OpFunction %void None %3 +%8 = OpLabel +%9 = OpCompositeExtract %float %7 0 3 +OpReturn +OpFunctionEnd +)"; + + const std::string expected = + R"(OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "main" +OpExecutionMode %1 OriginUpperLeft +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_struct_6 = OpTypeStruct %v4float +%7 = OpUndef %_struct_6 +%1 = OpFunction %void None %3 +%8 = OpLabel +%9 = OpCompositeExtract %float %7 0 3 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(test, expected, true); +} + +TEST_F(ConvertToHalfTest, DontRelaxOpCompositeExtract) { + // This test checks that a OpCompositeExtract with a Struct operand won't be + // relaxed, even if its result has no uses. + const std::string test = + R"(OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %1 "main" +OpExecutionMode %1 OriginUpperLeft +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%_struct_6 = OpTypeStruct %v4float +%7 = OpUndef %_struct_6 +%1 = OpFunction %void None %3 +%8 = OpLabel +%9 = OpCompositeExtract %float %7 0 3 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(test, test, true); +} + } // namespace } // namespace opt } // namespace spvtools From a8afbe941a1cf442dd3de3d474b1680a72fc17be Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 2 Feb 2024 21:19:05 +0000 Subject: [PATCH 367/523] roll deps (#5550) * Roll external/googletest/ 6a5938233..456574145 (5 commits) https://github.com/google/googletest/compare/6a5938233b65...456574145cf7 $ git log 6a5938233..456574145 --date=short --no-merges --format='%ad %ae %s' 2024-01-31 absl-team Modifications to improve portability of googletest tests. 2024-01-30 absl-team Do not emit stack traces for messages generated by SUCCEED() 2024-01-23 sxshx818 Docs: Add mention of `gtest_recreate_environments_when_repeating` 2024-01-12 sxshx818 Docs: add conditions for calling SetUp and TearDown() 2023-12-29 sxshx818 Docs: add conditions for calling TearDown() Created with: roll-dep external/googletest * Roll external/re2/ 826ad10e5..283636ffb (6 commits) https://github.com/google/re2/compare/826ad10e58a0...283636ffb2bc $ git log 826ad10e5..283636ffb --date=short --no-merges --format='%ad %ae %s' 2024-01-31 junyer Build and deploy to GitHub Pages from GitHub Actions. 2024-01-30 junyer Try using larger runners for macOS. 2024-01-30 junyer Add support for macOS 14. 2024-01-30 junyer Prepare to tag release `2024-02-01`. 2024-01-29 junyer Drop `manylinux2014` from the build matrix. 2024-01-29 junyer Bump versions of actions to address warnings. 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 e639859b39..d2141f450a 100644 --- a/DEPS +++ b/DEPS @@ -7,12 +7,12 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '6a5938233b6519ba99ddb7c7314d45d3fa877969', + 'googletest_revision': '456574145cf71a5375777cab58453acfd92a920b', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '826ad10e58a042faf57d7c329b0fd0a04b797e0b', + 're2_revision': '283636ffb2bc11ad2663deec732a9f1d34cbe41d', 'spirv_headers_revision': '1c9115b562bab79ee2160fbd845f41b815b9f21f', } From 6c11c2bd46dba5b68bf62fc7d1195ebc7aa3694a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 3 Feb 2024 06:21:01 +0000 Subject: [PATCH 368/523] Roll external/re2/ 283636ffb..ab7c5918b (2 commits) (#5555) https://github.com/google/re2/compare/283636ffb2bc...ab7c5918b418 $ git log 283636ffb..ab7c5918b --date=short --no-merges --format='%ad %ae %s' 2024-02-02 junyer Address a warning from `pypa/gh-action-pypi-publish`. 2024-02-02 junyer Update to `bazelbuild/setup-bazelisk@v3`. 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 d2141f450a..b8a40e7541 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': '283636ffb2bc11ad2663deec732a9f1d34cbe41d', + 're2_revision': 'ab7c5918b418428ed17dbe564e0d8402bd7d743d', 'spirv_headers_revision': '1c9115b562bab79ee2160fbd845f41b815b9f21f', } From ab59dc6087325452267d7b96329a045e7687f62c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 6 Feb 2024 12:12:00 +0100 Subject: [PATCH 369/523] opt: prevent meld to merge block with MaximalReconvergence (#5557) The extension SPV_KHR_maximal_reconvergence adds more constraints around the merge blocks, and how the control flow can be altered. The one we address here is explained in the following part of the spec: Note: This means that the instructions in a break block will execute as if they were still diverged according to the loop iteration. This restricts potential transformations an implementation may perform on the IR to match shader author expectations. Similarly, instructions in the loop construct cannot be moved into the continue construct unless it can be proven that invocations are always converged. Until the optimizer is clever enough to determine if the invocation have already converged, we shall not meld a block which branches to a merge block into it, as it might move some instructions outside of the convergence region. This behavior being only required with the extension, this commit behavior change is gated by the extension. This means using wave operations without the maximal reconvergence extension might lead to undefined behaviors. Co-authored-by: Natalie Chouinard --- source/opt/block_merge_util.cpp | 11 +++ test/opt/block_merge_test.cpp | 142 ++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) diff --git a/source/opt/block_merge_util.cpp b/source/opt/block_merge_util.cpp index fe23e36f90..42f695f235 100644 --- a/source/opt/block_merge_util.cpp +++ b/source/opt/block_merge_util.cpp @@ -98,6 +98,17 @@ bool CanMergeWithSuccessor(IRContext* context, BasicBlock* block) { return false; } + // Note: This means that the instructions in a break block will execute as if + // they were still diverged according to the loop iteration. This restricts + // potential transformations an implementation may perform on the IR to match + // shader author expectations. Similarly, instructions in the loop construct + // cannot be moved into the continue construct unless it can be proven that + // invocations are always converged. + if (succ_is_merge && context->get_feature_mgr()->HasExtension( + kSPV_KHR_maximal_reconvergence)) { + return false; + } + if (pred_is_merge && IsContinue(context, lab_id)) { // Cannot merge a continue target with a merge block. return false; diff --git a/test/opt/block_merge_test.cpp b/test/opt/block_merge_test.cpp index 57c5061fd3..331ce3a7ae 100644 --- a/test/opt/block_merge_test.cpp +++ b/test/opt/block_merge_test.cpp @@ -1320,6 +1320,148 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } +TEST_F(BlockMergeTest, MaximalReconvergenceNoMeldToMerge) { + const std::string text = R"( + OpCapability Shader + OpCapability GroupNonUniformBallot + OpCapability GroupNonUniformArithmetic + OpExtension "SPV_KHR_maximal_reconvergence" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID %output + OpExecutionMode %main LocalSize 1 1 1 + OpExecutionMode %main MaximallyReconvergesKHR + OpSource HLSL 660 + OpName %type_RWStructuredBuffer_uint "type.RWStructuredBuffer.uint" + OpName %output "output" + OpName %main "main" + OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId + OpDecorate %output DescriptorSet 0 + OpDecorate %output Binding 0 + OpDecorate %_runtimearr_uint ArrayStride 4 + OpMemberDecorate %type_RWStructuredBuffer_uint 0 Offset 0 + OpDecorate %type_RWStructuredBuffer_uint Block + %uint = OpTypeInt 32 0 + %bool = OpTypeBool + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %_runtimearr_uint = OpTypeRuntimeArray %uint + %type_RWStructuredBuffer_uint = OpTypeStruct %_runtimearr_uint + %_ptr_StorageBuffer_type_RWStructuredBuffer_uint = OpTypePointer StorageBuffer %type_RWStructuredBuffer_uint + %v3uint = OpTypeVector %uint 3 + %_ptr_Input_v3uint = OpTypePointer Input %v3uint + %void = OpTypeVoid + %15 = OpTypeFunction %void + %uint_3 = OpConstant %uint 3 + %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint + %output = OpVariable %_ptr_StorageBuffer_type_RWStructuredBuffer_uint StorageBuffer + %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input + %main = OpFunction %void None %15 + %18 = OpLabel + %19 = OpLoad %v3uint %gl_GlobalInvocationID + OpBranch %20 + %20 = OpLabel + OpLoopMerge %21 %22 None +; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] + OpBranch %23 + %23 = OpLabel + %24 = OpCompositeExtract %uint %19 0 + %25 = OpGroupNonUniformBroadcastFirst %uint %uint_3 %24 + %26 = OpIEqual %bool %24 %25 + OpSelectionMerge %27 None + OpBranchConditional %26 %28 %27 + %28 = OpLabel + %29 = OpGroupNonUniformIAdd %int %uint_3 Reduce %int_1 + %30 = OpBitcast %uint %29 + OpBranch %21 +; CHECK: [[t1:%\w+]] = OpGroupNonUniformIAdd %int %uint_3 Reduce %int_1 +; CHECK-NEXT: [[t2:%\w+]] = OpBitcast %uint [[t1]] +; CHECK-NEXT: OpBranch [[merge]] + %27 = OpLabel + OpBranch %22 + %22 = OpLabel + OpBranch %20 + %21 = OpLabel + %31 = OpAccessChain %_ptr_StorageBuffer_uint %output %int_0 %24 + OpStore %31 %30 + OpReturn + OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_VULKAN_1_3); + SinglePassRunAndMatch(text, true); +} + +TEST_F(BlockMergeTest, NoMaximalReconvergenceMeldToMerge) { + const std::string text = R"( + OpCapability Shader + OpCapability GroupNonUniformBallot + OpCapability GroupNonUniformArithmetic + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID %output + OpExecutionMode %main LocalSize 1 1 1 + OpSource HLSL 660 + OpName %type_RWStructuredBuffer_uint "type.RWStructuredBuffer.uint" + OpName %output "output" + OpName %main "main" + OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId + OpDecorate %output DescriptorSet 0 + OpDecorate %output Binding 0 + OpDecorate %_runtimearr_uint ArrayStride 4 + OpMemberDecorate %type_RWStructuredBuffer_uint 0 Offset 0 + OpDecorate %type_RWStructuredBuffer_uint Block + %uint = OpTypeInt 32 0 + %bool = OpTypeBool + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %_runtimearr_uint = OpTypeRuntimeArray %uint + %type_RWStructuredBuffer_uint = OpTypeStruct %_runtimearr_uint + %_ptr_StorageBuffer_type_RWStructuredBuffer_uint = OpTypePointer StorageBuffer %type_RWStructuredBuffer_uint + %v3uint = OpTypeVector %uint 3 + %_ptr_Input_v3uint = OpTypePointer Input %v3uint + %void = OpTypeVoid + %15 = OpTypeFunction %void + %uint_3 = OpConstant %uint 3 + %_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint + %output = OpVariable %_ptr_StorageBuffer_type_RWStructuredBuffer_uint StorageBuffer + %gl_GlobalInvocationID = OpVariable %_ptr_Input_v3uint Input + %main = OpFunction %void None %15 + %18 = OpLabel + %19 = OpLoad %v3uint %gl_GlobalInvocationID + OpBranch %20 + %20 = OpLabel + OpLoopMerge %21 %22 None +; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] + OpBranch %23 + %23 = OpLabel + %24 = OpCompositeExtract %uint %19 0 + %25 = OpGroupNonUniformBroadcastFirst %uint %uint_3 %24 + %26 = OpIEqual %bool %24 %25 + OpSelectionMerge %27 None + OpBranchConditional %26 %28 %27 + %28 = OpLabel + %29 = OpGroupNonUniformIAdd %int %uint_3 Reduce %int_1 + %30 = OpBitcast %uint %29 + OpBranch %21 +; CHECK: [[merge]] = OpLabel +; CHECK-NEXT: [[t1:%\w+]] = OpGroupNonUniformIAdd %int %uint_3 Reduce %int_1 +; CHECK-NEXT: [[t2:%\w+]] = OpBitcast %uint [[t1]] + %27 = OpLabel + OpBranch %22 + %22 = OpLabel + OpBranch %20 + %21 = OpLabel + %31 = OpAccessChain %_ptr_StorageBuffer_uint %output %int_0 %24 + OpStore %31 %30 + OpReturn + OpFunctionEnd +)"; + + SetTargetEnv(SPV_ENV_VULKAN_1_3); + SinglePassRunAndMatch(text, true); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // // More complex control flow From 9938f5bc2e8172cc1f5b8e43d00eb130a4362e21 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 18:00:14 +0000 Subject: [PATCH 370/523] Roll external/googletest/ 456574145..48729681a (1 commit) (#5559) https://github.com/google/googletest/compare/456574145cf7...48729681ad88 $ git log 456574145..48729681a --date=short --no-merges --format='%ad %ae %s' 2024-01-31 112332952+kaswhy Add myself to Contributors 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 b8a40e7541..20328ca380 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '456574145cf71a5375777cab58453acfd92a920b', + 'googletest_revision': '48729681ad88a89061344ee541b4548833077e00', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From 032c15aaf5af611f4ce868d8dab21e8cc9ba02e5 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Tue, 6 Feb 2024 13:05:05 -0500 Subject: [PATCH 371/523] [NFC] Refactor code to fold instruction in fold tests. (#5558) We repeat basically the same code multiple times in the different types of folding tests. This commit adds a function that builds the module, finds the instruction to fold, and folds it. Doing the routine checks at the same time. We also have a couple generic functions for checking that an instruction is a constant with the expected value. --- test/opt/fold_test.cpp | 654 ++++++++++++++++------------------------- 1 file changed, 247 insertions(+), 407 deletions(-) diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index a837597a55..d1a81dff32 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include "effcee/effcee.h" @@ -67,44 +66,134 @@ struct InstructionFoldingCase { ResultType expected_result; }; -using IntegerInstructionFoldingTest = - ::testing::TestWithParam>; - -TEST_P(IntegerInstructionFoldingTest, Case) { - const auto& tc = GetParam(); - +std::tuple, Instruction*> GetInstructionToFold( + const std::string test_body, const uint32_t id_to_fold, + spv_target_env spv_env) { // Build module. std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, + BuildModule(spv_env, nullptr, test_body, SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); + EXPECT_NE(nullptr, context); + if (context == nullptr) { + return {nullptr, nullptr}; + } // Fold the instruction to test. - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); + if (id_to_fold != 0) { + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + Instruction* inst = def_use_mgr->GetDef(id_to_fold); + return {std::move(context), inst}; + } + + // If there is not ID, we get the instruction just before a terminator + // instruction. That could be a return or abort. This is used for cases where + // the instruction we want to fold does not have a result id. + Function* func = &*context->module()->begin(); + for (auto& bb : *func) { + Instruction* terminator = bb.terminator(); + if (terminator->IsReturnOrAbort()) { + return {std::move(context), terminator->PreviousNode()}; + } + } + return {nullptr, nullptr}; +} + +std::tuple, Instruction*> FoldInstruction( + const std::string test_body, const uint32_t id_to_fold, + spv_target_env spv_env) { + // Build module. + std::unique_ptr context; + Instruction* inst = nullptr; + std::tie(context, inst) = + GetInstructionToFold(test_body, id_to_fold, spv_env); + + std::unique_ptr original_inst(inst->Clone(context.get())); bool succeeded = context->get_instruction_folder().FoldInstruction(inst); + EXPECT_EQ(inst->result_id(), original_inst->result_id()); + EXPECT_EQ(inst->type_id(), original_inst->type_id()); - // Make sure the instruction folded as expected. - EXPECT_TRUE(succeeded); - if (inst != nullptr) { - EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); + if (!succeeded && inst != nullptr) { + EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands()); + for (uint32_t i = 0; i < inst->NumInOperands(); ++i) { + EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i)); + } + } + + return {std::move(context), succeeded ? inst : nullptr}; +} + +template +void CheckForExpectedScalarConstant(Instruction* inst, + ElementType expected_result, + Function GetValue) { + ASSERT_TRUE(inst); + + IRContext* context = inst->context(); + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + while (inst->opcode() == spv::Op::OpCopyObject) { inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); - EXPECT_EQ(inst->opcode(), spv::Op::OpConstant); - analysis::ConstantManager* const_mrg = context->get_constant_mgr(); - const analysis::Constant* constant = const_mrg->GetConstantFromInst(inst); - // We expect to see either integer types or 16-bit float types here. - EXPECT_TRUE((constant->AsIntConstant() != nullptr) || - ((constant->AsFloatConstant() != nullptr) && - (constant->type()->AsFloat()->width() == 16))); - const analysis::ScalarConstant* result = - const_mrg->GetConstantFromInst(inst)->AsScalarConstant(); - EXPECT_NE(result, nullptr); - if (result != nullptr) { - EXPECT_EQ(result->GetU32BitValue(), tc.expected_result); + } + + // Make sure we have a constant. + analysis::ConstantManager* const_mrg = context->get_constant_mgr(); + const analysis::Constant* constant = const_mrg->GetConstantFromInst(inst); + ASSERT_TRUE(constant); + + // Make sure the constant is a scalar. + const analysis::ScalarConstant* result = constant->AsScalarConstant(); + ASSERT_TRUE(result); + + // Check if the result matches the expected value. + // If ExpectedType is not a float type, it should cast the value to a double + // and never get a nan. + if (!std::isnan(static_cast(expected_result))) { + EXPECT_EQ(expected_result, GetValue(result)); + } else { + EXPECT_TRUE(std::isnan(static_cast(GetValue(result)))); + } +} + +template +void CheckForExpectedVectorConstant(Instruction* inst, + std::vector expected_result, + Function GetValue) { + ASSERT_TRUE(inst); + + IRContext* context = inst->context(); + EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); + inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); + std::vector opcodes = {spv::Op::OpConstantComposite}; + EXPECT_THAT(opcodes, Contains(inst->opcode())); + analysis::ConstantManager* const_mrg = context->get_constant_mgr(); + const analysis::Constant* result = const_mrg->GetConstantFromInst(inst); + EXPECT_NE(result, nullptr); + if (result != nullptr) { + const std::vector& componenets = + result->AsVectorConstant()->GetComponents(); + EXPECT_EQ(componenets.size(), expected_result.size()); + for (size_t i = 0; i < componenets.size(); i++) { + EXPECT_EQ(expected_result[i], GetValue(componenets[i])); } } } +using IntegerInstructionFoldingTest = + ::testing::TestWithParam>; + +TEST_P(IntegerInstructionFoldingTest, Case) { + const auto& tc = GetParam(); + + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = + FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1); + CheckForExpectedScalarConstant( + inst, tc.expected_result, [](const analysis::Constant* c) { + return c->AsScalarConstant()->GetU32BitValue(); + }); +} + // Returns a common SPIR-V header for all of the test that follow. #define INT_0_ID 100 #define TRUE_ID 101 @@ -937,37 +1026,13 @@ using UIntVectorInstructionFoldingTest = TEST_P(UIntVectorInstructionFoldingTest, Case) { const auto& tc = GetParam(); - // Build module. - std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); - - // Fold the instruction to test. - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); - spv::Op original_opcode = inst->opcode(); - bool succeeded = context->get_instruction_folder().FoldInstruction(inst); - - // Make sure the instruction folded as expected. - EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode); - if (succeeded && inst != nullptr) { - EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); - inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); - std::vector opcodes = {spv::Op::OpConstantComposite}; - EXPECT_THAT(opcodes, Contains(inst->opcode())); - analysis::ConstantManager* const_mrg = context->get_constant_mgr(); - const analysis::Constant* result = const_mrg->GetConstantFromInst(inst); - EXPECT_NE(result, nullptr); - if (result != nullptr) { - const std::vector& componenets = - result->AsVectorConstant()->GetComponents(); - EXPECT_EQ(componenets.size(), tc.expected_result.size()); - for (size_t i = 0; i < componenets.size(); i++) { - EXPECT_EQ(tc.expected_result[i], componenets[i]->GetU32()); - } - } - } + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = + FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1); + CheckForExpectedVectorConstant( + inst, tc.expected_result, + [](const analysis::Constant* c) { return c->GetU32(); }); } // clang-format off @@ -992,24 +1057,6 @@ ::testing::Values( "OpReturn\n" + "OpFunctionEnd", 2, {0,3}), - InstructionFoldingCase>( - Header() + "%main = OpFunction %void None %void_func\n" + - "%main_lab = OpLabel\n" + - "%n = OpVariable %_ptr_int Function\n" + - "%load = OpLoad %int %n\n" + - "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 4294967295 3\n" + - "OpReturn\n" + - "OpFunctionEnd", - 2, {0,0}), - InstructionFoldingCase>( - Header() + "%main = OpFunction %void None %void_func\n" + - "%main_lab = OpLabel\n" + - "%n = OpVariable %_ptr_int Function\n" + - "%load = OpLoad %int %n\n" + - "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 4294967295 \n" + - "OpReturn\n" + - "OpFunctionEnd", - 2, {0,0}), // Test case 4: fold bit-cast int -24 to unsigned int InstructionFoldingCase>( Header() + "%main = OpFunction %void None %void_func\n" + @@ -1047,36 +1094,14 @@ using IntVectorInstructionFoldingTest = TEST_P(IntVectorInstructionFoldingTest, Case) { const auto& tc = GetParam(); - // Build module. - std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); - - // Fold the instruction to test. - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); - bool succeeded = context->get_instruction_folder().FoldInstruction(inst); + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = + FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1); - // Make sure the instruction folded as expected. - EXPECT_TRUE(succeeded); - if (succeeded && inst != nullptr) { - EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); - inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); - std::vector opcodes = {spv::Op::OpConstantComposite}; - EXPECT_THAT(opcodes, Contains(inst->opcode())); - analysis::ConstantManager* const_mrg = context->get_constant_mgr(); - const analysis::Constant* result = const_mrg->GetConstantFromInst(inst); - EXPECT_NE(result, nullptr); - if (result != nullptr) { - const std::vector& componenets = - result->AsVectorConstant()->GetComponents(); - EXPECT_EQ(componenets.size(), tc.expected_result.size()); - for (size_t i = 0; i < componenets.size(); i++) { - EXPECT_EQ(tc.expected_result[i], componenets[i]->GetS32()); - } - } - } + CheckForExpectedVectorConstant( + inst, tc.expected_result, + [](const analysis::Constant* c) { return c->GetS32(); }); } // clang-format off @@ -1123,36 +1148,13 @@ using DoubleVectorInstructionFoldingTest = TEST_P(DoubleVectorInstructionFoldingTest, Case) { const auto& tc = GetParam(); - // Build module. - std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); - - // Fold the instruction to test. - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); - bool succeeded = context->get_instruction_folder().FoldInstruction(inst); - - // Make sure the instruction folded as expected. - EXPECT_TRUE(succeeded); - if (succeeded && inst != nullptr) { - EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); - inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); - std::vector opcodes = {spv::Op::OpConstantComposite}; - EXPECT_THAT(opcodes, Contains(inst->opcode())); - analysis::ConstantManager* const_mrg = context->get_constant_mgr(); - const analysis::Constant* result = const_mrg->GetConstantFromInst(inst); - EXPECT_NE(result, nullptr); - if (result != nullptr) { - const std::vector& componenets = - result->AsVectorConstant()->GetComponents(); - EXPECT_EQ(componenets.size(), tc.expected_result.size()); - for (size_t i = 0; i < componenets.size(); i++) { - EXPECT_EQ(tc.expected_result[i], componenets[i]->GetDouble()); - } - } - } + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = + FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1); + CheckForExpectedVectorConstant( + inst, tc.expected_result, + [](const analysis::Constant* c) { return c->GetDouble(); }); } // clang-format off @@ -1247,37 +1249,10 @@ using FloatVectorInstructionFoldingTest = TEST_P(FloatVectorInstructionFoldingTest, Case) { const auto& tc = GetParam(); - // Build module. - std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); - - // Fold the instruction to test. - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); - spv::Op original_opcode = inst->opcode(); - bool succeeded = context->get_instruction_folder().FoldInstruction(inst); - - // Make sure the instruction folded as expected. - EXPECT_EQ(succeeded, inst == nullptr || inst->opcode() != original_opcode); - if (succeeded && inst != nullptr) { - EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); - inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); - std::vector opcodes = {spv::Op::OpConstantComposite}; - EXPECT_THAT(opcodes, Contains(inst->opcode())); - analysis::ConstantManager* const_mrg = context->get_constant_mgr(); - const analysis::Constant* result = const_mrg->GetConstantFromInst(inst); - EXPECT_NE(result, nullptr); - if (result != nullptr) { - const std::vector& componenets = - result->AsVectorConstant()->GetComponents(); - EXPECT_EQ(componenets.size(), tc.expected_result.size()); - for (size_t i = 0; i < componenets.size(); i++) { - EXPECT_EQ(tc.expected_result[i], componenets[i]->GetFloat()); - } - } - } + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = FoldInstruction(tc.test_body, tc.id_to_fold,SPV_ENV_UNIVERSAL_1_1); + CheckForExpectedVectorConstant(inst, tc.expected_result, [](const analysis::Constant* c){ return c->GetFloat();}); } // clang-format off @@ -1389,22 +1364,14 @@ using FloatMatrixInstructionFoldingTest = ::testing::TestWithParam< TEST_P(FloatMatrixInstructionFoldingTest, Case) { const auto& tc = GetParam(); - // Build module. - std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); - - // Fold the instruction to test. - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); - bool succeeded = context->get_instruction_folder().FoldInstruction(inst); + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = + FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1); - // Make sure the instruction folded as expected. - EXPECT_TRUE(succeeded); EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); - if (inst->opcode() == spv::Op::OpCopyObject) { + analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); analysis::ConstantManager* const_mgr = context->get_constant_mgr(); const analysis::Constant* result = const_mgr->GetConstantFromInst(inst); @@ -1466,33 +1433,13 @@ using BooleanInstructionFoldingTest = TEST_P(BooleanInstructionFoldingTest, Case) { const auto& tc = GetParam(); - // Build module. - std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); - - // Fold the instruction to test. - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); - bool succeeded = context->get_instruction_folder().FoldInstruction(inst); - - // Make sure the instruction folded as expected. - EXPECT_TRUE(succeeded); - if (inst != nullptr) { - EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); - inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); - std::vector bool_opcodes = {spv::Op::OpConstantTrue, - spv::Op::OpConstantFalse}; - EXPECT_THAT(bool_opcodes, Contains(inst->opcode())); - analysis::ConstantManager* const_mrg = context->get_constant_mgr(); - const analysis::BoolConstant* result = - const_mrg->GetConstantFromInst(inst)->AsBoolConstant(); - EXPECT_NE(result, nullptr); - if (result != nullptr) { - EXPECT_EQ(result->value(), tc.expected_result); - } - } + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = + FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1); + CheckForExpectedScalarConstant( + inst, tc.expected_result, + [](const analysis::Constant* c) { return c->AsBoolConstant()->value(); }); } // clang-format off @@ -2078,35 +2025,15 @@ using FloatInstructionFoldingTest = TEST_P(FloatInstructionFoldingTest, Case) { const auto& tc = GetParam(); - // Build module. - std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); - - // Fold the instruction to test. - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); - bool succeeded = context->get_instruction_folder().FoldInstruction(inst); + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = + FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1); - // Make sure the instruction folded as expected. - EXPECT_TRUE(succeeded); - if (inst != nullptr) { - EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); - inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); - EXPECT_EQ(inst->opcode(), spv::Op::OpConstant); - analysis::ConstantManager* const_mrg = context->get_constant_mgr(); - const analysis::FloatConstant* result = - const_mrg->GetConstantFromInst(inst)->AsFloatConstant(); - EXPECT_NE(result, nullptr); - if (result != nullptr) { - if (!std::isnan(tc.expected_result)) { - EXPECT_EQ(result->GetFloatValue(), tc.expected_result); - } else { - EXPECT_TRUE(std::isnan(result->GetFloatValue())); - } - } - } + CheckForExpectedScalarConstant(inst, tc.expected_result, + [](const analysis::Constant* c) { + return c->AsFloatConstant()->GetFloatValue(); + }); } // Not testing NaNs because there are no expectations concerning NaNs according @@ -2511,35 +2438,14 @@ using DoubleInstructionFoldingTest = TEST_P(DoubleInstructionFoldingTest, Case) { const auto& tc = GetParam(); - // Build module. - std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); - - // Fold the instruction to test. - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); - bool succeeded = context->get_instruction_folder().FoldInstruction(inst); - - // Make sure the instruction folded as expected. - EXPECT_TRUE(succeeded); - if (inst != nullptr) { - EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); - inst = def_use_mgr->GetDef(inst->GetSingleWordInOperand(0)); - EXPECT_EQ(inst->opcode(), spv::Op::OpConstant); - analysis::ConstantManager* const_mrg = context->get_constant_mgr(); - const analysis::FloatConstant* result = - const_mrg->GetConstantFromInst(inst)->AsFloatConstant(); - EXPECT_NE(result, nullptr); - if (result != nullptr) { - if (!std::isnan(tc.expected_result)) { - EXPECT_EQ(result->GetDoubleValue(), tc.expected_result); - } else { - EXPECT_TRUE(std::isnan(result->GetDoubleValue())); - } - } - } + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = + FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1); + CheckForExpectedScalarConstant( + inst, tc.expected_result, [](const analysis::Constant* c) { + return c->AsFloatConstant()->GetDoubleValue(); + }); } // clang-format off @@ -3397,32 +3303,22 @@ using IntegerInstructionFoldingTestWithMap = TEST_P(IntegerInstructionFoldingTestWithMap, Case) { const auto& tc = GetParam(); - // Build module. - std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = + GetInstructionToFold(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_5); - // Fold the instruction to test. - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); inst = context->get_instruction_folder().FoldInstructionToConstant(inst, tc.id_map); - - // Make sure the instruction folded as expected. EXPECT_NE(inst, nullptr); - if (inst != nullptr) { - EXPECT_EQ(inst->opcode(), spv::Op::OpConstant); - analysis::ConstantManager* const_mrg = context->get_constant_mgr(); - const analysis::IntConstant* result = - const_mrg->GetConstantFromInst(inst)->AsIntConstant(); - EXPECT_NE(result, nullptr); - if (result != nullptr) { - EXPECT_EQ(result->GetU32BitValue(), tc.expected_result); - } - } + + CheckForExpectedScalarConstant(inst, tc.expected_result, + [](const analysis::Constant* c) { + return c->AsIntConstant()->GetU32BitValue(); + }); } // clang-format off + INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTestWithMap, ::testing::Values( // Test case 0: fold %3 = 0; %3 * n @@ -3445,32 +3341,16 @@ using BooleanInstructionFoldingTestWithMap = TEST_P(BooleanInstructionFoldingTestWithMap, Case) { const auto& tc = GetParam(); - // Build module. - std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); - - // Fold the instruction to test. - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = + GetInstructionToFold(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_5); inst = context->get_instruction_folder().FoldInstructionToConstant(inst, tc.id_map); - - // Make sure the instruction folded as expected. - EXPECT_NE(inst, nullptr); - if (inst != nullptr) { - std::vector bool_opcodes = {spv::Op::OpConstantTrue, - spv::Op::OpConstantFalse}; - EXPECT_THAT(bool_opcodes, Contains(inst->opcode())); - analysis::ConstantManager* const_mrg = context->get_constant_mgr(); - const analysis::BoolConstant* result = - const_mrg->GetConstantFromInst(inst)->AsBoolConstant(); - EXPECT_NE(result, nullptr); - if (result != nullptr) { - EXPECT_EQ(result->value(), tc.expected_result); - } - } + ASSERT_NE(inst, nullptr); + CheckForExpectedScalarConstant( + inst, tc.expected_result, + [](const analysis::Constant* c) { return c->AsBoolConstant()->value(); }); } // clang-format off @@ -3496,30 +3376,15 @@ using GeneralInstructionFoldingTest = TEST_P(GeneralInstructionFoldingTest, Case) { const auto& tc = GetParam(); - // Build module. - std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); - - // Fold the instruction to test. - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); - std::unique_ptr original_inst(inst->Clone(context.get())); - bool succeeded = context->get_instruction_folder().FoldInstruction(inst); + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = + FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1); - // Make sure the instruction folded as expected. - EXPECT_EQ(inst->result_id(), original_inst->result_id()); - EXPECT_EQ(inst->type_id(), original_inst->type_id()); - EXPECT_TRUE((!succeeded) == (tc.expected_result == 0)); - if (succeeded) { + EXPECT_TRUE((inst == nullptr) == (tc.expected_result == 0)); + if (inst != nullptr) { EXPECT_EQ(inst->opcode(), spv::Op::OpCopyObject); EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result); - } else { - EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands()); - for (uint32_t i = 0; i < inst->NumInOperands(); ++i) { - EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i)); - } } } @@ -4843,7 +4708,31 @@ INSTANTIATE_TEST_SUITE_P(IntegerRedundantFoldingTest, GeneralInstructionFoldingT "%2 = OpIAdd %v2int %v2int_0_0 %3\n" + "OpReturn\n" + "OpFunctionEnd", - 2, 3) + 2, 3), + // Test case 8: Don't fold because of undefined value. Using 4294967295 + // means that entry is undefined. We do not expect it to ever happen, so + // not worth folding. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 4294967295 3\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 9: Don't fold because of undefined value. Using 4294967295 + // means that entry is undefined. We do not expect it to ever happen, so + // not worth folding. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpVectorShuffle %v2int %v2int_null %v2int_2_3 0 4294967295 \n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0) )); INSTANTIATE_TEST_SUITE_P(ClampAndCmpLHS, GeneralInstructionFoldingTest, @@ -5165,30 +5054,15 @@ using ToNegateFoldingTest = TEST_P(ToNegateFoldingTest, Case) { const auto& tc = GetParam(); - // Build module. - std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = + FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1); - // Fold the instruction to test. - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); - std::unique_ptr original_inst(inst->Clone(context.get())); - bool succeeded = context->get_instruction_folder().FoldInstruction(inst); - - // Make sure the instruction folded as expected. - EXPECT_EQ(inst->result_id(), original_inst->result_id()); - EXPECT_EQ(inst->type_id(), original_inst->type_id()); - EXPECT_TRUE((!succeeded) == (tc.expected_result == 0)); - if (succeeded) { + EXPECT_TRUE((inst == nullptr) == (tc.expected_result == 0)); + if (inst != nullptr) { EXPECT_EQ(inst->opcode(), spv::Op::OpFNegate); EXPECT_EQ(inst->GetSingleWordInOperand(0), tc.expected_result); - } else { - EXPECT_EQ(inst->NumInOperands(), original_inst->NumInOperands()); - for (uint32_t i = 0; i < inst->NumInOperands(); ++i) { - EXPECT_EQ(inst->GetOperand(i), original_inst->GetOperand(i)); - } } } @@ -5287,19 +5161,12 @@ using MatchingInstructionFoldingTest = TEST_P(MatchingInstructionFoldingTest, Case) { const auto& tc = GetParam(); - // Build module. - std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = FoldInstruction(tc.test_body, tc.id_to_fold,SPV_ENV_UNIVERSAL_1_1); - // Fold the instruction to test. - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); - std::unique_ptr original_inst(inst->Clone(context.get())); - bool succeeded = context->get_instruction_folder().FoldInstruction(inst); - EXPECT_EQ(succeeded, tc.expected_result); - if (succeeded) { + EXPECT_EQ(inst != nullptr, tc.expected_result); + if (inst != nullptr) { Match(tc.test_body, context.get()); } } @@ -8046,27 +7913,13 @@ ::testing::TestWithParam>; TEST_P(MatchingInstructionWithNoResultFoldingTest, Case) { const auto& tc = GetParam(); - // Build module. - std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = FoldInstruction(tc.test_body, tc.id_to_fold,SPV_ENV_UNIVERSAL_1_1); - // Fold the instruction to test. - Instruction* inst = nullptr; - Function* func = &*context->module()->begin(); - for (auto& bb : *func) { - Instruction* terminator = bb.terminator(); - if (terminator->IsReturnOrAbort()) { - inst = terminator->PreviousNode(); - break; - } - } - assert(inst && "Invalid test. Could not find instruction to fold."); - std::unique_ptr original_inst(inst->Clone(context.get())); - bool succeeded = context->get_instruction_folder().FoldInstruction(inst); - EXPECT_EQ(succeeded, tc.expected_result); - if (succeeded) { + // Find the instruction to test. + EXPECT_EQ(inst != nullptr, tc.expected_result); + if (inst != nullptr) { Match(tc.test_body, context.get()); } } @@ -8406,8 +8259,9 @@ TEST_P(EntryPointFoldingTest, Case) { SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); ASSERT_NE(nullptr, context); - // Fold the instruction to test. + // Find the first entry point. That is the instruction we want to fold. Instruction* inst = nullptr; + ASSERT_FALSE(context->module()->entry_points().empty()); inst = &*context->module()->entry_points().begin(); assert(inst && "Invalid test. Could not find entry point instruction to fold."); std::unique_ptr original_inst(inst->Clone(context.get())); @@ -8500,19 +8354,12 @@ ::testing::TestWithParam>; TEST_P(SPV14FoldingTest, Case) { const auto& tc = GetParam(); - // Build module. - std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_4, nullptr, tc.test_body, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = FoldInstruction(tc.test_body, tc.id_to_fold,SPV_ENV_UNIVERSAL_1_4); - // Fold the instruction to test. - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); - std::unique_ptr original_inst(inst->Clone(context.get())); - bool succeeded = context->get_instruction_folder().FoldInstruction(inst); - EXPECT_EQ(succeeded, tc.expected_result); - if (succeeded) { + EXPECT_EQ(inst != nullptr, tc.expected_result); + if (inst != nullptr) { Match(tc.test_body, context.get()); } } @@ -8613,19 +8460,12 @@ ::testing::TestWithParam>; TEST_P(FloatControlsFoldingTest, Case) { const auto& tc = GetParam(); - // Build module. - std::unique_ptr context = - BuildModule(SPV_ENV_UNIVERSAL_1_4, nullptr, tc.test_body, - SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ASSERT_NE(nullptr, context); + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_4); - // Fold the instruction to test. - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - Instruction* inst = def_use_mgr->GetDef(tc.id_to_fold); - std::unique_ptr original_inst(inst->Clone(context.get())); - bool succeeded = context->get_instruction_folder().FoldInstruction(inst); - EXPECT_EQ(succeeded, tc.expected_result); - if (succeeded) { + EXPECT_EQ(inst != nullptr, tc.expected_result); + if (inst != nullptr) { Match(tc.test_body, context.get()); } } From 7657cb1c698aa684cfb0546b97b5ff64626a5300 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Feb 2024 11:09:41 -0800 Subject: [PATCH 372/523] build(deps): bump the github-actions group with 3 updates (#5560) Bumps the github-actions group with 3 updates: [lukka/get-cmake](https://github.com/lukka/get-cmake), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [github/codeql-action](https://github.com/github/codeql-action). Updates `lukka/get-cmake` from 3.28.1 to 3.28.2 - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/2654d8ee382b9b6cbbfe6487653b8629b4e062c8...23a189c2ed38ec264f5026ce2303e5b7a664345c) Updates `actions/upload-artifact` from 4.3.0 to 4.3.1 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/26f96dfa697d77e81fd5907df203aa23a56210a8...5d5d22a31266ced268874388b861e4b58bb5c2f3) Updates `github/codeql-action` from 3.23.2 to 3.24.0 - [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/b7bf0a3ed3ecfa44160715d7c442788f65f0f923...e8893c57a1f3a2b659b6b55564fdfdbbd2982911) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-type: direct:production update-type: version-update:semver-patch 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/ios.yml | 2 +- .github/workflows/scorecard.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 8b8cca918b..d3a7058a19 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@2654d8ee382b9b6cbbfe6487653b8629b4e062c8 # v3.28.1 + - uses: lukka/get-cmake@23a189c2ed38ec264f5026ce2303e5b7a664345c # v3.28.2 - name: Download dependencies run: python3 utils/git-sync-deps # NOTE: The MacOS SDK ships universal binaries. CI should reflect this. diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 572491025d..f952197a9e 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -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@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0 + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 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@b7bf0a3ed3ecfa44160715d7c442788f65f0f923 # v3.23.2 + uses: github/codeql-action/upload-sarif@e8893c57a1f3a2b659b6b55564fdfdbbd2982911 # v3.24.0 with: sarif_file: results.sarif From 1a2cbabd8bbc4bbb45149f351871e36d94aeca64 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 7 Feb 2024 18:27:25 +0000 Subject: [PATCH 373/523] Roll external/googletest/ 48729681a..64be1c79f (1 commit) (#5563) https://github.com/google/googletest/compare/48729681ad88...64be1c79fa2c $ git log 48729681a..64be1c79f --date=short --no-merges --format='%ad %ae %s' 2024-02-06 absl-team Destroy installed environments in normal code, not in static teardown. 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 20328ca380..ed68a606d7 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '48729681ad88a89061344ee541b4548833077e00', + 'googletest_revision': '64be1c79fa2cea015d816687120878a110775351', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From 9a7b1af906e40b47b96e162a25c3faa04d78c39e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Feb 2024 14:15:04 -0500 Subject: [PATCH 374/523] build(deps): bump the github-actions group with 1 update (#5564) Bumps the github-actions group with 1 update: [lukka/get-cmake](https://github.com/lukka/get-cmake). Updates `lukka/get-cmake` from 3.28.2 to 3.28.3 - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/23a189c2ed38ec264f5026ce2303e5b7a664345c...139aae96315b496d9af1b5e9abe53b15ca7eece8) --- 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 d3a7058a19..70a0729e54 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@23a189c2ed38ec264f5026ce2303e5b7a664345c # v3.28.2 + - uses: lukka/get-cmake@139aae96315b496d9af1b5e9abe53b15ca7eece8 # v3.28.3 - name: Download dependencies run: python3 utils/git-sync-deps # NOTE: The MacOS SDK ships universal binaries. CI should reflect this. From 80926d97aba8d1b1162448713ca4825d4c816226 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 8 Feb 2024 19:47:36 +0000 Subject: [PATCH 375/523] roll deps (#5566) * Roll external/googletest/ 64be1c79f..b75ecf1be (2 commits) https://github.com/google/googletest/compare/64be1c79fa2c...b75ecf1bed2f $ git log 64be1c79f..b75ecf1be --date=short --no-merges --format='%ad %ae %s' 2024-02-07 kfm Switch rank structs to be consistent with written guidance in go/ranked-overloads 2024-02-07 absl-team Use _Exit instead of _exit in GoogleTest Created with: roll-dep external/googletest * Roll external/spirv-headers/ 1c9115b56..e77d03080 (1 commit) https://github.com/KhronosGroup/SPIRV-Headers/compare/1c9115b562ba...e77d03080b90 $ git log 1c9115b56..e77d03080 --date=short --no-merges --format='%ad %ae %s' 2024-02-07 gleese Update FPFastMath token reservation (#414) 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 ed68a606d7..2fbe251c1f 100644 --- a/DEPS +++ b/DEPS @@ -7,13 +7,13 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '64be1c79fa2cea015d816687120878a110775351', + 'googletest_revision': 'b75ecf1bed2fcd416b66c86cb6fe79122abf132e', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', 're2_revision': 'ab7c5918b418428ed17dbe564e0d8402bd7d743d', - 'spirv_headers_revision': '1c9115b562bab79ee2160fbd845f41b815b9f21f', + 'spirv_headers_revision': 'e77d03080b90c5d361663a67834c57bb1fddaec2', } deps = { From a8959dc653d71609ac5bbfd151ddd6da2b62e79b Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Fri, 9 Feb 2024 14:02:48 -0500 Subject: [PATCH 376/523] Fold 64-bit int operations (#5561) Adds folding rules that will fold basic artimetic for signed and unsigned integers of all sizes, including 64-bit. Also folds OpSConvert and OpUConvert. --- source/opt/const_folding_rules.cpp | 220 ++++++++++++++++++- test/opt/fold_test.cpp | 337 +++++++++++++++++++++++++++-- 2 files changed, 534 insertions(+), 23 deletions(-) diff --git a/source/opt/const_folding_rules.cpp b/source/opt/const_folding_rules.cpp index e676974c8c..79f34acd3c 100644 --- a/source/opt/const_folding_rules.cpp +++ b/source/opt/const_folding_rules.cpp @@ -21,6 +21,59 @@ namespace opt { namespace { constexpr uint32_t kExtractCompositeIdInIdx = 0; +// Returns the value obtained by extracting the |number_of_bits| least +// significant bits from |value|, and sign-extending it to 64-bits. +uint64_t SignExtendValue(uint64_t value, uint32_t number_of_bits) { + if (number_of_bits == 64) return value; + + uint64_t mask_for_sign_bit = 1ull << (number_of_bits - 1); + uint64_t mask_for_significant_bits = (mask_for_sign_bit << 1) - 1ull; + if (value & mask_for_sign_bit) { + // Set upper bits to 1 + value |= ~mask_for_significant_bits; + } else { + // Clear the upper bits + value &= mask_for_significant_bits; + } + return value; +} + +// Returns the value obtained by extracting the |number_of_bits| least +// significant bits from |value|, and zero-extending it to 64-bits. +uint64_t ZeroExtendValue(uint64_t value, uint32_t number_of_bits) { + if (number_of_bits == 64) return value; + + uint64_t mask_for_first_bit_to_clear = 1ull << (number_of_bits); + uint64_t mask_for_bits_to_keep = mask_for_first_bit_to_clear - 1; + value &= mask_for_bits_to_keep; + return value; +} + +// Returns a constant whose value is `value` and type is `type`. This constant +// will be generated by `const_mgr`. The type must be a scalar integer type. +const analysis::Constant* GenerateIntegerConstant( + const analysis::Integer* integer_type, uint64_t result, + analysis::ConstantManager* const_mgr) { + assert(integer_type != nullptr); + + std::vector words; + if (integer_type->width() == 64) { + // In the 64-bit case, two words are needed to represent the value. + words = {static_cast(result), + static_cast(result >> 32)}; + } else { + // In all other cases, only a single word is needed. + assert(integer_type->width() <= 32); + if (integer_type->IsSigned()) { + result = SignExtendValue(result, integer_type->width()); + } else { + result = ZeroExtendValue(result, integer_type->width()); + } + words = {static_cast(result)}; + } + return const_mgr->GetConstant(integer_type, words); +} + // Returns a constants with the value NaN of the given type. Only works for // 32-bit and 64-bit float point types. Returns |nullptr| if an error occurs. const analysis::Constant* GetNan(const analysis::Type* type, @@ -676,7 +729,6 @@ ConstantFoldingRule FoldUnaryOp(UnaryScalarFoldingRule scalar_rule) { return [scalar_rule](IRContext* context, Instruction* inst, const std::vector& constants) -> const analysis::Constant* { - analysis::ConstantManager* const_mgr = context->get_constant_mgr(); analysis::TypeManager* type_mgr = context->get_type_mgr(); const analysis::Type* result_type = type_mgr->GetType(inst->type_id()); @@ -716,6 +768,64 @@ ConstantFoldingRule FoldUnaryOp(UnaryScalarFoldingRule scalar_rule) { }; } +// Returns a |ConstantFoldingRule| that folds binary scalar ops +// using |scalar_rule| and binary vectors ops by applying +// |scalar_rule| to the elements of the vector. The folding rule assumes that op +// has two inputs. For regular instruction, those are in operands 0 and 1. For +// extended instruction, they are in operands 1 and 2. If an element in +// |constants| is not nullprt, then the constant's type is |Float|, |Integer|, +// or |Vector| whose element type is |Float| or |Integer|. +ConstantFoldingRule FoldBinaryOp(BinaryScalarFoldingRule scalar_rule) { + return [scalar_rule](IRContext* context, Instruction* inst, + const std::vector& constants) + -> const analysis::Constant* { + assert(constants.size() == inst->NumInOperands()); + assert(constants.size() == (inst->opcode() == spv::Op::OpExtInst ? 3 : 2)); + analysis::ConstantManager* const_mgr = context->get_constant_mgr(); + analysis::TypeManager* type_mgr = context->get_type_mgr(); + const analysis::Type* result_type = type_mgr->GetType(inst->type_id()); + const analysis::Vector* vector_type = result_type->AsVector(); + + const analysis::Constant* arg1 = + (inst->opcode() == spv::Op::OpExtInst) ? constants[1] : constants[0]; + const analysis::Constant* arg2 = + (inst->opcode() == spv::Op::OpExtInst) ? constants[2] : constants[1]; + + if (arg1 == nullptr || arg2 == nullptr) { + return nullptr; + } + + if (vector_type == nullptr) { + return scalar_rule(result_type, arg1, arg2, const_mgr); + } + + std::vector a_components; + std::vector b_components; + std::vector results_components; + + a_components = arg1->GetVectorComponents(const_mgr); + b_components = arg2->GetVectorComponents(const_mgr); + assert(a_components.size() == b_components.size()); + + // Fold each component of the vector. + for (uint32_t i = 0; i < a_components.size(); ++i) { + results_components.push_back(scalar_rule(vector_type->element_type(), + a_components[i], b_components[i], + const_mgr)); + if (results_components[i] == nullptr) { + return nullptr; + } + } + + // Build the constant object and return it. + std::vector ids; + for (const analysis::Constant* member : results_components) { + ids.push_back(const_mgr->GetDefiningInstruction(member)->result_id()); + } + return const_mgr->GetConstant(vector_type, ids); + }; +} + // Returns a |ConstantFoldingRule| that folds unary floating point scalar ops // using |scalar_rule| and unary float point vectors ops by applying // |scalar_rule| to the elements of the vector. The |ConstantFoldingRule| @@ -1587,6 +1697,72 @@ BinaryScalarFoldingRule FoldFTranscendentalBinary(double (*fp)(double, return nullptr; }; } + +enum Sign { Signed, Unsigned }; + +// Returns a BinaryScalarFoldingRule that applies `op` to the scalars. +// The `signedness` is used to determine if the operands should be interpreted +// as signed or unsigned. If the operands are signed, the value will be sign +// extended before the value is passed to `op`. Otherwise the values will be +// zero extended. +template +BinaryScalarFoldingRule FoldBinaryIntegerOperation(uint64_t (*op)(uint64_t, + uint64_t)) { + return + [op](const analysis::Type* result_type, const analysis::Constant* a, + const analysis::Constant* b, + analysis::ConstantManager* const_mgr) -> const analysis::Constant* { + assert(result_type != nullptr && a != nullptr && b != nullptr); + const analysis::Integer* integer_type = result_type->AsInteger(); + assert(integer_type != nullptr); + assert(integer_type == a->type()->AsInteger()); + assert(integer_type == b->type()->AsInteger()); + + // In SPIR-V, all operations support unsigned types, but the way they + // are interpreted depends on the opcode. This is why we use the + // template argument to determine how to interpret the operands. + uint64_t ia = (signedness == Signed ? a->GetSignExtendedValue() + : a->GetZeroExtendedValue()); + uint64_t ib = (signedness == Signed ? b->GetSignExtendedValue() + : b->GetZeroExtendedValue()); + uint64_t result = op(ia, ib); + + const analysis::Constant* result_constant = + GenerateIntegerConstant(integer_type, result, const_mgr); + return result_constant; + }; +} + +// A scalar folding rule that folds OpSConvert. +const analysis::Constant* FoldScalarSConvert( + const analysis::Type* result_type, const analysis::Constant* a, + analysis::ConstantManager* const_mgr) { + assert(result_type != nullptr); + assert(a != nullptr); + assert(const_mgr != nullptr); + const analysis::Integer* integer_type = result_type->AsInteger(); + assert(integer_type && "The result type of an SConvert"); + int64_t value = a->GetSignExtendedValue(); + return GenerateIntegerConstant(integer_type, value, const_mgr); +} + +// A scalar folding rule that folds OpUConvert. +const analysis::Constant* FoldScalarUConvert( + const analysis::Type* result_type, const analysis::Constant* a, + analysis::ConstantManager* const_mgr) { + assert(result_type != nullptr); + assert(a != nullptr); + assert(const_mgr != nullptr); + const analysis::Integer* integer_type = result_type->AsInteger(); + assert(integer_type && "The result type of an UConvert"); + uint64_t value = a->GetZeroExtendedValue(); + + // If the operand was an unsigned value with less than 32-bit, it would have + // been sign extended earlier, and we need to clear those bits. + auto* operand_type = a->type()->AsInteger(); + value = ZeroExtendValue(value, operand_type->width()); + return GenerateIntegerConstant(integer_type, value, const_mgr); +} } // namespace void ConstantFoldingRules::AddFoldingRules() { @@ -1604,6 +1780,8 @@ void ConstantFoldingRules::AddFoldingRules() { rules_[spv::Op::OpConvertFToU].push_back(FoldFToI()); rules_[spv::Op::OpConvertSToF].push_back(FoldIToF()); rules_[spv::Op::OpConvertUToF].push_back(FoldIToF()); + rules_[spv::Op::OpSConvert].push_back(FoldUnaryOp(FoldScalarSConvert)); + rules_[spv::Op::OpUConvert].push_back(FoldUnaryOp(FoldScalarUConvert)); rules_[spv::Op::OpDot].push_back(FoldOpDotWithConstants()); rules_[spv::Op::OpFAdd].push_back(FoldFAdd()); @@ -1662,6 +1840,46 @@ void ConstantFoldingRules::AddFoldingRules() { rules_[spv::Op::OpSNegate].push_back(FoldSNegate()); rules_[spv::Op::OpQuantizeToF16].push_back(FoldQuantizeToF16()); + rules_[spv::Op::OpIAdd].push_back( + FoldBinaryOp(FoldBinaryIntegerOperation( + [](uint64_t a, uint64_t b) { return a + b; }))); + rules_[spv::Op::OpISub].push_back( + FoldBinaryOp(FoldBinaryIntegerOperation( + [](uint64_t a, uint64_t b) { return a - b; }))); + rules_[spv::Op::OpIMul].push_back( + FoldBinaryOp(FoldBinaryIntegerOperation( + [](uint64_t a, uint64_t b) { return a * b; }))); + rules_[spv::Op::OpUDiv].push_back( + FoldBinaryOp(FoldBinaryIntegerOperation( + [](uint64_t a, uint64_t b) { return (b != 0 ? a / b : 0); }))); + rules_[spv::Op::OpSDiv].push_back(FoldBinaryOp( + FoldBinaryIntegerOperation([](uint64_t a, uint64_t b) { + return (b != 0 ? static_cast(static_cast(a) / + static_cast(b)) + : 0); + }))); + rules_[spv::Op::OpUMod].push_back( + FoldBinaryOp(FoldBinaryIntegerOperation( + [](uint64_t a, uint64_t b) { return (b != 0 ? a % b : 0); }))); + + rules_[spv::Op::OpSRem].push_back(FoldBinaryOp( + FoldBinaryIntegerOperation([](uint64_t a, uint64_t b) { + return (b != 0 ? static_cast(static_cast(a) % + static_cast(b)) + : 0); + }))); + + rules_[spv::Op::OpSMod].push_back(FoldBinaryOp( + FoldBinaryIntegerOperation([](uint64_t a, uint64_t b) { + if (b == 0) return static_cast(0ull); + + int64_t signed_a = static_cast(a); + int64_t signed_b = static_cast(b); + int64_t result = signed_a % signed_b; + if ((signed_b < 0) != (result < 0)) result += signed_b; + return static_cast(result); + }))); + // Add rules for GLSLstd450 FeatureManager* feature_manager = context_->get_feature_mgr(); uint32_t ext_inst_glslstd450_id = diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index d1a81dff32..a4e0447c10 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -107,6 +107,10 @@ std::tuple, Instruction*> FoldInstruction( std::tie(context, inst) = GetInstructionToFold(test_body, id_to_fold, spv_env); + if (context == nullptr) { + return {nullptr, nullptr}; + } + std::unique_ptr original_inst(inst->Clone(context.get())); bool succeeded = context->get_instruction_folder().FoldInstruction(inst); EXPECT_EQ(inst->result_id(), original_inst->result_id()); @@ -237,9 +241,13 @@ OpName %main "main" %ulong = OpTypeInt 64 0 %v2int = OpTypeVector %int 2 %v4int = OpTypeVector %int 4 +%v2short = OpTypeVector %short 2 +%v2long = OpTypeVector %long 2 +%v4long = OpTypeVector %long 4 %v4float = OpTypeVector %float 4 %v4double = OpTypeVector %double 4 %v2uint = OpTypeVector %uint 2 +%v2ulong = OpTypeVector %ulong 2 %v2float = OpTypeVector %float 2 %v2double = OpTypeVector %double 2 %v2half = OpTypeVector %half 2 @@ -270,6 +278,7 @@ OpName %main "main" %short_0 = OpConstant %short 0 %short_2 = OpConstant %short 2 %short_3 = OpConstant %short 3 +%short_n5 = OpConstant %short -5 %ubyte_1 = OpConstant %ubyte 1 %byte_n1 = OpConstant %byte -1 %100 = OpConstant %int 0 ; Need a def with an numerical id to define id maps. @@ -289,12 +298,20 @@ OpName %main "main" %long_1 = OpConstant %long 1 %long_2 = OpConstant %long 2 %long_3 = OpConstant %long 3 +%long_n3 = OpConstant %long -3 +%long_7 = OpConstant %long 7 +%long_n7 = OpConstant %long -7 %long_10 = OpConstant %long 10 +%long_32768 = OpConstant %long 32768 +%long_n57344 = OpConstant %long -57344 +%long_n4611686018427387904 = OpConstant %long -4611686018427387904 %long_4611686018427387904 = OpConstant %long 4611686018427387904 %long_n1 = OpConstant %long -1 %long_n3689348814741910323 = OpConstant %long -3689348814741910323 %long_min = OpConstant %long -9223372036854775808 %long_max = OpConstant %long 9223372036854775807 +%ulong_7 = OpConstant %ulong 7 +%ulong_4611686018427387904 = OpConstant %ulong 4611686018427387904 %uint_0 = OpConstant %uint 0 %uint_1 = OpConstant %uint 1 %uint_2 = OpConstant %uint 2 @@ -318,6 +335,9 @@ OpName %main "main" %v2int_n1_n24 = OpConstantComposite %v2int %int_n1 %int_n24 %v2int_4_4 = OpConstantComposite %v2int %int_4 %int_4 %v2int_min_max = OpConstantComposite %v2int %int_min %int_max +%v2short_2_n5 = OpConstantComposite %v2short %short_2 %short_n5 +%v2long_2_2 = OpConstantComposite %v2long %long_2 %long_2 +%v2long_2_3 = OpConstantComposite %v2long %long_2 %long_3 %v2bool_null = OpConstantNull %v2bool %v2bool_true_false = OpConstantComposite %v2bool %true %false %v2bool_false_true = OpConstantComposite %v2bool %false %true @@ -1016,10 +1036,238 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "%2 = OpSNegate %ushort %ushort_0x4400\n" + "OpReturn\n" + "OpFunctionEnd", - 2, 0xBC00 /* expected to be zero extended. */) + 2, 0xBC00 /* expected to be zero extended. */), + // Test case 67: Fold 2 + 3 (short) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpIAdd %short %short_2 %short_3\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 5), + // Test case 68: Fold 2 + -5 (short) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpIAdd %short %short_2 %short_n5\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, -3), + // Test case 69: Fold int(3ll) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSConvert %int %long_3\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 3), + // Test case 70: Fold short(-3ll) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSConvert %short %long_n3\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, -3), + // Test case 71: Fold short(32768ll) - This should do a sign extend when + // converting to short. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSConvert %short %long_32768\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, -32768), + // Test case 72: Fold short(-57344) - This should do a sign extend when + // converting to short making the upper bits 0. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSConvert %short %long_n57344\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 8192), + // Test case 73: Fold int(-5(short)). The -5 should be interpreted as an unsigned value, and be zero extended to 32-bits. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpUConvert %uint %short_n5\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 65531), + // Test case 74: Fold short(-24(int)). The upper bits should be cleared. So 0xFFFFFFE8 should become 0x0000FFE8. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpUConvert %ushort %int_n24\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 65512) )); // clang-format on +using LongIntegerInstructionFoldingTest = + ::testing::TestWithParam>; + +TEST_P(LongIntegerInstructionFoldingTest, Case) { + const auto& tc = GetParam(); + + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = + FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1); + CheckForExpectedScalarConstant( + inst, tc.expected_result, [](const analysis::Constant* c) { + return c->AsScalarConstant()->GetU64BitValue(); + }); +} + +INSTANTIATE_TEST_SUITE_P( + TestCase, LongIntegerInstructionFoldingTest, + ::testing::Values( + // Test case 0: fold 1+4611686018427387904 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpIAdd %long %long_1 %long_4611686018427387904\n" + + "OpReturn\n" + "OpFunctionEnd", + 2, 1 + 4611686018427387904), + // Test case 1: fold 1-4611686018427387904 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpISub %long %long_1 %long_4611686018427387904\n" + + "OpReturn\n" + "OpFunctionEnd", + 2, 1 - 4611686018427387904), + // Test case 2: fold 2*4611686018427387904 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpIMul %long %long_2 %long_4611686018427387904\n" + + "OpReturn\n" + "OpFunctionEnd", + 2, 9223372036854775808ull), + // Test case 3: fold 4611686018427387904/2 (unsigned) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpUDiv %ulong %ulong_4611686018427387904 %ulong_2\n" + + "OpReturn\n" + "OpFunctionEnd", + 2, 4611686018427387904 / 2), + // Test case 4: fold 4611686018427387904/2 (signed) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpSDiv %long %long_4611686018427387904 %long_2\n" + + "OpReturn\n" + "OpFunctionEnd", + 2, 4611686018427387904 / 2), + // Test case 5: fold -4611686018427387904/2 (signed) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpSDiv %long %long_n4611686018427387904 %long_2\n" + + "OpReturn\n" + "OpFunctionEnd", + 2, -4611686018427387904 / 2), + // Test case 6: fold 4611686018427387904 mod 7 (unsigned) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpUMod %ulong %ulong_4611686018427387904 %ulong_7\n" + + "OpReturn\n" + "OpFunctionEnd", + 2, 4611686018427387904ull % 7ull), + // Test case 7: fold 7 mod 3 (signed) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpSMod %long %long_7 %long_3\n" + "OpReturn\n" + + "OpFunctionEnd", + 2, 1ull), + // Test case 8: fold 7 rem 3 (signed) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpSRem %long %long_7 %long_3\n" + "OpReturn\n" + + "OpFunctionEnd", + 2, 1ull), + // Test case 9: fold 7 mod -3 (signed) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpSMod %long %long_7 %long_n3\n" + "OpReturn\n" + + "OpFunctionEnd", + 2, -2ll), + // Test case 10: fold 7 rem 3 (signed) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpSRem %long %long_7 %long_n3\n" + "OpReturn\n" + + "OpFunctionEnd", + 2, 1ll), + // Test case 11: fold -7 mod 3 (signed) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpSMod %long %long_n7 %long_3\n" + "OpReturn\n" + + "OpFunctionEnd", + 2, 2ll), + // Test case 12: fold -7 rem 3 (signed) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpSRem %long %long_n7 %long_3\n" + "OpReturn\n" + + "OpFunctionEnd", + 2, -1ll), + // Test case 13: fold long(-24) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpSConvert %long %int_n24\n" + "OpReturn\n" + + "OpFunctionEnd", + 2, -24ll), + // Test case 14: fold long(-24) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + "%2 = OpSConvert %long %int_10\n" + + "OpReturn\n" + "OpFunctionEnd", + 2, 10ll), + // Test case 15: fold long(-24(short)). + // The upper bits should be cleared. So 0xFFFFFFE8 should become + // 0x000000000000FFE8. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + "%2 = OpUConvert %ulong %short_n5\n" + + "OpReturn\n" + "OpFunctionEnd", + 2, 65531ull))); + using UIntVectorInstructionFoldingTest = ::testing::TestWithParam>>; @@ -1077,14 +1325,30 @@ ::testing::Values( "OpReturn\n" + "OpFunctionEnd", 2, {static_cast(-0x3f800000), static_cast(-0xbf800000)}), - // Test case 6: fold vector components of uint (incuding integer overflow) + // Test case 6: fold vector components of uint (including integer overflow) InstructionFoldingCase>( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%2 = OpIAdd %v2uint %v2uint_0x3f800000_0xbf800000 %v2uint_0x3f800000_0xbf800000\n" + "OpReturn\n" + "OpFunctionEnd", - 2, {0x7f000000u, 0x7f000000u}) + 2, {0x7f000000u, 0x7f000000u}), + // Test case 6: fold vector components of uint + InstructionFoldingCase>( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSConvert %v2int %v2short_2_n5\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {2,static_cast(-5)}), + // Test case 6: fold vector components of uint (incuding integer overflow) + InstructionFoldingCase>( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpUConvert %v2uint %v2short_2_n5\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {2,65531}) )); // clang-format on @@ -1142,6 +1406,51 @@ ::testing::Values( )); // clang-format on +using LongIntVectorInstructionFoldingTest = + ::testing::TestWithParam>>; + +TEST_P(LongIntVectorInstructionFoldingTest, Case) { + const auto& tc = GetParam(); + + std::unique_ptr context; + Instruction* inst; + std::tie(context, inst) = + FoldInstruction(tc.test_body, tc.id_to_fold, SPV_ENV_UNIVERSAL_1_1); + CheckForExpectedVectorConstant( + inst, tc.expected_result, + [](const analysis::Constant* c) { return c->GetU64(); }); +} + +// clang-format off +INSTANTIATE_TEST_SUITE_P(TestCase, LongIntVectorInstructionFoldingTest, + ::testing::Values( + // Test case 0: fold {2,2} + {2,3} (Testing that the vector logic works + // correctly. Scalar tests will check that the 64-bit values are correctly + // folded.) + InstructionFoldingCase>( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpIAdd %v2long %v2long_2_2 %v2long_2_3\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {4,5}), + // Test case 0: fold {2,2} / {2,3} (Testing that the vector logic works + // correctly. Scalar tests will check that the 64-bit values are correctly + // folded.) + InstructionFoldingCase>( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%n = OpVariable %_ptr_int Function\n" + + "%load = OpLoad %int %n\n" + + "%2 = OpSDiv %v2long %v2long_2_2 %v2long_2_3\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, {1,0}) + )); +// clang-format on + using DoubleVectorInstructionFoldingTest = ::testing::TestWithParam>>; @@ -3811,23 +4120,7 @@ INSTANTIATE_TEST_SUITE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTe "OpReturn\n" + "OpFunctionEnd", 2, 0), - // Test case 38: Don't fold 2 + 3 (long), bad length - InstructionFoldingCase( - Header() + "%main = OpFunction %void None %void_func\n" + - "%main_lab = OpLabel\n" + - "%2 = OpIAdd %long %long_2 %long_3\n" + - "OpReturn\n" + - "OpFunctionEnd", - 2, 0), - // Test case 39: Don't fold 2 + 3 (short), bad length - InstructionFoldingCase( - Header() + "%main = OpFunction %void None %void_func\n" + - "%main_lab = OpLabel\n" + - "%2 = OpIAdd %short %short_2 %short_3\n" + - "OpReturn\n" + - "OpFunctionEnd", - 2, 0), - // Test case 40: fold 1*n + // Test case 38: fold 1*n InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -3837,7 +4130,7 @@ INSTANTIATE_TEST_SUITE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTe "OpReturn\n" + "OpFunctionEnd", 2, 3), - // Test case 41: fold n*1 + // Test case 39: fold n*1 InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -3847,7 +4140,7 @@ INSTANTIATE_TEST_SUITE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTe "OpReturn\n" + "OpFunctionEnd", 2, 3), - // Test case 42: Don't fold comparisons of 64-bit types + // Test case 40: Don't fold comparisons of 64-bit types // (https://github.com/KhronosGroup/SPIRV-Tools/issues/3343). InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + From 784b064f90a597d2478064161438f4986485b5d4 Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Mon, 12 Feb 2024 23:51:38 +0900 Subject: [PATCH 377/523] spirv-val: Validate PhysicalStorageBuffer Stage Interface (#5539) Disallow PhysicalStorageBuffer pointers in Input and Output storage classes. --- source/val/validate_interfaces.cpp | 29 ++++++ source/val/validation_state.cpp | 2 + test/val/val_interfaces_test.cpp | 145 +++++++++++++++++++++++++++-- 3 files changed, 170 insertions(+), 6 deletions(-) diff --git a/source/val/validate_interfaces.cpp b/source/val/validate_interfaces.cpp index 291b4b82b2..33cf5a0699 100644 --- a/source/val/validate_interfaces.cpp +++ b/source/val/validate_interfaces.cpp @@ -46,6 +46,29 @@ bool is_interface_variable(const Instruction* inst, bool is_spv_1_4) { } } +// Special validation for varibles that are between shader stages +spv_result_t ValidateInputOutputInterfaceVariables(ValidationState_t& _, + const Instruction* var) { + auto var_pointer = _.FindDef(var->GetOperandAs(0)); + uint32_t pointer_id = var_pointer->GetOperandAs(2); + + const auto isPhysicalStorageBuffer = [](const Instruction* insn) { + return insn->opcode() == spv::Op::OpTypePointer && + insn->GetOperandAs(1) == + spv::StorageClass::PhysicalStorageBuffer; + }; + + if (_.ContainsType(pointer_id, isPhysicalStorageBuffer)) { + return _.diag(SPV_ERROR_INVALID_ID, var) + << _.VkErrorID(9557) << "Input/Output interface variable id <" + << var->id() + << "> contains a PhysicalStorageBuffer pointer, which is not " + "allowed. If you want to interface shader stages with a " + "PhysicalStorageBuffer, cast to a uint64 or uvec2 instead."; + } + return SPV_SUCCESS; +} + // Checks that \c var is listed as an interface in all the entry points that use // it. spv_result_t check_interface_variable(ValidationState_t& _, @@ -105,6 +128,12 @@ spv_result_t check_interface_variable(ValidationState_t& _, } } + if (var->GetOperandAs(2) == spv::StorageClass::Input || + var->GetOperandAs(2) == spv::StorageClass::Output) { + if (auto error = ValidateInputOutputInterfaceVariables(_, var)) + return error; + } + return SPV_SUCCESS; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 852860e171..31f7f6ef4c 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -2299,6 +2299,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-08722); case 8973: return VUID_WRAP(VUID-StandaloneSpirv-Pointer-08973); + case 9557: + return VUID_WRAP(VUID-StandaloneSpirv-Input-09557); default: return ""; // unknown id } diff --git a/test/val/val_interfaces_test.cpp b/test/val/val_interfaces_test.cpp index d75c20cf29..45b5f20663 100644 --- a/test/val/val_interfaces_test.cpp +++ b/test/val/val_interfaces_test.cpp @@ -1599,7 +1599,7 @@ TEST_F(ValidateInterfacesTest, InvalidLocationTypePointer) { HasSubstr("Invalid type to assign a location")); } -TEST_F(ValidateInterfacesTest, ValidLocationTypePhysicalStorageBufferPointer) { +TEST_F(ValidateInterfacesTest, PhysicalStorageBufferPointer) { const std::string text = R"( OpCapability Shader OpCapability PhysicalStorageBufferAddresses @@ -1608,10 +1608,71 @@ OpEntryPoint Vertex %main "main" %var OpDecorate %var Location 0 OpDecorate %var RestrictPointer %void = OpTypeVoid -%int = OpTypeInt 32 0 -%ptr = OpTypePointer PhysicalStorageBuffer %int -%ptr2 = OpTypePointer Input %ptr -%var = OpVariable %ptr2 Input +%uint = OpTypeInt 32 0 +%psb_ptr = OpTypePointer PhysicalStorageBuffer %uint +%in_ptr = OpTypePointer Input %psb_ptr +%var = OpVariable %in_ptr Input +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_VULKAN_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_3)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-Input-09557")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Input/Output interface variable id <2> contains a " + "PhysicalStorageBuffer pointer, which is not allowed")); +} + +TEST_F(ValidateInterfacesTest, PhysicalStorageBufferPointerArray) { + const std::string text = R"( +OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint Vertex %main "main" %var +OpDecorate %var Location 0 +OpDecorate %var RestrictPointer +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%uint_3 = OpConstant %uint 3 +%psb_ptr = OpTypePointer PhysicalStorageBuffer %uint +%array = OpTypeArray %psb_ptr %uint_3 +%in_ptr = OpTypePointer Input %array +%var = OpVariable %in_ptr Input +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_VULKAN_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_3)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-Input-09557")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Input/Output interface variable id <2> contains a " + "PhysicalStorageBuffer pointer, which is not allowed")); +} + +TEST_F(ValidateInterfacesTest, PhysicalStorageBufferPointerStruct) { + const std::string text = R"( +OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint Vertex %main "main" %var +OpDecorate %var Location 0 +OpDecorate %var RestrictPointer +%void = OpTypeVoid +%int = OpTypeInt 32 1 +OpTypeForwardPointer %psb_ptr PhysicalStorageBuffer +%struct_0 = OpTypeStruct %int %psb_ptr +%struct_1 = OpTypeStruct %int %int +%psb_ptr = OpTypePointer PhysicalStorageBuffer %struct_1 +%in_ptr = OpTypePointer Input %struct_0 +%var = OpVariable %in_ptr Input %void_fn = OpTypeFunction %void %main = OpFunction %void None %void_fn %entry = OpLabel @@ -1619,7 +1680,79 @@ OpReturn OpFunctionEnd )"; CompileSuccessfully(text, SPV_ENV_VULKAN_1_3); - EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3)); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_3)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-Input-09557")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Input/Output interface variable id <2> contains a " + "PhysicalStorageBuffer pointer, which is not allowed")); +} + +TEST_F(ValidateInterfacesTest, PhysicalStorageBufferPointerArrayOfStruct) { + const std::string text = R"( +OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint Vertex %main "main" %var +OpDecorate %var Location 0 +OpDecorate %var RestrictPointer +%void = OpTypeVoid +%int = OpTypeInt 32 1 +%uint = OpTypeInt 32 0 +%uint_3 = OpConstant %uint 3 +OpTypeForwardPointer %psb_ptr PhysicalStorageBuffer +%array_1 = OpTypeArray %psb_ptr %uint_3 +%struct_0 = OpTypeStruct %int %array_1 + %struct_1 = OpTypeStruct %int %int +%psb_ptr = OpTypePointer PhysicalStorageBuffer %struct_1 +%array_0 = OpTypeArray %struct_0 %uint_3 +%in_ptr = OpTypePointer Input %array_0 +%var = OpVariable %in_ptr Input +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_VULKAN_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_3)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-Input-09557")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Input/Output interface variable id <2> contains a " + "PhysicalStorageBuffer pointer, which is not allowed")); +} + +TEST_F(ValidateInterfacesTest, PhysicalStorageBufferPointerNestedStruct) { + const std::string text = R"( +OpCapability Shader +OpCapability PhysicalStorageBufferAddresses +OpMemoryModel PhysicalStorageBuffer64 GLSL450 +OpEntryPoint Vertex %main "main" %var +OpDecorate %var Location 0 +OpDecorate %var RestrictPointer +%void = OpTypeVoid +%int = OpTypeInt 32 1 +OpTypeForwardPointer %psb_ptr PhysicalStorageBuffer +%struct_0 = OpTypeStruct %int %psb_ptr +%struct_1 = OpTypeStruct %int %int +%psb_ptr = OpTypePointer PhysicalStorageBuffer %struct_1 +%struct_2 = OpTypeStruct %int %struct_0 +%in_ptr = OpTypePointer Input %struct_2 +%var = OpVariable %in_ptr Input +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(text, SPV_ENV_VULKAN_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_3)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-Input-09557")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Input/Output interface variable id <2> contains a " + "PhysicalStorageBuffer pointer, which is not allowed")); } } // namespace From b7413609cf2d5adccc877d71a1d67ec43bea07c0 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Mon, 12 Feb 2024 14:52:55 -0500 Subject: [PATCH 378/523] [OPT] Use new instruction folder for for all opcodes in spec consti folding (#5569) * [OPT] Use new instruction folder for for all opcodes in spec consti folding When folding and OpSpecConstantOp, we use the new instruction folder for a small number of opcodes. This enable the new instruction folder for all opcodes and uses the old one as a fall back. This allows us to remove some code from the older folder that is now covered by the new one. Fixes #5499 --- source/opt/const_folding_rules.cpp | 6 +- source/opt/fold.cpp | 52 --------- ...ld_spec_constant_op_and_composite_pass.cpp | 17 +-- .../opt/fold_spec_const_op_composite_test.cpp | 105 +----------------- 4 files changed, 9 insertions(+), 171 deletions(-) diff --git a/source/opt/const_folding_rules.cpp b/source/opt/const_folding_rules.cpp index 79f34acd3c..17900af245 100644 --- a/source/opt/const_folding_rules.cpp +++ b/source/opt/const_folding_rules.cpp @@ -1715,8 +1715,10 @@ BinaryScalarFoldingRule FoldBinaryIntegerOperation(uint64_t (*op)(uint64_t, assert(result_type != nullptr && a != nullptr && b != nullptr); const analysis::Integer* integer_type = result_type->AsInteger(); assert(integer_type != nullptr); - assert(integer_type == a->type()->AsInteger()); - assert(integer_type == b->type()->AsInteger()); + assert(a->type()->kind() == analysis::Type::kInteger); + assert(b->type()->kind() == analysis::Type::kInteger); + assert(integer_type->width() == a->type()->AsInteger()->width()); + assert(integer_type->width() == b->type()->AsInteger()->width()); // In SPIR-V, all operations support unsigned types, but the way they // are interpreted depends on the opcode. This is why we use the diff --git a/source/opt/fold.cpp b/source/opt/fold.cpp index c2a97b6e6e..942da6835f 100644 --- a/source/opt/fold.cpp +++ b/source/opt/fold.cpp @@ -70,58 +70,6 @@ uint32_t InstructionFolder::UnaryOperate(spv::Op opcode, uint32_t InstructionFolder::BinaryOperate(spv::Op opcode, uint32_t a, uint32_t b) const { switch (opcode) { - // Arthimetics - case spv::Op::OpIAdd: - return a + b; - case spv::Op::OpISub: - return a - b; - case spv::Op::OpIMul: - return a * b; - case spv::Op::OpUDiv: - if (b != 0) { - return a / b; - } else { - // Dividing by 0 is undefined, so we will just pick 0. - return 0; - } - case spv::Op::OpSDiv: - if (b != 0u) { - return (static_cast(a)) / (static_cast(b)); - } else { - // Dividing by 0 is undefined, so we will just pick 0. - return 0; - } - case spv::Op::OpSRem: { - // The sign of non-zero result comes from the first operand: a. This is - // guaranteed by C++11 rules for integer division operator. The division - // result is rounded toward zero, so the result of '%' has the sign of - // the first operand. - if (b != 0u) { - return static_cast(a) % static_cast(b); - } else { - // Remainder when dividing with 0 is undefined, so we will just pick 0. - return 0; - } - } - case spv::Op::OpSMod: { - // The sign of non-zero result comes from the second operand: b - if (b != 0u) { - int32_t rem = BinaryOperate(spv::Op::OpSRem, a, b); - int32_t b_prim = static_cast(b); - return (rem + b_prim) % b_prim; - } else { - // Mod with 0 is undefined, so we will just pick 0. - return 0; - } - } - case spv::Op::OpUMod: - if (b != 0u) { - return (a % b); - } else { - // Mod with 0 is undefined, so we will just pick 0. - return 0; - } - // Shifting case spv::Op::OpShiftRightLogical: if (b >= 32) { 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 770e1fe50c..c568027d2a 100644 --- a/source/opt/fold_spec_constant_op_and_composite_pass.cpp +++ b/source/opt/fold_spec_constant_op_and_composite_pass.cpp @@ -115,20 +115,9 @@ bool FoldSpecConstantOpAndCompositePass::ProcessOpSpecConstantOp( "The first in-operand of OpSpecConstantOp instruction must be of " "SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER type"); - switch (static_cast(inst->GetSingleWordInOperand(0))) { - case spv::Op::OpCompositeExtract: - case spv::Op::OpVectorShuffle: - case spv::Op::OpCompositeInsert: - case spv::Op::OpQuantizeToF16: - folded_inst = FoldWithInstructionFolder(pos); - break; - default: - // TODO: This should use the instruction folder as well, but some folding - // rules are missing. - - // Component-wise operations. - folded_inst = DoComponentWiseOperation(pos); - break; + folded_inst = FoldWithInstructionFolder(pos); + if (!folded_inst) { + folded_inst = DoComponentWiseOperation(pos); } if (!folded_inst) return false; diff --git a/test/opt/fold_spec_const_op_composite_test.cpp b/test/opt/fold_spec_const_op_composite_test.cpp index 70ba362056..335e0f5162 100644 --- a/test/opt/fold_spec_const_op_composite_test.cpp +++ b/test/opt/fold_spec_const_op_composite_test.cpp @@ -1058,14 +1058,8 @@ INSTANTIATE_TEST_SUITE_P( }, // expected { - "%true = OpConstantTrue %bool", - "%true_0 = OpConstantTrue %bool", "%spec_bool_t_vec = OpConstantComposite %v2bool %bool_true %bool_true", - "%false = OpConstantFalse %bool", - "%false_0 = OpConstantFalse %bool", "%spec_bool_f_vec = OpConstantComposite %v2bool %bool_false %bool_false", - "%false_1 = OpConstantFalse %bool", - "%false_2 = OpConstantFalse %bool", "%spec_bool_from_null = OpConstantComposite %v2bool %bool_false %bool_false", }, }, @@ -1080,14 +1074,8 @@ INSTANTIATE_TEST_SUITE_P( }, // expected { - "%true = OpConstantTrue %bool", - "%true_0 = OpConstantTrue %bool", "%spec_bool_t_vec = OpConstantComposite %v2bool %bool_true %bool_true", - "%false = OpConstantFalse %bool", - "%false_0 = OpConstantFalse %bool", "%spec_bool_f_vec = OpConstantComposite %v2bool %bool_false %bool_false", - "%false_1 = OpConstantFalse %bool", - "%false_2 = OpConstantFalse %bool", "%spec_bool_from_null = OpConstantComposite %v2bool %bool_false %bool_false", }, }, @@ -1102,14 +1090,8 @@ INSTANTIATE_TEST_SUITE_P( }, // expected { - "%int_1 = OpConstant %int 1", - "%int_1_0 = OpConstant %int 1", "%spec_int_one_vec = OpConstantComposite %v2int %signed_one %signed_one", - "%int_0 = OpConstant %int 0", - "%int_0_0 = OpConstant %int 0", "%spec_int_zero_vec = OpConstantComposite %v2int %signed_zero %signed_zero", - "%int_0_1 = OpConstant %int 0", - "%int_0_2 = OpConstant %int 0", "%spec_int_from_null = OpConstantComposite %v2int %signed_zero %signed_zero", }, }, @@ -1124,14 +1106,8 @@ INSTANTIATE_TEST_SUITE_P( }, // expected { - "%int_1 = OpConstant %int 1", - "%int_1_0 = OpConstant %int 1", "%spec_int_one_vec = OpConstantComposite %v2int %signed_one %signed_one", - "%int_0 = OpConstant %int 0", - "%int_0_0 = OpConstant %int 0", "%spec_int_zero_vec = OpConstantComposite %v2int %signed_zero %signed_zero", - "%int_0_1 = OpConstant %int 0", - "%int_0_2 = OpConstant %int 0", "%spec_int_from_null = OpConstantComposite %v2int %signed_zero %signed_zero", }, }, @@ -1146,14 +1122,8 @@ INSTANTIATE_TEST_SUITE_P( }, // expected { - "%uint_1 = OpConstant %uint 1", - "%uint_1_0 = OpConstant %uint 1", "%spec_uint_one_vec = OpConstantComposite %v2uint %unsigned_one %unsigned_one", - "%uint_0 = OpConstant %uint 0", - "%uint_0_0 = OpConstant %uint 0", "%spec_uint_zero_vec = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero", - "%uint_0_1 = OpConstant %uint 0", - "%uint_0_2 = OpConstant %uint 0", "%spec_uint_from_null = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero", }, }, @@ -1168,14 +1138,8 @@ INSTANTIATE_TEST_SUITE_P( }, // expected { - "%uint_1 = OpConstant %uint 1", - "%uint_1_0 = OpConstant %uint 1", "%spec_uint_one_vec = OpConstantComposite %v2uint %unsigned_one %unsigned_one", - "%uint_0 = OpConstant %uint 0", - "%uint_0_0 = OpConstant %uint 0", "%spec_uint_zero_vec = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero", - "%uint_0_1 = OpConstant %uint 0", - "%uint_0_2 = OpConstant %uint 0", "%spec_uint_from_null = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero", }, }, @@ -1184,8 +1148,6 @@ INSTANTIATE_TEST_SUITE_P( { // original { - "%spec_uint_zero = OpSpecConstantOp %uint UConvert %bool_false", - "%spec_uint_one = OpSpecConstantOp %uint UConvert %bool_true", "%spec_ulong_zero = OpSpecConstantOp %ulong UConvert %unsigned_zero", "%spec_ulong_one = OpSpecConstantOp %ulong UConvert %unsigned_one", "%spec_short_zero = OpSpecConstantOp %ushort UConvert %unsigned_zero", @@ -1197,8 +1159,6 @@ INSTANTIATE_TEST_SUITE_P( }, // expected { - "%spec_uint_zero = OpConstant %uint 0", - "%spec_uint_one = OpConstant %uint 1", "%spec_ulong_zero = OpConstant %ulong 0", "%spec_ulong_one = OpConstant %ulong 1", "%spec_short_zero = OpConstant %ushort 0", @@ -1236,24 +1196,13 @@ INSTANTIATE_TEST_SUITE_P( { // original { - "%spec_v2uint_zero = OpSpecConstantOp %v2uint UConvert %bool_false_vec", - "%spec_v2uint_one = OpSpecConstantOp %v2uint UConvert %bool_true_vec", "%spec_v2ulong_zero = OpSpecConstantOp %v2ulong UConvert %unsigned_zero_vec", "%spec_v2ulong_one = OpSpecConstantOp %v2ulong UConvert %unsigned_one_vec", }, // expected { - "%uint_0 = OpConstant %uint 0", - "%uint_0_0 = OpConstant %uint 0", - "%spec_v2uint_zero = OpConstantComposite %v2uint %unsigned_zero %unsigned_zero", - "%uint_1 = OpConstant %uint 1", - "%uint_1_0 = OpConstant %uint 1", - "%spec_v2uint_one = OpConstantComposite %v2uint %unsigned_one %unsigned_one", - "%ulong_0 = OpConstant %ulong 0", - "%ulong_0_0 = OpConstant %ulong 0", "%spec_v2ulong_zero = OpConstantComposite %v2ulong %ulong_zero %ulong_zero", "%ulong_1 = OpConstant %ulong 1", - "%ulong_1_0 = OpConstant %ulong 1", "%spec_v2ulong_one = OpConstantComposite %v2ulong %ulong_1 %ulong_1", }, }, @@ -1268,14 +1217,10 @@ INSTANTIATE_TEST_SUITE_P( }, // expected { - "%long_0 = OpConstant %long 0", - "%long_0_0 = OpConstant %long 0", "%spec_v2long_zero = OpConstantComposite %v2long %long_zero %long_zero", "%long_1 = OpConstant %long 1", - "%long_1_0 = OpConstant %long 1", "%spec_v2long_one = OpConstantComposite %v2long %long_1 %long_1", "%long_n1 = OpConstant %long -1", - "%long_n1_0 = OpConstant %long -1", "%spec_v2long_minus_one = OpConstantComposite %v2long %long_n1 %long_n1", }, }, @@ -1372,7 +1317,7 @@ INSTANTIATE_TEST_SUITE_P( { "%int_minus_1 = OpConstant %int -1", "%int_minus_2 = OpConstant %int -2", - "%int_neg_null = OpConstant %int 0", + "%int_neg_null = OpConstantNull %int", "%int_max = OpConstant %int 2147483647", "%int_neg_max = OpConstant %int -2147483647", }, @@ -1553,15 +1498,10 @@ INSTANTIATE_TEST_SUITE_P( }, // expected { - "%int_n1 = OpConstant %int -1", - "%int_n1_0 = OpConstant %int -1", "%v2int_minus_1 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", "%int_n2 = OpConstant %int -2", - "%int_n2_0 = OpConstant %int -2", "%v2int_minus_2 = OpConstantComposite %v2int %int_n2 %int_n2", - "%int_0 = OpConstant %int 0", - "%int_0_0 = OpConstant %int 0", - "%v2int_neg_null = OpConstantComposite %v2int %signed_zero %signed_zero", + "%v2int_neg_null = OpConstantComposite %v2int %signed_null %signed_null", }, }, // vector integer (including null vetors) add, sub, div, mul @@ -1583,35 +1523,23 @@ INSTANTIATE_TEST_SUITE_P( // expected { "%int_5 = OpConstant %int 5", - "%int_5_0 = OpConstant %int 5", "%spec_v2int_iadd = OpConstantComposite %v2int %int_5 %int_5", "%int_n4 = OpConstant %int -4", - "%int_n4_0 = OpConstant %int -4", "%spec_v2int_isub = OpConstantComposite %v2int %int_n4 %int_n4", "%int_n2 = OpConstant %int -2", - "%int_n2_0 = OpConstant %int -2", "%spec_v2int_sdiv = OpConstantComposite %v2int %int_n2 %int_n2", "%int_n6 = OpConstant %int -6", - "%int_n6_0 = OpConstant %int -6", "%spec_v2int_imul = OpConstantComposite %v2int %int_n6 %int_n6", - "%int_n6_1 = OpConstant %int -6", - "%int_n6_2 = OpConstant %int -6", "%spec_v2int_iadd_null = OpConstantComposite %v2int %int_n6 %int_n6", "%uint_5 = OpConstant %uint 5", - "%uint_5_0 = OpConstant %uint 5", "%spec_v2uint_iadd = OpConstantComposite %v2uint %uint_5 %uint_5", "%uint_4294967292 = OpConstant %uint 4294967292", - "%uint_4294967292_0 = OpConstant %uint 4294967292", "%spec_v2uint_isub = OpConstantComposite %v2uint %uint_4294967292 %uint_4294967292", "%uint_1431655764 = OpConstant %uint 1431655764", - "%uint_1431655764_0 = OpConstant %uint 1431655764", "%spec_v2uint_udiv = OpConstantComposite %v2uint %uint_1431655764 %uint_1431655764", "%uint_2863311528 = OpConstant %uint 2863311528", - "%uint_2863311528_0 = OpConstant %uint 2863311528", "%spec_v2uint_imul = OpConstantComposite %v2uint %uint_2863311528 %uint_2863311528", - "%uint_2863311528_1 = OpConstant %uint 2863311528", - "%uint_2863311528_2 = OpConstant %uint 2863311528", "%spec_v2uint_isub_null = OpConstantComposite %v2uint %uint_2863311528 %uint_2863311528", }, }, @@ -1655,34 +1583,17 @@ INSTANTIATE_TEST_SUITE_P( "%v2int_minus_3 = OpConstantComposite %v2int %int_minus_3 %int_minus_3", // srem - "%int_1 = OpConstant %int 1", - "%int_1_0 = OpConstant %int 1", "%7_srem_3 = OpConstantComposite %v2int %signed_one %signed_one", - "%int_n1 = OpConstant %int -1", - "%int_n1_0 = OpConstant %int -1", "%minus_7_srem_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", - "%int_1_1 = OpConstant %int 1", - "%int_1_2 = OpConstant %int 1", "%7_srem_minus_3 = OpConstantComposite %v2int %signed_one %signed_one", - "%int_n1_1 = OpConstant %int -1", - "%int_n1_2 = OpConstant %int -1", "%minus_7_srem_minus_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", // smod - "%int_1_3 = OpConstant %int 1", - "%int_1_4 = OpConstant %int 1", "%7_smod_3 = OpConstantComposite %v2int %signed_one %signed_one", - "%int_2 = OpConstant %int 2", - "%int_2_0 = OpConstant %int 2", "%minus_7_smod_3 = OpConstantComposite %v2int %signed_two %signed_two", "%int_n2 = OpConstant %int -2", - "%int_n2_0 = OpConstant %int -2", "%7_smod_minus_3 = OpConstantComposite %v2int %int_n2 %int_n2", - "%int_n1_3 = OpConstant %int -1", - "%int_n1_4 = OpConstant %int -1", "%minus_7_smod_minus_3 = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", // umod - "%uint_1 = OpConstant %uint 1", - "%uint_1_0 = OpConstant %uint 1", "%7_umod_3 = OpConstantComposite %v2uint %unsigned_one %unsigned_one", }, }, @@ -1702,26 +1613,15 @@ INSTANTIATE_TEST_SUITE_P( }, // expected { - "%int_2 = OpConstant %int 2", - "%int_2_0 = OpConstant %int 2", "%xor_1_3 = OpConstantComposite %v2int %signed_two %signed_two", - "%int_0 = OpConstant %int 0", - "%int_0_0 = OpConstant %int 0", "%and_1_2 = OpConstantComposite %v2int %signed_zero %signed_zero", - "%int_3 = OpConstant %int 3", - "%int_3_0 = OpConstant %int 3", "%or_1_2 = OpConstantComposite %v2int %signed_three %signed_three", "%unsigned_31 = OpConstant %uint 31", "%v2unsigned_31 = OpConstantComposite %v2uint %unsigned_31 %unsigned_31", "%uint_2147483648 = OpConstant %uint 2147483648", - "%uint_2147483648_0 = OpConstant %uint 2147483648", "%unsigned_left_shift_max = OpConstantComposite %v2uint %uint_2147483648 %uint_2147483648", - "%uint_1 = OpConstant %uint 1", - "%uint_1_0 = OpConstant %uint 1", "%unsigned_right_shift_logical = OpConstantComposite %v2uint %unsigned_one %unsigned_one", - "%int_n1 = OpConstant %int -1", - "%int_n1_0 = OpConstant %int -1", "%signed_right_shift_arithmetic = OpConstantComposite %v2int %signed_minus_one %signed_minus_one", }, }, @@ -2091,7 +1991,6 @@ INSTANTIATE_TEST_SUITE_P( "%spec_int_20 = OpConstant %int 101", "%used_vec_a = OpConstantComposite %v2int %spec_int_18 %spec_int_19", "%int_10201 = OpConstant %int 10201", - "%int_1 = OpConstant %int 1", "%used_vec_b = OpConstantComposite %v2int %int_10201 %signed_one", "%spec_int_21 = OpConstant %int 10201", "%array = OpConstantComposite %type_arr_int_4 %spec_int_20 %spec_int_20 %spec_int_21 %spec_int_21", From 0c986f596d7dab29510d67d71456155c508e2354 Mon Sep 17 00:00:00 2001 From: Ben Ashbaugh Date: Tue, 13 Feb 2024 08:07:39 -0800 Subject: [PATCH 379/523] update image enum tests to remove Kernel capability (#5562) We are removing Kernel from the image channel order and image channel data type enums because Kernel is already required transitively, so we need to update the tests to match. --- DEPS | 2 +- test/operand_capabilities_test.cpp | 92 +++++++++++++++--------------- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/DEPS b/DEPS index 2fbe251c1f..50fd6c194b 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': 'ab7c5918b418428ed17dbe564e0d8402bd7d743d', - 'spirv_headers_revision': 'e77d03080b90c5d361663a67834c57bb1fddaec2', + 'spirv_headers_revision': 'd3c2a6fa95ad463ca8044d7fc45557db381a6a64', } deps = { diff --git a/test/operand_capabilities_test.cpp b/test/operand_capabilities_test.cpp index 6f2ac9f77f..53dbe07010 100644 --- a/test/operand_capabilities_test.cpp +++ b/test/operand_capabilities_test.cpp @@ -340,56 +340,56 @@ INSTANTIATE_TEST_SUITE_P( // See SPIR-V Section 3.12 Image Channel Order INSTANTIATE_TEST_SUITE_P( ImageChannelOrder, EnumCapabilityTest, - Combine( - Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), - ValuesIn(std::vector{ - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::R, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::A, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RG, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RA, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RGB, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RGBA, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::BGRA, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::ARGB, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::Intensity, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::Luminance, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::Rx, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RGx, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RGBx, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::Depth, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::DepthStencil, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::sRGB, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::sRGBx, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::sRGBA, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::sBGRA, Kernel), - CASE1(IMAGE_CHANNEL_ORDER, ImageChannelOrder::ABGR, Kernel), - }))); + Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), + ValuesIn(std::vector{ + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::R), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::A), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RG), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RA), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RGB), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RGBA), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::BGRA), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::ARGB), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::Intensity), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::Luminance), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::Rx), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RGx), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::RGBx), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::Depth), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::DepthStencil), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::sRGB), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::sRGBx), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::sRGBA), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::sBGRA), + CASE0(IMAGE_CHANNEL_ORDER, ImageChannelOrder::ABGR), + }))); // See SPIR-V Section 3.13 Image Channel Data Type INSTANTIATE_TEST_SUITE_P( ImageChannelDataType, EnumCapabilityTest, - Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), - ValuesIn(std::vector{ - // clang-format off - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SnormInt8, Kernel), - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SnormInt16, Kernel), - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt8, Kernel), - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt16, Kernel), - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormShort565, Kernel), - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormShort555, Kernel), - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt101010, Kernel), - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SignedInt8, Kernel), - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SignedInt16, Kernel), - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SignedInt32, Kernel), - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnsignedInt8, Kernel), - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnsignedInt16, Kernel), - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnsignedInt32, Kernel), - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::HalfFloat, Kernel), - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::Float, Kernel), - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt24, Kernel), - CASE1(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt101010_2, Kernel), - // clang-format on - }))); + Combine( + Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1), + ValuesIn(std::vector{ + // clang-format off + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SnormInt8), + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SnormInt16), + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt8), + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt16), + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormShort565), + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormShort555), + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt101010), + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SignedInt8), + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SignedInt16), + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::SignedInt32), + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnsignedInt8), + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnsignedInt16), + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnsignedInt32), + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::HalfFloat), + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::Float), + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt24), + CASE0(IMAGE_CHANNEL_DATA_TYPE, ImageChannelDataType::UnormInt101010_2), + // clang-format on + }))); // See SPIR-V Section 3.14 Image Operands INSTANTIATE_TEST_SUITE_P( From 56a51dd9475a43f38f827ce43c149a624cd9a0fb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 14:19:09 -0500 Subject: [PATCH 380/523] Roll external/spirv-headers/ e77d03080..d3c2a6fa9 (1 commit) (#5574) https://github.com/KhronosGroup/SPIRV-Headers/compare/e77d03080b90...d3c2a6fa95ad $ git log e77d03080..d3c2a6fa9 --date=short --no-merges --format='%ad %ae %s' 2024-02-12 ben.ashbaugh remove Kernel from Image Channel Order and Channel Data Type enums (#413) Created with: roll-dep external/spirv-headers Co-authored-by: GitHub Actions[bot] <> Co-authored-by: Cassandra Beckley From e08c012b19e80e7798f55f6010a3cf0645dd9e71 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Tue, 13 Feb 2024 14:41:38 -0500 Subject: [PATCH 381/523] [OPT] Identify arrays with unknown length in copy prop arrays (#5570) * [OPT] Identify arrays with unknown length in copy prop arrays The code in copy propagate arrays assumes that the length of an OpTypeArray is known at compile time, but that is not true when the size is an OpSpecConstant. We try to fix that assumption. Fixes https://crbug.com/oss-fuzz/66634 --- source/opt/copy_prop_arrays.cpp | 58 +++++++++++++++---------------- source/opt/copy_prop_arrays.h | 5 +-- test/opt/copy_prop_array_test.cpp | 35 +++++++++++++++++++ 3 files changed, 66 insertions(+), 32 deletions(-) diff --git a/source/opt/copy_prop_arrays.cpp b/source/opt/copy_prop_arrays.cpp index 66a268fbaa..c2bea8ad04 100644 --- a/source/opt/copy_prop_arrays.cpp +++ b/source/opt/copy_prop_arrays.cpp @@ -35,6 +35,32 @@ bool IsDebugDeclareOrValue(Instruction* di) { dbg_opcode == CommonDebugInfoDebugValue; } +// Returns the number of members in |type|. If |type| is not a composite type +// or the number of components is not known at compile time, the return value +// will be 0. +uint32_t GetNumberOfMembers(const analysis::Type* type, IRContext* context) { + if (const analysis::Struct* struct_type = type->AsStruct()) { + return static_cast(struct_type->element_types().size()); + } else if (const analysis::Array* array_type = type->AsArray()) { + const analysis::Constant* length_const = + context->get_constant_mgr()->FindDeclaredConstant( + array_type->LengthId()); + + if (length_const == nullptr) { + // This can happen if the length is an OpSpecConstant. + return 0; + } + assert(length_const->type()->AsInteger()); + return length_const->GetU32(); + } else if (const analysis::Vector* vector_type = type->AsVector()) { + return vector_type->element_count(); + } else if (const analysis::Matrix* matrix_type = type->AsMatrix()) { + return matrix_type->element_count(); + } else { + return 0; + } +} + } // namespace Pass::Status CopyPropagateArrays::Process() { @@ -357,22 +383,9 @@ CopyPropagateArrays::BuildMemoryObjectFromInsert(Instruction* insert_inst) { analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr(); analysis::TypeManager* type_mgr = context()->get_type_mgr(); - analysis::ConstantManager* const_mgr = context()->get_constant_mgr(); const analysis::Type* result_type = type_mgr->GetType(insert_inst->type_id()); - uint32_t number_of_elements = 0; - if (const analysis::Struct* struct_type = result_type->AsStruct()) { - number_of_elements = - static_cast(struct_type->element_types().size()); - } else if (const analysis::Array* array_type = result_type->AsArray()) { - const analysis::Constant* length_const = - const_mgr->FindDeclaredConstant(array_type->LengthId()); - number_of_elements = length_const->GetU32(); - } else if (const analysis::Vector* vector_type = result_type->AsVector()) { - number_of_elements = vector_type->element_count(); - } else if (const analysis::Matrix* matrix_type = result_type->AsMatrix()) { - number_of_elements = matrix_type->element_count(); - } + uint32_t number_of_elements = GetNumberOfMembers(result_type, context()); if (number_of_elements == 0) { return nullptr; @@ -800,23 +813,8 @@ uint32_t CopyPropagateArrays::MemoryObject::GetNumberOfMembers() { std::vector access_indices = GetAccessIds(); type = type_mgr->GetMemberType(type, access_indices); - if (const analysis::Struct* struct_type = type->AsStruct()) { - return static_cast(struct_type->element_types().size()); - } else if (const analysis::Array* array_type = type->AsArray()) { - const analysis::Constant* length_const = - context->get_constant_mgr()->FindDeclaredConstant( - array_type->LengthId()); - assert(length_const->type()->AsInteger()); - return length_const->GetU32(); - } else if (const analysis::Vector* vector_type = type->AsVector()) { - return vector_type->element_count(); - } else if (const analysis::Matrix* matrix_type = type->AsMatrix()) { - return matrix_type->element_count(); - } else { - return 0; - } + return opt::GetNumberOfMembers(type, context); } - template CopyPropagateArrays::MemoryObject::MemoryObject(Instruction* var_inst, iterator begin, iterator end) diff --git a/source/opt/copy_prop_arrays.h b/source/opt/copy_prop_arrays.h index 7486f8086e..c6ca7d251b 100644 --- a/source/opt/copy_prop_arrays.h +++ b/source/opt/copy_prop_arrays.h @@ -101,7 +101,8 @@ class CopyPropagateArrays : public MemPass { bool IsMember() const { return !access_chain_.empty(); } // Returns the number of members in the object represented by |this|. If - // |this| does not represent a composite type, the return value will be 0. + // |this| does not represent a composite type or the number of components is + // not known at compile time, the return value will be 0. uint32_t GetNumberOfMembers(); // Returns the owning variable that the memory object is contained in. @@ -207,7 +208,7 @@ class CopyPropagateArrays : public MemPass { // Returns the memory object that at some point was equivalent to the result // of |insert_inst|. If a memory object cannot be identified, the return - // value is |nullptr\. The opcode of |insert_inst| must be + // value is |nullptr|. The opcode of |insert_inst| must be // |OpCompositeInsert|. This function looks for a series of // |OpCompositeInsert| instructions that insert the elements one at a time in // order from beginning to end. diff --git a/test/opt/copy_prop_array_test.cpp b/test/opt/copy_prop_array_test.cpp index 2d4b7a3b60..16719b8700 100644 --- a/test/opt/copy_prop_array_test.cpp +++ b/test/opt/copy_prop_array_test.cpp @@ -1942,6 +1942,41 @@ OpFunctionEnd SinglePassRunAndCheck(text, text, false); } + +// If the size of an array used in an OpCompositeInsert is not known at compile +// time, then we should not propagate the array, because we do not have a single +// array that represents the final value. +TEST_F(CopyPropArrayPassTest, SpecConstSizedArray) { + const std::string text = R"(OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %2 "main" +OpExecutionMode %2 OriginUpperLeft +%void = OpTypeVoid +%4 = OpTypeFunction %void +%int = OpTypeInt 32 1 +%uint = OpTypeInt 32 0 +%7 = OpSpecConstant %uint 32 +%_arr_int_7 = OpTypeArray %int %7 +%int_63 = OpConstant %int 63 +%uint_0 = OpConstant %uint 0 +%bool = OpTypeBool +%int_0 = OpConstant %int 0 +%int_587202566 = OpConstant %int 587202566 +%false = OpConstantFalse %bool +%_ptr_Function__arr_int_7 = OpTypePointer Function %_arr_int_7 +%16 = OpUndef %_arr_int_7 +%2 = OpFunction %void None %4 +%17 = OpLabel +%18 = OpVariable %_ptr_Function__arr_int_7 Function +%19 = OpCompositeInsert %_arr_int_7 %int_0 %16 0 +OpStore %18 %19 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, false); +} } // namespace } // namespace opt } // namespace spvtools From 20ad38c18d3fb8751005c3dbbac1955d34bc62c8 Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Wed, 14 Feb 2024 05:55:43 +0900 Subject: [PATCH 382/523] spirv-val: Multiple interface var with same SC (#5528) --- source/val/validate_interfaces.cpp | 61 ++++++++++++++++++++ source/val/validation_state.cpp | 8 +++ test/val/val_decoration_test.cpp | 42 ++++++++++++++ test/val/val_ray_tracing_test.cpp | 89 ++++++++++++++++++++++++++++++ 4 files changed, 200 insertions(+) diff --git a/source/val/validate_interfaces.cpp b/source/val/validate_interfaces.cpp index 33cf5a0699..ef775a8524 100644 --- a/source/val/validate_interfaces.cpp +++ b/source/val/validate_interfaces.cpp @@ -587,6 +587,64 @@ spv_result_t ValidateLocations(ValidationState_t& _, return SPV_SUCCESS; } +spv_result_t ValidateStorageClass(ValidationState_t& _, + const Instruction* entry_point) { + bool has_push_constant = false; + bool has_ray_payload = false; + bool has_hit_attribute = false; + bool has_callable_data = false; + for (uint32_t i = 3; i < entry_point->operands().size(); ++i) { + auto interface_id = entry_point->GetOperandAs(i); + auto interface_var = _.FindDef(interface_id); + auto storage_class = interface_var->GetOperandAs(2); + switch (storage_class) { + case spv::StorageClass::PushConstant: { + if (has_push_constant) { + return _.diag(SPV_ERROR_INVALID_DATA, entry_point) + << _.VkErrorID(6673) + << "Entry-point has more than one variable with the " + "PushConstant storage class in the interface"; + } + has_push_constant = true; + break; + } + case spv::StorageClass::IncomingRayPayloadKHR: { + if (has_ray_payload) { + return _.diag(SPV_ERROR_INVALID_DATA, entry_point) + << _.VkErrorID(4700) + << "Entry-point has more than one variable with the " + "IncomingRayPayloadKHR storage class in the interface"; + } + has_ray_payload = true; + break; + } + case spv::StorageClass::HitAttributeKHR: { + if (has_hit_attribute) { + return _.diag(SPV_ERROR_INVALID_DATA, entry_point) + << _.VkErrorID(4702) + << "Entry-point has more than one variable with the " + "HitAttributeKHR storage class in the interface"; + } + has_hit_attribute = true; + break; + } + case spv::StorageClass::IncomingCallableDataKHR: { + if (has_callable_data) { + return _.diag(SPV_ERROR_INVALID_DATA, entry_point) + << _.VkErrorID(4706) + << "Entry-point has more than one variable with the " + "IncomingCallableDataKHR storage class in the interface"; + } + has_callable_data = true; + break; + } + default: + break; + } + } + return SPV_SUCCESS; +} + } // namespace spv_result_t ValidateInterfaces(ValidationState_t& _) { @@ -605,6 +663,9 @@ spv_result_t ValidateInterfaces(ValidationState_t& _) { if (auto error = ValidateLocations(_, &inst)) { return error; } + if (auto error = ValidateStorageClass(_, &inst)) { + return error; + } } if (inst.opcode() == spv::Op::OpTypeVoid) break; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 31f7f6ef4c..6d764e8409 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -2173,14 +2173,20 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-RayPayloadKHR-04698); case 4699: return VUID_WRAP(VUID-StandaloneSpirv-IncomingRayPayloadKHR-04699); + case 4700: + return VUID_WRAP(VUID-StandaloneSpirv-IncomingRayPayloadKHR-04700); case 4701: return VUID_WRAP(VUID-StandaloneSpirv-HitAttributeKHR-04701); + case 4702: + return VUID_WRAP(VUID-StandaloneSpirv-HitAttributeKHR-04702); case 4703: return VUID_WRAP(VUID-StandaloneSpirv-HitAttributeKHR-04703); case 4704: return VUID_WRAP(VUID-StandaloneSpirv-CallableDataKHR-04704); case 4705: return VUID_WRAP(VUID-StandaloneSpirv-IncomingCallableDataKHR-04705); + case 4706: + return VUID_WRAP(VUID-StandaloneSpirv-IncomingCallableDataKHR-04706); case 7119: return VUID_WRAP(VUID-StandaloneSpirv-ShaderRecordBufferKHR-07119); case 4708: @@ -2239,6 +2245,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpTypeSampledImage-06671); case 6672: return VUID_WRAP(VUID-StandaloneSpirv-Location-06672); + case 6673: + return VUID_WRAP(VUID-StandaloneSpirv-OpVariable-06673); case 6674: return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-06674); case 6675: diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp index e32e237a51..ba0e95976c 100644 --- a/test/val/val_decoration_test.cpp +++ b/test/val/val_decoration_test.cpp @@ -3209,6 +3209,48 @@ TEST_F(ValidateDecorations, "statically used per shader entry point.")); } +TEST_F(ValidateDecorations, + VulkanMultiplePushConstantsSingleEntryPointInterfaceBad) { + std::string spirv = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %func1 "func1" %pc1 %pc2 + OpDecorate %struct Block + OpMemberDecorate %struct 0 Offset 0 + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %float = OpTypeFloat 32 + %int = OpTypeInt 32 0 + %int_0 = OpConstant %int 0 + %struct = OpTypeStruct %float + %ptr = OpTypePointer PushConstant %struct +%ptr_float = OpTypePointer PushConstant %float + %pc1 = OpVariable %ptr PushConstant + %pc2 = OpVariable %ptr PushConstant + %func1 = OpFunction %void None %voidfn + %label1 = OpLabel + %access1 = OpAccessChain %ptr_float %pc1 %int_0 + %load1 = OpLoad %float %access1 + OpReturn + OpFunctionEnd + %func2 = OpFunction %void None %voidfn + %label2 = OpLabel + %access2 = OpAccessChain %ptr_float %pc2 %int_0 + %load2 = OpLoad %float %access2 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpVariable-06673")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Entry-point has more than one variable with the " + "PushConstant storage class in the interface")); +} + TEST_F(ValidateDecorations, VulkanUniformMissingDescriptorSetBad) { std::string spirv = R"( OpCapability Shader diff --git a/test/val/val_ray_tracing_test.cpp b/test/val/val_ray_tracing_test.cpp index 58b9356cef..60f2f89117 100644 --- a/test/val/val_ray_tracing_test.cpp +++ b/test/val/val_ray_tracing_test.cpp @@ -578,6 +578,95 @@ OpTraceRayKHR %as %uint_1 %uint_1 %uint_1 %uint_1 %uint_1 %v3composite %float_0 "IncomingRayPayloadKHR")); } +TEST_F(ValidateRayTracing, InterfaceIncomingRayPayload) { + const std::string body = R"( +OpCapability RayTracingKHR +OpExtension "SPV_KHR_ray_tracing" +OpMemoryModel Logical GLSL450 +OpEntryPoint CallableKHR %main "main" %inData1 %inData2 +OpName %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%int = OpTypeInt 32 1 +%inData_ptr = OpTypePointer IncomingRayPayloadKHR %int +%inData1 = OpVariable %inData_ptr IncomingRayPayloadKHR +%inData2 = OpVariable %inData_ptr IncomingRayPayloadKHR +%main = OpFunction %void None %func +%label = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-IncomingRayPayloadKHR-04700")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Entry-point has more than one variable with the " + "IncomingRayPayloadKHR storage class in the interface")); +} + +TEST_F(ValidateRayTracing, InterfaceHitAttribute) { + const std::string body = R"( +OpCapability RayTracingKHR +OpExtension "SPV_KHR_ray_tracing" +OpMemoryModel Logical GLSL450 +OpEntryPoint CallableKHR %main "main" %inData1 %inData2 +OpName %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%int = OpTypeInt 32 1 +%inData_ptr = OpTypePointer HitAttributeKHR %int +%inData1 = OpVariable %inData_ptr HitAttributeKHR +%inData2 = OpVariable %inData_ptr HitAttributeKHR +%main = OpFunction %void None %func +%label = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-HitAttributeKHR-04702")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Entry-point has more than one variable with the " + "HitAttributeKHR storage class in the interface")); +} + +TEST_F(ValidateRayTracing, InterfaceIncomingCallableData) { + const std::string body = R"( +OpCapability RayTracingKHR +OpExtension "SPV_KHR_ray_tracing" +OpMemoryModel Logical GLSL450 +OpEntryPoint CallableKHR %main "main" %inData1 %inData2 +OpName %main "main" +%void = OpTypeVoid +%func = OpTypeFunction %void +%int = OpTypeInt 32 1 +%inData_ptr = OpTypePointer IncomingCallableDataKHR %int +%inData1 = OpVariable %inData_ptr IncomingCallableDataKHR +%inData2 = OpVariable %inData_ptr IncomingCallableDataKHR +%main = OpFunction %void None %func +%label = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, + ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-IncomingCallableDataKHR-04706")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Entry-point has more than one variable with the " + "IncomingCallableDataKHR storage class in the interface")); +} + } // namespace } // namespace val } // namespace spvtools From f9184c6501f7e349e0664d281ac93b1db9c1e5ad Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Wed, 14 Feb 2024 11:24:20 +0900 Subject: [PATCH 383/523] spirv-val: Revert Validate PhysicalStorageBuffer Stage Interface (#5575) --- source/val/validate_interfaces.cpp | 29 ------ source/val/validation_state.cpp | 2 - test/val/val_interfaces_test.cpp | 145 ++--------------------------- 3 files changed, 6 insertions(+), 170 deletions(-) diff --git a/source/val/validate_interfaces.cpp b/source/val/validate_interfaces.cpp index ef775a8524..54ebfd7885 100644 --- a/source/val/validate_interfaces.cpp +++ b/source/val/validate_interfaces.cpp @@ -46,29 +46,6 @@ bool is_interface_variable(const Instruction* inst, bool is_spv_1_4) { } } -// Special validation for varibles that are between shader stages -spv_result_t ValidateInputOutputInterfaceVariables(ValidationState_t& _, - const Instruction* var) { - auto var_pointer = _.FindDef(var->GetOperandAs(0)); - uint32_t pointer_id = var_pointer->GetOperandAs(2); - - const auto isPhysicalStorageBuffer = [](const Instruction* insn) { - return insn->opcode() == spv::Op::OpTypePointer && - insn->GetOperandAs(1) == - spv::StorageClass::PhysicalStorageBuffer; - }; - - if (_.ContainsType(pointer_id, isPhysicalStorageBuffer)) { - return _.diag(SPV_ERROR_INVALID_ID, var) - << _.VkErrorID(9557) << "Input/Output interface variable id <" - << var->id() - << "> contains a PhysicalStorageBuffer pointer, which is not " - "allowed. If you want to interface shader stages with a " - "PhysicalStorageBuffer, cast to a uint64 or uvec2 instead."; - } - return SPV_SUCCESS; -} - // Checks that \c var is listed as an interface in all the entry points that use // it. spv_result_t check_interface_variable(ValidationState_t& _, @@ -128,12 +105,6 @@ spv_result_t check_interface_variable(ValidationState_t& _, } } - if (var->GetOperandAs(2) == spv::StorageClass::Input || - var->GetOperandAs(2) == spv::StorageClass::Output) { - if (auto error = ValidateInputOutputInterfaceVariables(_, var)) - return error; - } - return SPV_SUCCESS; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 6d764e8409..971e031558 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -2307,8 +2307,6 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-08722); case 8973: return VUID_WRAP(VUID-StandaloneSpirv-Pointer-08973); - case 9557: - return VUID_WRAP(VUID-StandaloneSpirv-Input-09557); default: return ""; // unknown id } diff --git a/test/val/val_interfaces_test.cpp b/test/val/val_interfaces_test.cpp index 45b5f20663..d75c20cf29 100644 --- a/test/val/val_interfaces_test.cpp +++ b/test/val/val_interfaces_test.cpp @@ -1599,7 +1599,7 @@ TEST_F(ValidateInterfacesTest, InvalidLocationTypePointer) { HasSubstr("Invalid type to assign a location")); } -TEST_F(ValidateInterfacesTest, PhysicalStorageBufferPointer) { +TEST_F(ValidateInterfacesTest, ValidLocationTypePhysicalStorageBufferPointer) { const std::string text = R"( OpCapability Shader OpCapability PhysicalStorageBufferAddresses @@ -1608,138 +1608,10 @@ OpEntryPoint Vertex %main "main" %var OpDecorate %var Location 0 OpDecorate %var RestrictPointer %void = OpTypeVoid -%uint = OpTypeInt 32 0 -%psb_ptr = OpTypePointer PhysicalStorageBuffer %uint -%in_ptr = OpTypePointer Input %psb_ptr -%var = OpVariable %in_ptr Input -%void_fn = OpTypeFunction %void -%main = OpFunction %void None %void_fn -%entry = OpLabel -OpReturn -OpFunctionEnd -)"; - CompileSuccessfully(text, SPV_ENV_VULKAN_1_3); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_3)); - EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-StandaloneSpirv-Input-09557")); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Input/Output interface variable id <2> contains a " - "PhysicalStorageBuffer pointer, which is not allowed")); -} - -TEST_F(ValidateInterfacesTest, PhysicalStorageBufferPointerArray) { - const std::string text = R"( -OpCapability Shader -OpCapability PhysicalStorageBufferAddresses -OpMemoryModel PhysicalStorageBuffer64 GLSL450 -OpEntryPoint Vertex %main "main" %var -OpDecorate %var Location 0 -OpDecorate %var RestrictPointer -%void = OpTypeVoid -%uint = OpTypeInt 32 0 -%uint_3 = OpConstant %uint 3 -%psb_ptr = OpTypePointer PhysicalStorageBuffer %uint -%array = OpTypeArray %psb_ptr %uint_3 -%in_ptr = OpTypePointer Input %array -%var = OpVariable %in_ptr Input -%void_fn = OpTypeFunction %void -%main = OpFunction %void None %void_fn -%entry = OpLabel -OpReturn -OpFunctionEnd -)"; - CompileSuccessfully(text, SPV_ENV_VULKAN_1_3); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_3)); - EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-StandaloneSpirv-Input-09557")); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Input/Output interface variable id <2> contains a " - "PhysicalStorageBuffer pointer, which is not allowed")); -} - -TEST_F(ValidateInterfacesTest, PhysicalStorageBufferPointerStruct) { - const std::string text = R"( -OpCapability Shader -OpCapability PhysicalStorageBufferAddresses -OpMemoryModel PhysicalStorageBuffer64 GLSL450 -OpEntryPoint Vertex %main "main" %var -OpDecorate %var Location 0 -OpDecorate %var RestrictPointer -%void = OpTypeVoid -%int = OpTypeInt 32 1 -OpTypeForwardPointer %psb_ptr PhysicalStorageBuffer -%struct_0 = OpTypeStruct %int %psb_ptr -%struct_1 = OpTypeStruct %int %int -%psb_ptr = OpTypePointer PhysicalStorageBuffer %struct_1 -%in_ptr = OpTypePointer Input %struct_0 -%var = OpVariable %in_ptr Input -%void_fn = OpTypeFunction %void -%main = OpFunction %void None %void_fn -%entry = OpLabel -OpReturn -OpFunctionEnd -)"; - CompileSuccessfully(text, SPV_ENV_VULKAN_1_3); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_3)); - EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-StandaloneSpirv-Input-09557")); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Input/Output interface variable id <2> contains a " - "PhysicalStorageBuffer pointer, which is not allowed")); -} - -TEST_F(ValidateInterfacesTest, PhysicalStorageBufferPointerArrayOfStruct) { - const std::string text = R"( -OpCapability Shader -OpCapability PhysicalStorageBufferAddresses -OpMemoryModel PhysicalStorageBuffer64 GLSL450 -OpEntryPoint Vertex %main "main" %var -OpDecorate %var Location 0 -OpDecorate %var RestrictPointer -%void = OpTypeVoid -%int = OpTypeInt 32 1 -%uint = OpTypeInt 32 0 -%uint_3 = OpConstant %uint 3 -OpTypeForwardPointer %psb_ptr PhysicalStorageBuffer -%array_1 = OpTypeArray %psb_ptr %uint_3 -%struct_0 = OpTypeStruct %int %array_1 - %struct_1 = OpTypeStruct %int %int -%psb_ptr = OpTypePointer PhysicalStorageBuffer %struct_1 -%array_0 = OpTypeArray %struct_0 %uint_3 -%in_ptr = OpTypePointer Input %array_0 -%var = OpVariable %in_ptr Input -%void_fn = OpTypeFunction %void -%main = OpFunction %void None %void_fn -%entry = OpLabel -OpReturn -OpFunctionEnd -)"; - CompileSuccessfully(text, SPV_ENV_VULKAN_1_3); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_3)); - EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-StandaloneSpirv-Input-09557")); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Input/Output interface variable id <2> contains a " - "PhysicalStorageBuffer pointer, which is not allowed")); -} - -TEST_F(ValidateInterfacesTest, PhysicalStorageBufferPointerNestedStruct) { - const std::string text = R"( -OpCapability Shader -OpCapability PhysicalStorageBufferAddresses -OpMemoryModel PhysicalStorageBuffer64 GLSL450 -OpEntryPoint Vertex %main "main" %var -OpDecorate %var Location 0 -OpDecorate %var RestrictPointer -%void = OpTypeVoid -%int = OpTypeInt 32 1 -OpTypeForwardPointer %psb_ptr PhysicalStorageBuffer -%struct_0 = OpTypeStruct %int %psb_ptr -%struct_1 = OpTypeStruct %int %int -%psb_ptr = OpTypePointer PhysicalStorageBuffer %struct_1 -%struct_2 = OpTypeStruct %int %struct_0 -%in_ptr = OpTypePointer Input %struct_2 -%var = OpVariable %in_ptr Input +%int = OpTypeInt 32 0 +%ptr = OpTypePointer PhysicalStorageBuffer %int +%ptr2 = OpTypePointer Input %ptr +%var = OpVariable %ptr2 Input %void_fn = OpTypeFunction %void %main = OpFunction %void None %void_fn %entry = OpLabel @@ -1747,12 +1619,7 @@ OpReturn OpFunctionEnd )"; CompileSuccessfully(text, SPV_ENV_VULKAN_1_3); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_3)); - EXPECT_THAT(getDiagnosticString(), - AnyVUID("VUID-StandaloneSpirv-Input-09557")); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Input/Output interface variable id <2> contains a " - "PhysicalStorageBuffer pointer, which is not allowed")); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3)); } } // namespace From 7604147c25d68ea26e178ada44f401bf19712d76 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 14 Feb 2024 13:08:25 -0500 Subject: [PATCH 384/523] [OPT] Add removed unused interface var pass to legalization passes (#5579) DXC does not do a good job of recognizing which variables need to be on the entry point for which functions. This is because it does not want to have to walk the call tree to determine which instructions are reachable from which entry points. This is also useful if the same input variable gets used from two different shader, but the uses in one get optimized away. Will parially fix https://github.com/microsoft/DirectXShaderCompiler/issues/4621. Will not fix code compiled with -fcgl. --- source/opt/optimizer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index 429a6cba85..c4c2b0f554 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -167,6 +167,7 @@ Optimizer& Optimizer::RegisterLegalizationPasses(bool preserve_interface) { .RegisterPass(CreateDeadInsertElimPass()) .RegisterPass(CreateReduceLoadSizePass()) .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) + .RegisterPass(CreateRemoveUnusedInterfaceVariablesPass()) .RegisterPass(CreateInterpolateFixupPass()) .RegisterPass(CreateInvocationInterlockPlacementPass()); } From 11afeb4bb19be375fe5aad968e5f6588ee2ee7d8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 14 Feb 2024 18:25:53 +0000 Subject: [PATCH 385/523] roll deps (#5576) * Roll external/googletest/ b75ecf1be..6eb225cb8 (1 commit) https://github.com/google/googletest/compare/b75ecf1bed2f...6eb225cb8823 $ git log b75ecf1be..6eb225cb8 --date=short --no-merges --format='%ad %ae %s' 2024-02-13 absl-team Add anchor for expectation ordering note Created with: roll-dep external/googletest * Roll external/re2/ ab7c5918b..b4c6fe091 (2 commits) https://github.com/google/re2/compare/ab7c5918b418...b4c6fe091b74 $ git log ab7c5918b..b4c6fe091 --date=short --no-merges --format='%ad %ae %s' 2024-02-13 junyer Bump version of `p0deje/setup-bazel` to address warnings. 2024-02-13 junyer Try using `p0deje/setup-bazel` everywhere. 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 50fd6c194b..2cd4493de5 100644 --- a/DEPS +++ b/DEPS @@ -7,12 +7,12 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': 'b75ecf1bed2fcd416b66c86cb6fe79122abf132e', + 'googletest_revision': '6eb225cb8823c254d3a64549f2e1efad05c01757', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': 'ab7c5918b418428ed17dbe564e0d8402bd7d743d', + 're2_revision': 'b4c6fe091b74b65f706ff9c9ff369b396c2a3177', 'spirv_headers_revision': 'd3c2a6fa95ad463ca8044d7fc45557db381a6a64', } From 55cb3989ec116b3f26dab421f91acc8cf600e6b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 14 Feb 2024 13:53:33 -0500 Subject: [PATCH 386/523] build(deps): bump the github-actions group with 1 update (#5578) Bumps the github-actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action). Updates `github/codeql-action` from 3.24.0 to 3.24.1 - [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/e8893c57a1f3a2b659b6b55564fdfdbbd2982911...e675ced7a7522a761fc9c8eb26682c8b27c42b2b) --- 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 f952197a9e..83a9a25f2a 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@e8893c57a1f3a2b659b6b55564fdfdbbd2982911 # v3.24.0 + uses: github/codeql-action/upload-sarif@e675ced7a7522a761fc9c8eb26682c8b27c42b2b # v3.24.1 with: sarif_file: results.sarif From b0a5c4ac12b742086ffb16e2ba0ad4903450ae1d Mon Sep 17 00:00:00 2001 From: Jeff Bolz Date: Wed, 14 Feb 2024 14:58:12 -0600 Subject: [PATCH 387/523] SPV_NV_shader_atomic_fp16_vector (#5581) --- DEPS | 2 +- source/val/validate_atomics.cpp | 50 +++++++---- source/val/validate_image.cpp | 19 ++++- source/val/validation_state.cpp | 14 ++++ source/val/validation_state.h | 1 + test/val/val_atomics_test.cpp | 142 +++++++++++++++++++++++++++++++- 6 files changed, 206 insertions(+), 22 deletions(-) diff --git a/DEPS b/DEPS index 2cd4493de5..136f5da969 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': 'b4c6fe091b74b65f706ff9c9ff369b396c2a3177', - 'spirv_headers_revision': 'd3c2a6fa95ad463ca8044d7fc45557db381a6a64', + 'spirv_headers_revision': '05cc486580771e4fa7ddc89f5c9ee1e97382689a', } deps = { diff --git a/source/val/validate_atomics.cpp b/source/val/validate_atomics.cpp index b745a9ec1d..8ddef17896 100644 --- a/source/val/validate_atomics.cpp +++ b/source/val/validate_atomics.cpp @@ -144,12 +144,13 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { case spv::Op::OpAtomicFlagClear: { const uint32_t result_type = inst->type_id(); - // All current atomics only are scalar result // Validate return type first so can just check if pointer type is same // (if applicable) if (HasReturnType(opcode)) { if (HasOnlyFloatReturnType(opcode) && - !_.IsFloatScalarType(result_type)) { + (!(_.HasCapability(spv::Capability::AtomicFloat16VectorNV) && + _.IsFloat16Vector2Or4Type(result_type)) && + !_.IsFloatScalarType(result_type))) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << spvOpcodeString(opcode) << ": expected Result Type to be float scalar type"; @@ -160,6 +161,9 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { << ": expected Result Type to be integer scalar type"; } else if (HasIntOrFloatReturnType(opcode) && !_.IsFloatScalarType(result_type) && + !(opcode == spv::Op::OpAtomicExchange && + _.HasCapability(spv::Capability::AtomicFloat16VectorNV) && + _.IsFloat16Vector2Or4Type(result_type)) && !_.IsIntScalarType(result_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << spvOpcodeString(opcode) @@ -222,12 +226,21 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { if (opcode == spv::Op::OpAtomicFAddEXT) { // result type being float checked already - if ((_.GetBitWidth(result_type) == 16) && - (!_.HasCapability(spv::Capability::AtomicFloat16AddEXT))) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": float add atomics require the AtomicFloat32AddEXT " - "capability"; + if (_.GetBitWidth(result_type) == 16) { + if (_.IsFloat16Vector2Or4Type(result_type)) { + if (!_.HasCapability(spv::Capability::AtomicFloat16VectorNV)) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": float vector atomics require the " + "AtomicFloat16VectorNV capability"; + } else { + if (!_.HasCapability(spv::Capability::AtomicFloat16AddEXT)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": float add atomics require the AtomicFloat32AddEXT " + "capability"; + } + } } if ((_.GetBitWidth(result_type) == 32) && (!_.HasCapability(spv::Capability::AtomicFloat32AddEXT))) { @@ -245,12 +258,21 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { } } else if (opcode == spv::Op::OpAtomicFMinEXT || opcode == spv::Op::OpAtomicFMaxEXT) { - if ((_.GetBitWidth(result_type) == 16) && - (!_.HasCapability(spv::Capability::AtomicFloat16MinMaxEXT))) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << spvOpcodeString(opcode) - << ": float min/max atomics require the " - "AtomicFloat16MinMaxEXT capability"; + if (_.GetBitWidth(result_type) == 16) { + if (_.IsFloat16Vector2Or4Type(result_type)) { + if (!_.HasCapability(spv::Capability::AtomicFloat16VectorNV)) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": float vector atomics require the " + "AtomicFloat16VectorNV capability"; + } else { + if (!_.HasCapability(spv::Capability::AtomicFloat16MinMaxEXT)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << spvOpcodeString(opcode) + << ": float min/max atomics require the " + "AtomicFloat16MinMaxEXT capability"; + } + } } if ((_.GetBitWidth(result_type) == 32) && (!_.HasCapability(spv::Capability::AtomicFloat32MinMaxEXT))) { diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 39eeb4bd7e..46a32f2411 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -1118,7 +1118,10 @@ spv_result_t ValidateImageTexelPointer(ValidationState_t& _, const auto ptr_type = result_type->GetOperandAs(2); const auto ptr_opcode = _.GetIdOpcode(ptr_type); if (ptr_opcode != spv::Op::OpTypeInt && ptr_opcode != spv::Op::OpTypeFloat && - ptr_opcode != spv::Op::OpTypeVoid) { + ptr_opcode != spv::Op::OpTypeVoid && + !(ptr_opcode == spv::Op::OpTypeVector && + _.HasCapability(spv::Capability::AtomicFloat16VectorNV) && + _.IsFloat16Vector2Or4Type(ptr_type))) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Result Type to be OpTypePointer whose Type operand " "must be a scalar numerical type or OpTypeVoid"; @@ -1142,7 +1145,14 @@ spv_result_t ValidateImageTexelPointer(ValidationState_t& _, << "Corrupt image type definition"; } - if (info.sampled_type != ptr_type) { + if (info.sampled_type != ptr_type && + !(_.HasCapability(spv::Capability::AtomicFloat16VectorNV) && + _.IsFloat16Vector2Or4Type(ptr_type) && + _.GetIdOpcode(info.sampled_type) == spv::Op::OpTypeFloat && + ((_.GetDimension(ptr_type) == 2 && + info.format == spv::ImageFormat::Rg16f) || + (_.GetDimension(ptr_type) == 4 && + info.format == spv::ImageFormat::Rgba16f)))) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Image 'Sampled Type' to be the same as the Type " "pointed to by Result Type"; @@ -1213,7 +1223,10 @@ spv_result_t ValidateImageTexelPointer(ValidationState_t& _, (info.format != spv::ImageFormat::R64ui) && (info.format != spv::ImageFormat::R32f) && (info.format != spv::ImageFormat::R32i) && - (info.format != spv::ImageFormat::R32ui)) { + (info.format != spv::ImageFormat::R32ui) && + !((info.format == spv::ImageFormat::Rg16f || + info.format == spv::ImageFormat::Rgba16f) && + _.HasCapability(spv::Capability::AtomicFloat16VectorNV))) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << _.VkErrorID(4658) << "Expected the Image Format in Image to be R64i, R64ui, R32f, " diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 971e031558..25b374de11 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -954,6 +954,20 @@ bool ValidationState_t::IsFloatVectorType(uint32_t id) const { return false; } +bool ValidationState_t::IsFloat16Vector2Or4Type(uint32_t id) const { + const Instruction* inst = FindDef(id); + assert(inst); + + if (inst->opcode() == spv::Op::OpTypeVector) { + uint32_t vectorDim = GetDimension(id); + return IsFloatScalarType(GetComponentType(id)) && + (vectorDim == 2 || vectorDim == 4) && + (GetBitWidth(GetComponentType(id)) == 16); + } + + return false; +} + bool ValidationState_t::IsFloatScalarOrVectorType(uint32_t id) const { const Instruction* inst = FindDef(id); if (!inst) { diff --git a/source/val/validation_state.h b/source/val/validation_state.h index 0cd6c789bb..46a8cbfa60 100644 --- a/source/val/validation_state.h +++ b/source/val/validation_state.h @@ -602,6 +602,7 @@ class ValidationState_t { bool IsVoidType(uint32_t id) const; bool IsFloatScalarType(uint32_t id) const; bool IsFloatVectorType(uint32_t id) const; + bool IsFloat16Vector2Or4Type(uint32_t id) const; bool IsFloatScalarOrVectorType(uint32_t id) const; bool IsFloatMatrixType(uint32_t id) const; bool IsIntScalarType(uint32_t id) const; diff --git a/test/val/val_atomics_test.cpp b/test/val/val_atomics_test.cpp index b266ad6665..0f65634a95 100644 --- a/test/val/val_atomics_test.cpp +++ b/test/val/val_atomics_test.cpp @@ -318,7 +318,8 @@ TEST_F(ValidateAtomics, AtomicAddFloatVulkan) { EXPECT_THAT( getDiagnosticString(), HasSubstr("Opcode AtomicFAddEXT requires one of these capabilities: " - "AtomicFloat32AddEXT AtomicFloat64AddEXT AtomicFloat16AddEXT")); + "AtomicFloat16VectorNV AtomicFloat32AddEXT AtomicFloat64AddEXT " + "AtomicFloat16AddEXT")); } TEST_F(ValidateAtomics, AtomicMinFloatVulkan) { @@ -331,7 +332,8 @@ TEST_F(ValidateAtomics, AtomicMinFloatVulkan) { EXPECT_THAT( getDiagnosticString(), HasSubstr("Opcode AtomicFMinEXT requires one of these capabilities: " - "AtomicFloat32MinMaxEXT AtomicFloat64MinMaxEXT AtomicFloat16MinMaxEXT")); + "AtomicFloat16VectorNV AtomicFloat32MinMaxEXT " + "AtomicFloat64MinMaxEXT AtomicFloat16MinMaxEXT")); } TEST_F(ValidateAtomics, AtomicMaxFloatVulkan) { @@ -343,8 +345,10 @@ TEST_F(ValidateAtomics, AtomicMaxFloatVulkan) { ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), - HasSubstr("Opcode AtomicFMaxEXT requires one of these capabilities: " - "AtomicFloat32MinMaxEXT AtomicFloat64MinMaxEXT AtomicFloat16MinMaxEXT")); + HasSubstr( + "Opcode AtomicFMaxEXT requires one of these capabilities: " + "AtomicFloat16VectorNV AtomicFloat32MinMaxEXT AtomicFloat64MinMaxEXT " + "AtomicFloat16MinMaxEXT")); } TEST_F(ValidateAtomics, AtomicAddFloatVulkanWrongType1) { @@ -2713,6 +2717,136 @@ TEST_F(ValidateAtomics, IIncrementBadPointerDataType) { "value of type Result Type")); } +TEST_F(ValidateAtomics, AtomicFloat16VectorSuccess) { + const std::string definitions = R"( +%f16 = OpTypeFloat 16 +%f16vec2 = OpTypeVector %f16 2 +%f16vec4 = OpTypeVector %f16 4 + +%f16_1 = OpConstant %f16 1 +%f16vec2_1 = OpConstantComposite %f16vec2 %f16_1 %f16_1 +%f16vec4_1 = OpConstantComposite %f16vec4 %f16_1 %f16_1 %f16_1 %f16_1 + +%f16vec2_ptr = OpTypePointer Workgroup %f16vec2 +%f16vec4_ptr = OpTypePointer Workgroup %f16vec4 +%f16vec2_var = OpVariable %f16vec2_ptr Workgroup +%f16vec4_var = OpVariable %f16vec4_ptr Workgroup +)"; + + const std::string body = R"( +%val3 = OpAtomicFMinEXT %f16vec2 %f16vec2_var %device %relaxed %f16vec2_1 +%val4 = OpAtomicFMaxEXT %f16vec2 %f16vec2_var %device %relaxed %f16vec2_1 +%val8 = OpAtomicFAddEXT %f16vec2 %f16vec2_var %device %relaxed %f16vec2_1 +%val9 = OpAtomicExchange %f16vec2 %f16vec2_var %device %relaxed %f16vec2_1 + +%val11 = OpAtomicFMinEXT %f16vec4 %f16vec4_var %device %relaxed %f16vec4_1 +%val12 = OpAtomicFMaxEXT %f16vec4 %f16vec4_var %device %relaxed %f16vec4_1 +%val18 = OpAtomicFAddEXT %f16vec4 %f16vec4_var %device %relaxed %f16vec4_1 +%val19 = OpAtomicExchange %f16vec4 %f16vec4_var %device %relaxed %f16vec4_1 + +)"; + + CompileSuccessfully(GenerateShaderComputeCode( + body, + "OpCapability Float16\n" + "OpCapability AtomicFloat16VectorNV\n" + "OpExtension \"SPV_NV_shader_atomic_fp16_vector\"\n", + definitions), + SPV_ENV_VULKAN_1_0); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + +static constexpr char Float16Vector3Defs[] = R"( +%f16 = OpTypeFloat 16 +%f16vec3 = OpTypeVector %f16 3 + +%f16_1 = OpConstant %f16 1 +%f16vec3_1 = OpConstantComposite %f16vec3 %f16_1 %f16_1 %f16_1 + +%f16vec3_ptr = OpTypePointer Workgroup %f16vec3 +%f16vec3_var = OpVariable %f16vec3_ptr Workgroup +)"; + +TEST_F(ValidateAtomics, AtomicFloat16Vector3MinFail) { + const std::string definitions = Float16Vector3Defs; + + const std::string body = R"( +%val11 = OpAtomicFMinEXT %f16vec3 %f16vec3_var %device %relaxed %f16vec3_1 +)"; + + CompileSuccessfully(GenerateShaderComputeCode( + body, + "OpCapability Float16\n" + "OpCapability AtomicFloat16VectorNV\n" + "OpExtension \"SPV_NV_shader_atomic_fp16_vector\"\n", + definitions), + SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("AtomicFMinEXT: expected Result Type to be float scalar type")); +} + +TEST_F(ValidateAtomics, AtomicFloat16Vector3MaxFail) { + const std::string definitions = Float16Vector3Defs; + + const std::string body = R"( +%val12 = OpAtomicFMaxEXT %f16vec3 %f16vec3_var %device %relaxed %f16vec3_1 +)"; + + CompileSuccessfully(GenerateShaderComputeCode( + body, + "OpCapability Float16\n" + "OpCapability AtomicFloat16VectorNV\n" + "OpExtension \"SPV_NV_shader_atomic_fp16_vector\"\n", + definitions), + SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("AtomicFMaxEXT: expected Result Type to be float scalar type")); +} + +TEST_F(ValidateAtomics, AtomicFloat16Vector3AddFail) { + const std::string definitions = Float16Vector3Defs; + + const std::string body = R"( +%val18 = OpAtomicFAddEXT %f16vec3 %f16vec3_var %device %relaxed %f16vec3_1 +)"; + + CompileSuccessfully(GenerateShaderComputeCode( + body, + "OpCapability Float16\n" + "OpCapability AtomicFloat16VectorNV\n" + "OpExtension \"SPV_NV_shader_atomic_fp16_vector\"\n", + definitions), + SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("AtomicFAddEXT: expected Result Type to be float scalar type")); +} + +TEST_F(ValidateAtomics, AtomicFloat16Vector3ExchangeFail) { + const std::string definitions = Float16Vector3Defs; + + const std::string body = R"( +%val19 = OpAtomicExchange %f16vec3 %f16vec3_var %device %relaxed %f16vec3_1 +)"; + + CompileSuccessfully(GenerateShaderComputeCode( + body, + "OpCapability Float16\n" + "OpCapability AtomicFloat16VectorNV\n" + "OpExtension \"SPV_NV_shader_atomic_fp16_vector\"\n", + definitions), + SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("AtomicExchange: expected Result Type to be integer or " + "float scalar type")); +} + } // namespace } // namespace val } // namespace spvtools From 16af142c15e789040f82acf4f8b5e2f451ba02c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Feb 2024 12:04:01 -0500 Subject: [PATCH 388/523] build(deps): bump the github-actions group with 1 update (#5586) Bumps the github-actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action). Updates `github/codeql-action` from 3.24.1 to 3.24.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/e675ced7a7522a761fc9c8eb26682c8b27c42b2b...379614612a29c9e28f31f39a59013eb8012a51f0) --- 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 83a9a25f2a..9fb86eafbe 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@e675ced7a7522a761fc9c8eb26682c8b27c42b2b # v3.24.1 + uses: github/codeql-action/upload-sarif@379614612a29c9e28f31f39a59013eb8012a51f0 # v3.24.3 with: sarif_file: results.sarif From 7da2c941f022a5a61d49dae339cc68fff12f09af Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Fri, 16 Feb 2024 15:09:08 -0800 Subject: [PATCH 389/523] Update WORKSPACE (#5588) * Update WORKSPACE Same purpose as #5585, but a bit less intrusive perhaps. * Update WORKSPACE Add `rules_license`, needed by `platforms`. --- WORKSPACE | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/WORKSPACE b/WORKSPACE index 589dc12202..8f49808900 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -6,6 +6,26 @@ http_archive( urls = ["https://github.com/bazelbuild/bazel-skylib/archive/main.zip"], ) +# Override bazel's default `platforms`, since googletest requires a newer version. This can be removed once we use a newer Bazel version. +http_archive( + name = "platforms", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz", + "https://github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz", + ], + sha256 = "8150406605389ececb6da07cbcb509d5637a3ab9a24bc69b1101531367d89d74", +) + +# `platforms` needs `rules_license` on Windows. This can be removed if `platforms` above is removed. +http_archive( + name = "rules_license", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/rules_license/releases/download/0.0.8/rules_license-0.0.8.tar.gz", + "https://github.com/bazelbuild/rules_license/releases/download/0.0.8/rules_license-0.0.8.tar.gz", + ], + sha256 = "241b06f3097fd186ff468832150d6cc142247dc42a32aaefb56d0099895fd229", +) + local_repository( name = "spirv_headers", path = "external/spirv-headers", From dc6676445be97ab19d8191fee019af62e2aaf774 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 16 Feb 2024 19:28:03 -0500 Subject: [PATCH 390/523] Roll external/googletest/ 6eb225cb8..5df0241ea (2 commits) (#5583) * Roll external/googletest/ 6eb225cb8..5df0241ea (2 commits) https://github.com/google/googletest/compare/6eb225cb8823...5df0241ea488 $ git log 6eb225cb8..5df0241ea --date=short --no-merges --format='%ad %ae %s' 2024-02-14 absl-team gtest.h: add IWYU export pragmas 2024-02-13 absl-team Support Fuchsia target builds. Created with: roll-dep external/googletest * Roll external/re2/ b4c6fe091..ed9fc269e (1 commit) https://github.com/google/re2/compare/b4c6fe091b74...ed9fc269e2fd $ git log b4c6fe091..ed9fc269e --date=short --no-merges --format='%ad %ae %s' 2024-02-15 junyer Update @apple_support to version 1.12.0. Created with: roll-dep external/re2 --------- Co-authored-by: GitHub Actions[bot] <> Co-authored-by: Cassandra Beckley --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 136f5da969..323728a34c 100644 --- a/DEPS +++ b/DEPS @@ -7,12 +7,12 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '6eb225cb8823c254d3a64549f2e1efad05c01757', + 'googletest_revision': '5df0241ea4880e5a846775d3efc8b873f7b36c31', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': 'b4c6fe091b74b65f706ff9c9ff369b396c2a3177', + 're2_revision': 'ed9fc269e2fdb299afe59e912928d31ad3fdcf7d', 'spirv_headers_revision': '05cc486580771e4fa7ddc89f5c9ee1e97382689a', } From 1b643eac5d4062bbec48b912a1332e6909802479 Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Thu, 22 Feb 2024 07:52:13 +0900 Subject: [PATCH 391/523] spirv-val: Make Constant evaluation consistent (#5587) Bring 64-bit evaluation in line with 32-bit evaluation. --- source/val/validate_builtins.cpp | 2 +- source/val/validate_composites.cpp | 4 +-- source/val/validate_extensions.cpp | 4 +-- source/val/validate_image.cpp | 4 +-- source/val/validate_memory.cpp | 17 +++++------ source/val/validate_non_uniform.cpp | 13 +++++--- source/val/validate_type.cpp | 43 +++++--------------------- source/val/validation_state.cpp | 47 +++++++++++++++++++++++------ source/val/validation_state.h | 12 +++++--- test/val/val_id_test.cpp | 2 +- 10 files changed, 78 insertions(+), 70 deletions(-) diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp index 42fbc52a78..a7e9942a0f 100644 --- a/source/val/validate_builtins.cpp +++ b/source/val/validate_builtins.cpp @@ -1120,7 +1120,7 @@ spv_result_t BuiltInsValidator::ValidateF32ArrHelper( if (num_components != 0) { uint64_t actual_num_components = 0; - if (!_.GetConstantValUint64(type_inst->word(3), &actual_num_components)) { + if (!_.EvalConstantValUint64(type_inst->word(3), &actual_num_components)) { assert(0 && "Array type definition is corrupt"); } if (actual_num_components != num_components) { diff --git a/source/val/validate_composites.cpp b/source/val/validate_composites.cpp index ed043b688a..26486dac70 100644 --- a/source/val/validate_composites.cpp +++ b/source/val/validate_composites.cpp @@ -94,7 +94,7 @@ spv_result_t GetExtractInsertValueType(ValidationState_t& _, break; } - if (!_.GetConstantValUint64(type_inst->word(3), &array_size)) { + if (!_.EvalConstantValUint64(type_inst->word(3), &array_size)) { assert(0 && "Array type definition is corrupt"); } if (component_index >= array_size) { @@ -289,7 +289,7 @@ spv_result_t ValidateCompositeConstruct(ValidationState_t& _, } uint64_t array_size = 0; - if (!_.GetConstantValUint64(array_inst->word(3), &array_size)) { + if (!_.EvalConstantValUint64(array_inst->word(3), &array_size)) { assert(0 && "Array type definition is corrupt"); } diff --git a/source/val/validate_extensions.cpp b/source/val/validate_extensions.cpp index 0334b60640..7b73c9c6e2 100644 --- a/source/val/validate_extensions.cpp +++ b/source/val/validate_extensions.cpp @@ -3100,7 +3100,7 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { uint32_t vector_count = inst->word(6); uint64_t const_val; - if (!_.GetConstantValUint64(vector_count, &const_val)) { + if (!_.EvalConstantValUint64(vector_count, &const_val)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": Vector Count must be 32-bit integer OpConstant"; @@ -3191,7 +3191,7 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { uint32_t component_count = inst->word(6); if (vulkanDebugInfo) { uint64_t const_val; - if (!_.GetConstantValUint64(component_count, &const_val)) { + if (!_.EvalConstantValUint64(component_count, &const_val)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": Component Count must be 32-bit integer OpConstant"; diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 46a32f2411..543f345ecd 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -495,7 +495,7 @@ spv_result_t ValidateImageOperands(ValidationState_t& _, } uint64_t array_size = 0; - if (!_.GetConstantValUint64(type_inst->word(3), &array_size)) { + if (!_.EvalConstantValUint64(type_inst->word(3), &array_size)) { assert(0 && "Array type definition is corrupt"); } @@ -1210,7 +1210,7 @@ spv_result_t ValidateImageTexelPointer(ValidationState_t& _, if (info.multisampled == 0) { uint64_t ms = 0; - if (!_.GetConstantValUint64(inst->GetOperandAs(4), &ms) || + if (!_.EvalConstantValUint64(inst->GetOperandAs(4), &ms) || ms != 0) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Sample for Image with MS 0 to be a valid for " diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index 5b25eeb3c7..41dd71e9ff 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -1374,22 +1374,18 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, case spv::Op::OpTypeStruct: { // In case of structures, there is an additional constraint on the // index: the index must be an OpConstant. - if (spv::Op::OpConstant != cur_word_instr->opcode()) { + int64_t cur_index; + if (!_.EvalConstantValInt64(cur_word, &cur_index)) { return _.diag(SPV_ERROR_INVALID_ID, cur_word_instr) << "The passed to " << instr_name << " to index into a " "structure must be an OpConstant."; } - // Get the index value from the OpConstant (word 3 of OpConstant). - // OpConstant could be a signed integer. But it's okay to treat it as - // unsigned because a negative constant int would never be seen as - // correct as a struct offset, since structs can't have more than 2 - // billion members. - const uint32_t cur_index = cur_word_instr->word(3); + // The index points to the struct member we want, therefore, the index // should be less than the number of struct members. - const uint32_t num_struct_members = - static_cast(type_pointee->words().size() - 2); + const int64_t num_struct_members = + static_cast(type_pointee->words().size() - 2); if (cur_index >= num_struct_members) { return _.diag(SPV_ERROR_INVALID_ID, cur_word_instr) << "Index is out of bounds: " << instr_name @@ -1400,7 +1396,8 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, << num_struct_members - 1 << "."; } // Struct members IDs start at word 2 of OpTypeStruct. - auto structMemberId = type_pointee->word(cur_index + 2); + const size_t word_index = static_cast(cur_index) + 2; + auto structMemberId = type_pointee->word(word_index); type_pointee = _.FindDef(structMemberId); break; } diff --git a/source/val/validate_non_uniform.cpp b/source/val/validate_non_uniform.cpp index 74449e9dc0..75967d2ff9 100644 --- a/source/val/validate_non_uniform.cpp +++ b/source/val/validate_non_uniform.cpp @@ -389,20 +389,25 @@ spv_result_t ValidateGroupNonUniformRotateKHR(ValidationState_t& _, if (inst->words().size() > 6) { const uint32_t cluster_size_op_id = inst->GetOperandAs(5); - const uint32_t cluster_size_type = _.GetTypeId(cluster_size_op_id); + const Instruction* cluster_size_inst = _.FindDef(cluster_size_op_id); + const uint32_t cluster_size_type = + cluster_size_inst ? cluster_size_inst->type_id() : 0; if (!_.IsUnsignedIntScalarType(cluster_size_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "ClusterSize must be a scalar of integer type, whose " "Signedness operand is 0."; } - uint64_t cluster_size; - if (!_.GetConstantValUint64(cluster_size_op_id, &cluster_size)) { + if (!spvOpcodeIsConstant(cluster_size_inst->opcode())) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "ClusterSize must come from a constant instruction."; } - if ((cluster_size == 0) || ((cluster_size & (cluster_size - 1)) != 0)) { + uint64_t cluster_size; + const bool valid_const = + _.EvalConstantValUint64(cluster_size_op_id, &cluster_size); + if (valid_const && + ((cluster_size == 0) || ((cluster_size & (cluster_size - 1)) != 0))) { return _.diag(SPV_WARNING, inst) << "Behavior is undefined unless ClusterSize is at least 1 and a " "power of 2."; diff --git a/source/val/validate_type.cpp b/source/val/validate_type.cpp index 7edd12ffaf..cb26a527cc 100644 --- a/source/val/validate_type.cpp +++ b/source/val/validate_type.cpp @@ -24,21 +24,6 @@ namespace spvtools { namespace val { namespace { -// Returns, as an int64_t, the literal value from an OpConstant or the -// default value of an OpSpecConstant, assuming it is an integral type. -// For signed integers, relies the rule that literal value is sign extended -// to fill out to word granularity. Assumes that the constant value -// has -int64_t ConstantLiteralAsInt64(uint32_t width, - const std::vector& const_words) { - const uint32_t lo_word = const_words[3]; - if (width <= 32) return int32_t(lo_word); - assert(width <= 64); - assert(const_words.size() > 4); - const uint32_t hi_word = const_words[4]; // Must exist, per spec. - return static_cast(uint64_t(lo_word) | uint64_t(hi_word) << 32); -} - // Validates that type declarations are unique, unless multiple declarations // of the same data type are allowed by the specification. // (see section 2.8 Types and Variables) @@ -252,29 +237,17 @@ spv_result_t ValidateTypeArray(ValidationState_t& _, const Instruction* inst) { << " is not a constant integer type."; } - switch (length->opcode()) { - case spv::Op::OpSpecConstant: - case spv::Op::OpConstant: { - auto& type_words = const_result_type->words(); - const bool is_signed = type_words[3] > 0; - const uint32_t width = type_words[2]; - const int64_t ivalue = ConstantLiteralAsInt64(width, length->words()); - if (ivalue == 0 || (ivalue < 0 && is_signed)) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpTypeArray Length " << _.getIdName(length_id) - << " default value must be at least 1: found " << ivalue; - } - } break; - case spv::Op::OpConstantNull: + int64_t length_value; + if (_.EvalConstantValInt64(length_id, &length_value)) { + auto& type_words = const_result_type->words(); + const bool is_signed = type_words[3] > 0; + if (length_value == 0 || (length_value < 0 && is_signed)) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpTypeArray Length " << _.getIdName(length_id) - << " default value must be at least 1."; - case spv::Op::OpSpecConstantOp: - // Assume it's OK, rather than try to evaluate the operation. - break; - default: - assert(0 && "bug in spvOpcodeIsConstant() or result type isn't int"); + << " default value must be at least 1: found " << length_value; + } } + return SPV_SUCCESS; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 25b374de11..fa5ae3e00f 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -1209,7 +1209,7 @@ bool ValidationState_t::IsCooperativeMatrixAType(uint32_t id) const { if (!IsCooperativeMatrixKHRType(id)) return false; const Instruction* inst = FindDef(id); uint64_t matrixUse = 0; - if (GetConstantValUint64(inst->word(6), &matrixUse)) { + if (EvalConstantValUint64(inst->word(6), &matrixUse)) { return matrixUse == static_cast(spv::CooperativeMatrixUse::MatrixAKHR); } @@ -1220,7 +1220,7 @@ bool ValidationState_t::IsCooperativeMatrixBType(uint32_t id) const { if (!IsCooperativeMatrixKHRType(id)) return false; const Instruction* inst = FindDef(id); uint64_t matrixUse = 0; - if (GetConstantValUint64(inst->word(6), &matrixUse)) { + if (EvalConstantValUint64(inst->word(6), &matrixUse)) { return matrixUse == static_cast(spv::CooperativeMatrixUse::MatrixBKHR); } @@ -1230,7 +1230,7 @@ bool ValidationState_t::IsCooperativeMatrixAccType(uint32_t id) const { if (!IsCooperativeMatrixKHRType(id)) return false; const Instruction* inst = FindDef(id); uint64_t matrixUse = 0; - if (GetConstantValUint64(inst->word(6), &matrixUse)) { + if (EvalConstantValUint64(inst->word(6), &matrixUse)) { return matrixUse == static_cast( spv::CooperativeMatrixUse::MatrixAccumulatorKHR); } @@ -1340,20 +1340,23 @@ uint32_t ValidationState_t::GetOperandTypeId(const Instruction* inst, return GetTypeId(inst->GetOperandAs(operand_index)); } -bool ValidationState_t::GetConstantValUint64(uint32_t id, uint64_t* val) const { +bool ValidationState_t::EvalConstantValUint64(uint32_t id, + uint64_t* val) const { const Instruction* inst = FindDef(id); if (!inst) { assert(0 && "Instruction not found"); return false; } - if (inst->opcode() != spv::Op::OpConstant && - inst->opcode() != spv::Op::OpSpecConstant) - return false; - if (!IsIntScalarType(inst->type_id())) return false; - if (inst->words().size() == 4) { + if (inst->opcode() == spv::Op::OpConstantNull) { + *val = 0; + } else if (inst->opcode() != spv::Op::OpConstant) { + // Spec constant values cannot be evaluated so don't consider constant for + // static validation + return false; + } else if (inst->words().size() == 4) { *val = inst->word(3); } else { assert(inst->words().size() == 5); @@ -1363,6 +1366,32 @@ bool ValidationState_t::GetConstantValUint64(uint32_t id, uint64_t* val) const { return true; } +bool ValidationState_t::EvalConstantValInt64(uint32_t id, int64_t* val) const { + const Instruction* inst = FindDef(id); + if (!inst) { + assert(0 && "Instruction not found"); + return false; + } + + if (!IsIntScalarType(inst->type_id())) return false; + + if (inst->opcode() == spv::Op::OpConstantNull) { + *val = 0; + } else if (inst->opcode() != spv::Op::OpConstant) { + // Spec constant values cannot be evaluated so don't consider constant for + // static validation + return false; + } else if (inst->words().size() == 4) { + *val = int32_t(inst->word(3)); + } else { + assert(inst->words().size() == 5); + const uint32_t lo_word = inst->word(3); + const uint32_t hi_word = inst->word(4); + *val = static_cast(uint64_t(lo_word) | uint64_t(hi_word) << 32); + } + return true; +} + std::tuple ValidationState_t::EvalInt32IfConst( uint32_t id) const { const Instruction* const inst = FindDef(id); diff --git a/source/val/validation_state.h b/source/val/validation_state.h index 46a8cbfa60..27acdcc2f2 100644 --- a/source/val/validation_state.h +++ b/source/val/validation_state.h @@ -648,10 +648,6 @@ class ValidationState_t { const std::function& f, bool traverse_all_types = true) const; - // Gets value from OpConstant and OpSpecConstant as uint64. - // Returns false on failure (no instruction, wrong instruction, not int). - bool GetConstantValUint64(uint32_t id, uint64_t* val) const; - // Returns type_id if id has type or zero otherwise. uint32_t GetTypeId(uint32_t id) const; @@ -726,6 +722,14 @@ class ValidationState_t { pointer_to_storage_image_.insert(type_id); } + // Tries to evaluate a any scalar integer OpConstant as uint64. + // OpConstantNull is defined as zero for scalar int (will return true) + // OpSpecConstant* return false since their values cannot be relied upon + // during validation. + bool EvalConstantValUint64(uint32_t id, uint64_t* val) const; + // Same as EvalConstantValUint64 but returns a signed int + bool EvalConstantValInt64(uint32_t id, int64_t* val) const; + // Tries to evaluate a 32-bit signed or unsigned scalar integer constant. // Returns tuple . // OpSpecConstant* return |is_const_int32| as false since their values cannot diff --git a/test/val/val_id_test.cpp b/test/val/val_id_test.cpp index 7acac563ed..e236134b78 100644 --- a/test/val/val_id_test.cpp +++ b/test/val/val_id_test.cpp @@ -1056,7 +1056,7 @@ TEST_P(ValidateIdWithMessage, OpTypeArrayLengthNull) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr(make_message("OpTypeArray Length '2[%2]' default " - "value must be at least 1."))); + "value must be at least 1: found 0"))); } TEST_P(ValidateIdWithMessage, OpTypeArrayLengthSpecConst) { From c3a9ffd74f8b27434d220f2e48a98ac6cd72d178 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:36:47 -0500 Subject: [PATCH 392/523] build(deps): bump the github-actions group with 1 update (#5593) Bumps the github-actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action). Updates `github/codeql-action` from 3.24.3 to 3.24.4 - [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/379614612a29c9e28f31f39a59013eb8012a51f0...e2e140ad1441662206e8f97754b166877dfa1c73) --- 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 9fb86eafbe..8f926ed11c 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@379614612a29c9e28f31f39a59013eb8012a51f0 # v3.24.3 + uses: github/codeql-action/upload-sarif@e2e140ad1441662206e8f97754b166877dfa1c73 # v3.24.4 with: sarif_file: results.sarif From 99a3ad32ffbf35797ca079537940bb5c870ebaaf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 12:51:21 -0500 Subject: [PATCH 393/523] build(deps): bump the github-actions group with 1 update (#5594) Bumps the github-actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action). Updates `github/codeql-action` from 3.24.4 to 3.24.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/e2e140ad1441662206e8f97754b166877dfa1c73...47b3d888fe66b639e431abf22ebca059152f1eea) --- 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 8f926ed11c..2d2a92107e 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@e2e140ad1441662206e8f97754b166877dfa1c73 # v3.24.4 + uses: github/codeql-action/upload-sarif@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5 with: sarif_file: results.sarif From fbc7a14b3e5e494113a464bbfafc48b94516446a Mon Sep 17 00:00:00 2001 From: alan-baker Date: Tue, 27 Feb 2024 15:54:08 -0500 Subject: [PATCH 394/523] Fix access chain struct checks (#5592) * Fix access chain struct checks Fixes https://crbug.com/oss-fuzz/66948 * Negative indices are invalid for struct access * Fix typos * formatting --- source/val/validate_memory.cpp | 6 ++-- test/val/val_id_test.cpp | 2 +- test/val/val_memory_test.cpp | 54 ++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index 41dd71e9ff..c9ecf51a1e 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -1386,10 +1386,10 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, // should be less than the number of struct members. const int64_t num_struct_members = static_cast(type_pointee->words().size() - 2); - if (cur_index >= num_struct_members) { + if (cur_index >= num_struct_members || cur_index < 0) { return _.diag(SPV_ERROR_INVALID_ID, cur_word_instr) << "Index is out of bounds: " << instr_name - << " can not find index " << cur_index + << " cannot find index " << cur_index << " into the structure " << _.getIdName(type_pointee->id()) << ". This structure has " << num_struct_members << " members. Largest valid index is " @@ -1410,7 +1410,7 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, } } } - // At this point, we have fully walked down from the base using the indeces. + // At this point, we have fully walked down from the base using the indices. // The type being pointed to should be the same as the result type. if (type_pointee->id() != result_type_pointee->id()) { return _.diag(SPV_ERROR_INVALID_ID, inst) diff --git a/test/val/val_id_test.cpp b/test/val/val_id_test.cpp index e236134b78..cc2973696c 100644 --- a/test/val/val_id_test.cpp +++ b/test/val/val_id_test.cpp @@ -4225,7 +4225,7 @@ OpReturn OpFunctionEnd )"; const std::string expected_err = "Index is out of bounds: " + instr + - " can not find index 3 into the structure " + " cannot find index 3 into the structure " " '25[%_struct_25]'. This structure " "has 3 members. Largest valid index is 2."; CompileSuccessfully(spirv); diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp index 8d0a94d2b0..74a17e9846 100644 --- a/test/val/val_memory_test.cpp +++ b/test/val/val_memory_test.cpp @@ -5115,6 +5115,60 @@ TEST_F(ValidateMemory, VulkanPtrAccessChainWorkgroupNoArrayStrideSuccess) { EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2)); } +TEST_F(ValidateMemory, AccessChainNegativeStructIndex32) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%int = OpTypeInt 32 1 +%_struct_4 = OpTypeStruct %int %int %int +%_ptr_Function__struct_4 = OpTypePointer Function %_struct_4 +%_ptr_Function_int = OpTypePointer Function %int +%int_n224 = OpConstant %int -224 +%fn = OpFunction %void Inline %void_fn +%entry = OpLabel +%var = OpVariable %_ptr_Function__struct_4 Function +%gep = OpInBoundsAccessChain %_ptr_Function_int %var %int_n224 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Index is out of bounds")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("cannot find index -224")); +} + +TEST_F(ValidateMemory, AccessChainNegativeStructIndex64) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability Int64 +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%int = OpTypeInt 32 1 +%long = OpTypeInt 64 1 +%_struct_4 = OpTypeStruct %int %int %int +%_ptr_Function__struct_4 = OpTypePointer Function %_struct_4 +%_ptr_Function_int = OpTypePointer Function %int +%long_n224 = OpConstant %long -224 +%fn = OpFunction %void Inline %void_fn +%entry = OpLabel +%var = OpVariable %_ptr_Function__struct_4 Function +%gep = OpInBoundsAccessChain %_ptr_Function_int %var %long_n224 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Index is out of bounds")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("cannot find index -224")); +} + } // namespace } // namespace val } // namespace spvtools From 0b027bafa54dba4e3f41c679ba0d45d6e514c4d5 Mon Sep 17 00:00:00 2001 From: Viktoria Maximova Date: Wed, 28 Feb 2024 19:58:09 +0100 Subject: [PATCH 395/523] Support operand kind for SPV_INTEL_maximum_registers (#5580) * Support operand kind for SPV_INTEL_maximum_registers * improvements * Update DEPS --- DEPS | 2 +- include/spirv-tools/libspirv.h | 2 ++ source/binary.cpp | 3 ++- source/operand.cpp | 3 +++ source/val/validate_mode_setting.cpp | 1 + 5 files changed, 9 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 323728a34c..01960700b4 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': 'ed9fc269e2fdb299afe59e912928d31ad3fdcf7d', - 'spirv_headers_revision': '05cc486580771e4fa7ddc89f5c9ee1e97382689a', + 'spirv_headers_revision': 'b73e168ca5e123dcf3dea8a34b19a5130f421ae1', } deps = { diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index abdfc15d4f..923e85f89e 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -301,6 +301,8 @@ typedef enum spv_operand_type_t { SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL, // Enum type from SPV_INTEL_cache_controls SPV_OPERAND_TYPE_STORE_CACHE_CONTROL, + // Enum type from SPV_INTEL_maximum_registers + SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS, // This is a sentinel value, and does not represent an operand type. // It should come last. diff --git a/source/binary.cpp b/source/binary.cpp index 3cfdee0434..cc7d242b97 100644 --- a/source/binary.cpp +++ b/source/binary.cpp @@ -670,7 +670,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset, case SPV_OPERAND_TYPE_QUANTIZATION_MODES: case SPV_OPERAND_TYPE_OVERFLOW_MODES: case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT: - case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT: { + case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT: + case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS: { // A single word that is a plain enum value. // Map an optional operand type to its corresponding concrete type. diff --git a/source/operand.cpp b/source/operand.cpp index 6577f8f7db..1762e63568 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -220,6 +220,8 @@ const char* spvOperandTypeStr(spv_operand_type_t type) { return "load cache control"; case SPV_OPERAND_TYPE_STORE_CACHE_CONTROL: return "store cache control"; + case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS: + return "named maximum number of registers"; case SPV_OPERAND_TYPE_IMAGE: case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: return "image"; @@ -360,6 +362,7 @@ bool spvOperandIsConcrete(spv_operand_type_t type) { case SPV_OPERAND_TYPE_HOST_ACCESS_QUALIFIER: case SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL: case SPV_OPERAND_TYPE_STORE_CACHE_CONTROL: + case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS: return true; default: break; diff --git a/source/val/validate_mode_setting.cpp b/source/val/validate_mode_setting.cpp index 82c6c3f0e8..199d8ed455 100644 --- a/source/val/validate_mode_setting.cpp +++ b/source/val/validate_mode_setting.cpp @@ -346,6 +346,7 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _, case spv::ExecutionMode::LocalSizeHintId: case spv::ExecutionMode::LocalSizeId: case spv::ExecutionMode::FPFastMathDefault: + case spv::ExecutionMode::MaximumRegistersIdINTEL: valid_mode = true; break; default: From 9bd44d028e8ca257dde9c24d5f67adabee3275ab Mon Sep 17 00:00:00 2001 From: Wooyoung Kim Date: Wed, 28 Feb 2024 13:26:28 -0800 Subject: [PATCH 396/523] Suppot for SPV_QCOM_image_processing2 (#5582) --- source/val/validate_image.cpp | 47 +- source/val/validation_state.cpp | 3 +- test/val/val_extensions_test.cpp | 208 +++ test/val/val_image_test.cpp | 2612 +++++++++++++++++++++++++++++- 4 files changed, 2857 insertions(+), 13 deletions(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 543f345ecd..f62c3a26c3 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -982,6 +982,10 @@ bool IsAllowedSampledImageOperand(spv::Op opcode, ValidationState_t& _) { case spv::Op::OpImageBoxFilterQCOM: case spv::Op::OpImageBlockMatchSSDQCOM: case spv::Op::OpImageBlockMatchSADQCOM: + case spv::Op::OpImageBlockMatchWindowSADQCOM: + case spv::Op::OpImageBlockMatchWindowSSDQCOM: + case spv::Op::OpImageBlockMatchGatherSADQCOM: + case spv::Op::OpImageBlockMatchGatherSSDQCOM: return true; case spv::Op::OpStore: if (_.HasCapability(spv::Capability::BindlessTextureNV)) return true; @@ -2168,7 +2172,7 @@ spv_result_t ValidateImageProcessingQCOMDecoration(ValidationState_t& _, int id, 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"; + << "Missing decoration " << _.SpvDecorationString(decor); } return SPV_SUCCESS; @@ -2196,6 +2200,34 @@ spv_result_t ValidateImageProcessingQCOM(ValidationState_t& _, _, ref_idx, spv::Decoration::BlockMatchTextureQCOM); break; } + case spv::Op::OpImageBlockMatchWindowSSDQCOM: + case spv::Op::OpImageBlockMatchWindowSADQCOM: { + int tgt_idx = inst->GetOperandAs(2); // target + res = ValidateImageProcessingQCOMDecoration( + _, tgt_idx, spv::Decoration::BlockMatchTextureQCOM); + if (res != SPV_SUCCESS) break; + res = ValidateImageProcessingQCOMDecoration( + _, tgt_idx, spv::Decoration::BlockMatchSamplerQCOM); + if (res != SPV_SUCCESS) break; + int ref_idx = inst->GetOperandAs(4); // reference + res = ValidateImageProcessingQCOMDecoration( + _, ref_idx, spv::Decoration::BlockMatchTextureQCOM); + if (res != SPV_SUCCESS) break; + res = ValidateImageProcessingQCOMDecoration( + _, ref_idx, spv::Decoration::BlockMatchSamplerQCOM); + break; + } + case spv::Op::OpImageBlockMatchGatherSSDQCOM: + case spv::Op::OpImageBlockMatchGatherSADQCOM: { + 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; } @@ -2326,6 +2358,10 @@ spv_result_t ImagePass(ValidationState_t& _, const Instruction* inst) { case spv::Op::OpImageBoxFilterQCOM: case spv::Op::OpImageBlockMatchSSDQCOM: case spv::Op::OpImageBlockMatchSADQCOM: + case spv::Op::OpImageBlockMatchWindowSADQCOM: + case spv::Op::OpImageBlockMatchWindowSSDQCOM: + case spv::Op::OpImageBlockMatchGatherSADQCOM: + case spv::Op::OpImageBlockMatchGatherSSDQCOM: return ValidateImageProcessingQCOM(_, inst); default: @@ -2378,6 +2414,10 @@ bool IsImageInstruction(const spv::Op opcode) { case spv::Op::OpImageBoxFilterQCOM: case spv::Op::OpImageBlockMatchSSDQCOM: case spv::Op::OpImageBlockMatchSADQCOM: + case spv::Op::OpImageBlockMatchWindowSADQCOM: + case spv::Op::OpImageBlockMatchWindowSSDQCOM: + case spv::Op::OpImageBlockMatchGatherSADQCOM: + case spv::Op::OpImageBlockMatchGatherSSDQCOM: return true; default: break; @@ -2396,6 +2436,11 @@ spv_result_t ValidateQCOMImageProcessingTextureUsages(ValidationState_t& _, case spv::Op::OpImageBlockMatchSSDQCOM: case spv::Op::OpImageBlockMatchSADQCOM: break; + case spv::Op::OpImageBlockMatchWindowSADQCOM: + case spv::Op::OpImageBlockMatchWindowSSDQCOM: + case spv::Op::OpImageBlockMatchGatherSADQCOM: + case spv::Op::OpImageBlockMatchGatherSSDQCOM: + break; default: for (size_t i = 0; i < inst->operands().size(); ++i) { int id = inst->GetOperandAs(i); diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index fa5ae3e00f..896849930e 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -615,7 +615,8 @@ 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)) { + HasDecoration(texture_id, spv::Decoration::BlockMatchTextureQCOM) || + HasDecoration(texture_id, spv::Decoration::BlockMatchSamplerQCOM)) { qcom_image_processing_consumers_.insert(consumer0->id()); if (consumer1) { qcom_image_processing_consumers_.insert(consumer1->id()); diff --git a/test/val/val_extensions_test.cpp b/test/val/val_extensions_test.cpp index 0ab8c6e3c3..932bbee8f5 100644 --- a/test/val/val_extensions_test.cpp +++ b/test/val/val_extensions_test.cpp @@ -131,6 +131,214 @@ TEST_F(ValidateExtensionCapabilities, DeclCapabilityFailure) { EXPECT_THAT(getDiagnosticString(), HasSubstr("SPV_KHR_device_group")); } +TEST_F(ValidateExtensionCapabilities, + DeclCapabilityFailureBlockMatchWIndowSAD) { + const std::string str = R"( + OpCapability Shader + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing2" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %v_texcoord %fragColor %target_samp %ref_samp + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpSourceExtension "GL_QCOM_image_processing" + OpSourceExtension "GL_QCOM_image_processing2" + OpName %main "main" + OpName %tgt_coords "tgt_coords" + OpName %v_texcoord "v_texcoord" + OpName %ref_coords "ref_coords" + OpName %blockSize "blockSize" + OpName %fragColor "fragColor" + OpName %target_samp "target_samp" + OpName %ref_samp "ref_samp" + OpDecorate %v_texcoord Location 0 + OpDecorate %fragColor Location 0 + OpDecorate %target_samp DescriptorSet 0 + OpDecorate %target_samp Binding 4 + OpDecorate %ref_samp DescriptorSet 0 + OpDecorate %ref_samp Binding 5 + OpDecorate %target_samp BlockMatchTextureQCOM + OpDecorate %target_samp BlockMatchSamplerQCOM + OpDecorate %ref_samp BlockMatchTextureQCOM + OpDecorate %ref_samp BlockMatchSamplerQCOM + %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 + %v_texcoord = OpVariable %_ptr_Input_v4float Input + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float +%_ptr_Function_uint = OpTypePointer Function %uint + %uint_1 = OpConstant %uint 1 + %uint_2 = OpConstant %uint 2 + %uint_3 = OpConstant %uint 3 + %uint_4 = OpConstant %uint 4 + %39 = OpConstantComposite %v2uint %uint_4 %uint_4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %fragColor = OpVariable %_ptr_Output_v4float Output + %42 = OpTypeImage %float 2D 0 0 0 1 Unknown + %43 = OpTypeSampledImage %42 +%_ptr_UniformConstant_43 = OpTypePointer UniformConstant %43 +%target_samp = OpVariable %_ptr_UniformConstant_43 UniformConstant + %ref_samp = OpVariable %_ptr_UniformConstant_43 UniformConstant + %main = OpFunction %void None %3 + %5 = OpLabel + %tgt_coords = OpVariable %_ptr_Function_v2uint Function + %ref_coords = OpVariable %_ptr_Function_v2uint Function + %blockSize = OpVariable %_ptr_Function_v2uint Function + %16 = OpAccessChain %_ptr_Input_float %v_texcoord %uint_0 + %17 = OpLoad %float %16 + %18 = OpConvertFToU %uint %17 + %20 = OpAccessChain %_ptr_Function_uint %tgt_coords %uint_0 + OpStore %20 %18 + %22 = OpAccessChain %_ptr_Input_float %v_texcoord %uint_1 + %23 = OpLoad %float %22 + %24 = OpConvertFToU %uint %23 + %25 = OpAccessChain %_ptr_Function_uint %tgt_coords %uint_0 + OpStore %25 %24 + %28 = OpAccessChain %_ptr_Input_float %v_texcoord %uint_2 + %29 = OpLoad %float %28 + %30 = OpConvertFToU %uint %29 + %31 = OpAccessChain %_ptr_Function_uint %ref_coords %uint_0 + OpStore %31 %30 + %33 = OpAccessChain %_ptr_Input_float %v_texcoord %uint_3 + %34 = OpLoad %float %33 + %35 = OpConvertFToU %uint %34 + %36 = OpAccessChain %_ptr_Function_uint %ref_coords %uint_1 + OpStore %36 %35 + OpStore %blockSize %39 + %46 = OpLoad %43 %target_samp + %47 = OpLoad %v2uint %tgt_coords + %49 = OpLoad %43 %ref_samp + %50 = OpLoad %v2uint %ref_coords + %51 = OpLoad %v2uint %blockSize + %52 = OpImageBlockMatchWindowSADQCOM %v4float %46 %47 %49 %50 %51 + OpStore %fragColor %52 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + ASSERT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("2nd operand of Decorate")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires one of these extensions")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("SPV_QCOM_image_processing")); +} + +TEST_F(ValidateExtensionCapabilities, + DeclCapabilityFailureBlockMatchWIndowSSD) { + const std::string str = R"( + OpCapability Shader + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing2" + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %v_texcoord %fragColor %tex2D_src1 %samp %tex2D_src2 + OpExecutionMode %main OriginUpperLeft + OpSource GLSL 450 + OpSourceExtension "GL_QCOM_image_processing" + OpSourceExtension "GL_QCOM_image_processing2" + OpName %main "main" + OpName %tgt_coords "tgt_coords" + OpName %v_texcoord "v_texcoord" + OpName %ref_coords "ref_coords" + OpName %blockSize "blockSize" + OpName %fragColor "fragColor" + OpName %tex2D_src1 "tex2D_src1" + OpName %samp "samp" + OpName %tex2D_src2 "tex2D_src2" + OpDecorate %v_texcoord Location 0 + OpDecorate %fragColor Location 0 + OpDecorate %tex2D_src1 DescriptorSet 0 + OpDecorate %tex2D_src1 Binding 1 + OpDecorate %samp DescriptorSet 0 + OpDecorate %samp Binding 3 + OpDecorate %tex2D_src2 DescriptorSet 0 + OpDecorate %tex2D_src2 Binding 2 + OpDecorate %tex2D_src1 BlockMatchTextureQCOM + OpDecorate %samp BlockMatchSamplerQCOM + OpDecorate %tex2D_src2 BlockMatchTextureQCOM + OpDecorate %samp BlockMatchSamplerQCOM + %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 + %v_texcoord = OpVariable %_ptr_Input_v4float Input + %uint_0 = OpConstant %uint 0 +%_ptr_Input_float = OpTypePointer Input %float +%_ptr_Function_uint = OpTypePointer Function %uint + %uint_1 = OpConstant %uint 1 + %uint_2 = OpConstant %uint 2 + %uint_3 = OpConstant %uint 3 + %uint_4 = OpConstant %uint 4 + %39 = OpConstantComposite %v2uint %uint_4 %uint_4 +%_ptr_Output_v4float = OpTypePointer Output %v4float + %fragColor = OpVariable %_ptr_Output_v4float Output + %42 = OpTypeImage %float 2D 0 0 0 1 Unknown +%_ptr_UniformConstant_42 = OpTypePointer UniformConstant %42 + %tex2D_src1 = OpVariable %_ptr_UniformConstant_42 UniformConstant + %46 = OpTypeSampler +%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46 + %samp = OpVariable %_ptr_UniformConstant_46 UniformConstant + %50 = OpTypeSampledImage %42 + %tex2D_src2 = OpVariable %_ptr_UniformConstant_42 UniformConstant + %main = OpFunction %void None %3 + %5 = OpLabel + %tgt_coords = OpVariable %_ptr_Function_v2uint Function + %ref_coords = OpVariable %_ptr_Function_v2uint Function + %blockSize = OpVariable %_ptr_Function_v2uint Function + %16 = OpAccessChain %_ptr_Input_float %v_texcoord %uint_0 + %17 = OpLoad %float %16 + %18 = OpConvertFToU %uint %17 + %20 = OpAccessChain %_ptr_Function_uint %tgt_coords %uint_0 + OpStore %20 %18 + %22 = OpAccessChain %_ptr_Input_float %v_texcoord %uint_1 + %23 = OpLoad %float %22 + %24 = OpConvertFToU %uint %23 + %25 = OpAccessChain %_ptr_Function_uint %tgt_coords %uint_0 + OpStore %25 %24 + %28 = OpAccessChain %_ptr_Input_float %v_texcoord %uint_2 + %29 = OpLoad %float %28 + %30 = OpConvertFToU %uint %29 + %31 = OpAccessChain %_ptr_Function_uint %ref_coords %uint_0 + OpStore %31 %30 + %33 = OpAccessChain %_ptr_Input_float %v_texcoord %uint_3 + %34 = OpLoad %float %33 + %35 = OpConvertFToU %uint %34 + %36 = OpAccessChain %_ptr_Function_uint %ref_coords %uint_1 + OpStore %36 %35 + OpStore %blockSize %39 + %45 = OpLoad %42 %tex2D_src1 + %49 = OpLoad %46 %samp + %51 = OpSampledImage %50 %45 %49 + %52 = OpLoad %v2uint %tgt_coords + %54 = OpLoad %42 %tex2D_src2 + %55 = OpLoad %46 %samp + %56 = OpSampledImage %50 %54 %55 + %57 = OpLoad %v2uint %ref_coords + %58 = OpLoad %v2uint %blockSize + %59 = OpImageBlockMatchWindowSSDQCOM %v4float %51 %52 %56 %57 %58 + OpStore %fragColor %59 + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + ASSERT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("2nd operand of Decorate")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires one of these extensions")); + EXPECT_THAT(getDiagnosticString(), HasSubstr("SPV_QCOM_image_processing")); +} + using ValidateAMDShaderBallotCapabilities = spvtest::ValidateBase; // Returns a vector of strings for the prefix of a SPIR-V assembly shader diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index 9a704098de..35b76fc5b5 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -6733,7 +6733,8 @@ TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADNoDecorationA) { 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")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Missing decoration BlockMatchTextureQCOM")); } TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADNoDecorationB) { @@ -6792,7 +6793,8 @@ TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADNoDecorationB) { 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")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Missing decoration BlockMatchTextureQCOM")); } TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADNoDecorationC) { @@ -6844,7 +6846,8 @@ TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADNoDecorationC) { 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")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Missing decoration BlockMatchTextureQCOM")); } TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADNoDecorationD) { @@ -6896,7 +6899,8 @@ TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADNoDecorationD) { 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")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Missing decoration BlockMatchTextureQCOM")); } TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDNoDecorationA) { @@ -6955,7 +6959,8 @@ TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDNoDecorationA) { 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")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Missing decoration BlockMatchTextureQCOM")); } TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDNoDecorationB) { @@ -7014,7 +7019,8 @@ TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDNoDecorationB) { 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")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Missing decoration BlockMatchTextureQCOM")); } TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDNoDecorationC) { @@ -7066,7 +7072,8 @@ TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDNoDecorationC) { 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")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Missing decoration BlockMatchTextureQCOM")); } TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDNoDecorationD) { @@ -7118,7 +7125,8 @@ TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSSDNoDecorationD) { 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")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Missing decoration BlockMatchTextureQCOM")); } TEST_F(ValidateImage, QCOMImageProcessingSampleWeightedNoDecorationA) { @@ -7177,7 +7185,8 @@ TEST_F(ValidateImage, QCOMImageProcessingSampleWeightedNoDecorationA) { 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")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Missing decoration WeightTextureQCOM")); } TEST_F(ValidateImage, QCOMImageProcessingSampleWeightedNoDecorationB) { @@ -7230,10 +7239,11 @@ TEST_F(ValidateImage, QCOMImageProcessingSampleWeightedNoDecorationB) { 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")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Missing decoration WeightTextureQCOM")); } -TEST_F(ValidateImage, QCOMImageProcessingBlockMatchSADInvalidUseA) { +TEST_F(ValidateImage, QCOMImageProcessingBlockMatchWindowSADInvalidUseA) { std::string text = R"( ; SPIR-V ; Version: 1.0 @@ -7936,6 +7946,2586 @@ TEST_F(ValidateImage, QCOMImageProcessingSampleWeightedInvalidUseB) { HasSubstr("Illegal use of QCOM image processing decorated texture")); } +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorTargetIT) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 BlockMatchSamplerQCOM + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 5 + OpDecorate %5 BlockMatchTextureQCOM + OpDecorate %5 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSADQCOM %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 BlockMatchTextureQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorTargetIS) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 + OpDecorate %5 BlockMatchTextureQCOM + OpDecorate %5 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSADQCOM %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 BlockMatchSamplerQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorRefIT) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %4 BlockMatchSamplerQCOM + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 5 + OpDecorate %5 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSADQCOM %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 BlockMatchTextureQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorRefIS) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %4 BlockMatchSamplerQCOM + 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 = OpImageBlockMatchWindowSADQCOM %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 BlockMatchSamplerQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorTargetNIT) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %4 BlockMatchSamplerQCOM + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 3 + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 2 + OpDecorate %6 BlockMatchTextureQCOM + OpDecorate %6 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSADQCOM %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 BlockMatchTextureQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorTargetNIS) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %4 BlockMatchTextureQCOM + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 3 + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 2 + OpDecorate %6 BlockMatchTextureQCOM + OpDecorate %6 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSADQCOM %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 BlockMatchSamplerQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorRefNIT) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %4 BlockMatchTextureQCOM + OpDecorate %4 BlockMatchSamplerQCOM + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 3 + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 2 + OpDecorate %6 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSADQCOM %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 BlockMatchTextureQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorRefNIS) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %4 BlockMatchTextureQCOM + OpDecorate %4 BlockMatchSamplerQCOM + 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 = OpImageBlockMatchWindowSADQCOM %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 BlockMatchSamplerQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorTargetIT) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 BlockMatchSamplerQCOM + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 5 + OpDecorate %5 BlockMatchTextureQCOM + OpDecorate %5 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSSDQCOM %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 BlockMatchTextureQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorTargetIS) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 + OpDecorate %5 BlockMatchTextureQCOM + OpDecorate %5 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSSDQCOM %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 BlockMatchSamplerQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorRefIT) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %4 BlockMatchSamplerQCOM + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 5 + OpDecorate %5 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSSDQCOM %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 BlockMatchTextureQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorRefIS) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %4 BlockMatchSamplerQCOM + 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 = OpImageBlockMatchWindowSSDQCOM %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 BlockMatchSamplerQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorTargetNIT) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %4 BlockMatchSamplerQCOM + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 3 + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 2 + OpDecorate %6 BlockMatchTextureQCOM + OpDecorate %6 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSSDQCOM %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 BlockMatchTextureQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorTargetNIS) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %4 BlockMatchTextureQCOM + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 3 + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 2 + OpDecorate %6 BlockMatchTextureQCOM + OpDecorate %6 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSSDQCOM %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 BlockMatchSamplerQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorRefNIT) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %4 BlockMatchTextureQCOM + OpDecorate %4 BlockMatchSamplerQCOM + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 3 + OpDecorate %6 DescriptorSet 0 + OpDecorate %6 Binding 2 + OpDecorate %6 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSSDQCOM %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 BlockMatchTextureQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorRefNIS) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %4 BlockMatchTextureQCOM + OpDecorate %4 BlockMatchSamplerQCOM + 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 = OpImageBlockMatchWindowSSDQCOM %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 BlockMatchSamplerQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSADNoDecorTargetIT) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 = OpImageBlockMatchGatherSADQCOM %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 BlockMatchTextureQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSADNoDecorRefIT) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 = OpImageBlockMatchGatherSADQCOM %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 BlockMatchTextureQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSADNoDecorTargetNIT) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 = OpImageBlockMatchGatherSADQCOM %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 BlockMatchTextureQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSADNoDecorRefNIT) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %4 BlockMatchTextureQCOM + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 3 + 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 = OpImageBlockMatchGatherSADQCOM %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 BlockMatchTextureQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSSDNoDecorTargetIT) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 = OpImageBlockMatchGatherSSDQCOM %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 BlockMatchTextureQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSSDNoDecorRefIT) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 = OpImageBlockMatchGatherSSDQCOM %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 BlockMatchTextureQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSSDNoDecorTargetNIT) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 = OpImageBlockMatchGatherSSDQCOM %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 BlockMatchTextureQCOM")); +} + +TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchGatherSSDNoDecorRefNIT) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %4 BlockMatchTextureQCOM + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 3 + 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 = OpImageBlockMatchGatherSSDQCOM %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 BlockMatchTextureQCOM")); +} + +TEST_F(ValidateImage, + QCOMImageProcessing2BlockMatchWindowSADInvalidUseTargetI) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %5 BlockMatchSamplerQCOM + OpDecorate %6 BlockMatchTextureQCOM + OpDecorate %6 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSADQCOM %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, QCOMImageProcessing2BlockMatchWindowSADInvalidUseRefI) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %5 BlockMatchSamplerQCOM + OpDecorate %6 BlockMatchTextureQCOM + OpDecorate %6 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSADQCOM %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, + QCOMImageProcessing2BlockMatchWindowSADInvalidUseTargetNI) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %102 BlockMatchSamplerQCOM + OpDecorate %104 BlockMatchTextureQCOM + OpDecorate %104 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSADQCOM %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, QCOMImageProcessing2BlockMatchWindowSADInvalidUseRefNI) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %102 BlockMatchSamplerQCOM + OpDecorate %104 BlockMatchTextureQCOM + OpDecorate %104 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSADQCOM %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, + QCOMImageProcessing2BlockMatchWindowSSDInvalidUseTargetI) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %5 BlockMatchSamplerQCOM + OpDecorate %6 BlockMatchTextureQCOM + OpDecorate %6 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSSDQCOM %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, QCOMImageProcessing2BlockMatchWindowSSDInvalidUseRefI) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %5 BlockMatchSamplerQCOM + OpDecorate %6 BlockMatchTextureQCOM + OpDecorate %6 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSSDQCOM %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, + QCOMImageProcessing2BlockMatchWindowSSDInvalidUseTargetNI) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %102 BlockMatchSamplerQCOM + OpDecorate %104 BlockMatchTextureQCOM + OpDecorate %104 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSSDQCOM %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, QCOMImageProcessing2BlockMatchWindowSSDInvalidUseRefNI) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 %102 BlockMatchSamplerQCOM + OpDecorate %104 BlockMatchTextureQCOM + OpDecorate %104 BlockMatchSamplerQCOM + %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 = OpImageBlockMatchWindowSSDQCOM %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, + QCOMImageProcessing2BlockMatchGatherSADInvalidUseTargetI) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 = OpImageBlockMatchGatherSADQCOM %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, QCOMImageProcessing2BlockMatchGatherSADInvalidUseRefI) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 = OpImageBlockMatchGatherSADQCOM %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, + QCOMImageProcessing2BlockMatchGatherSADInvalidUseTargetNI) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 = OpImageBlockMatchGatherSADQCOM %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, QCOMImageProcessing2BlockMatchGatherSADInvalidUseRefNI) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 = OpImageBlockMatchGatherSADQCOM %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, + QCOMImageProcessing2BlockMatchGatherSSDInvalidUseTargetI) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 = OpImageBlockMatchGatherSSDQCOM %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, QCOMImageProcessing2BlockMatchGatherSSDInvalidUseRefI) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 = OpImageBlockMatchGatherSSDQCOM %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, + QCOMImageProcessing2BlockMatchGatherSSDInvalidUseTargetNI) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 = OpImageBlockMatchGatherSSDQCOM %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, QCOMImageProcessing2BlockMatchGatherSSDInvalidUseRefNI) { + const std::string text = R"( + OpCapability Shader + OpCapability TextureBlockMatchQCOM + OpCapability TextureBlockMatch2QCOM + OpExtension "SPV_QCOM_image_processing" + OpExtension "SPV_QCOM_image_processing2" + %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 = OpImageBlockMatchGatherSSDQCOM %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, ImageMSArray_ArrayedSampledTypeRequiresCapability) { const std::string code = R"( OpCapability Shader From 75ad1345d4af5268448a9b26797294b48795cd69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Petit?= Date: Thu, 29 Feb 2024 17:46:38 +0000 Subject: [PATCH 397/523] Remove redundant function declarations from source/operand.h (#5584) Flagged by -Wredundant-decls I'm assuming the declarations in libspirv.h are part of the external interface and need to be kept. Change-Id: I6b138d3322a7a4ee49ee33b0fbcf0ca35dd92261 Signed-off-by: Kevin Petit --- source/operand.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/source/operand.h b/source/operand.h index a3010d9341..f74c93389e 100644 --- a/source/operand.h +++ b/source/operand.h @@ -57,12 +57,6 @@ spv_result_t spvOperandTableValueLookup(spv_target_env, // Gets the name string of the non-variable operand type. const char* spvOperandTypeStr(spv_operand_type_t type); -// Returns true if the given type is concrete. -bool spvOperandIsConcrete(spv_operand_type_t type); - -// Returns true if the given type is concrete and also a mask. -bool spvOperandIsConcreteMask(spv_operand_type_t type); - // Returns true if an operand of the given type is optional. bool spvOperandIsOptional(spv_operand_type_t type); From 5bc7c2876359787f120ceb9f9bedbbc4907438c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 13:00:12 -0500 Subject: [PATCH 398/523] build(deps): bump the github-actions group with 2 updates (#5598) Bumps the github-actions group with 2 updates: [actions/cache](https://github.com/actions/cache) and [github/codeql-action](https://github.com/github/codeql-action). Updates `actions/cache` from 4.0.0 to 4.0.1 - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/13aacd865c20de90d75de3b17ebe84f7a17d57d2...ab5e6d0c87105b4c9c2047343972218f562e4319) Updates `github/codeql-action` from 3.24.5 to 3.24.6 - [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/47b3d888fe66b639e431abf22ebca059152f1eea...8a470fddafa5cbb6266ee11b37ef4d8aae19c571) --- updated-dependencies: - dependency-name: actions/cache 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/bazel.yml | 2 +- .github/workflows/scorecard.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index bd90e82e9c..33840b855c 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -24,7 +24,7 @@ jobs: - name: Download dependencies run: python3 utils/git-sync-deps - name: Mount Bazel cache - uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 with: path: ~/.bazel/cache key: bazel-cache-${{ runner.os }} diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 2d2a92107e..d800df2c05 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@47b3d888fe66b639e431abf22ebca059152f1eea # v3.24.5 + uses: github/codeql-action/upload-sarif@8a470fddafa5cbb6266ee11b37ef4d8aae19c571 # v3.24.6 with: sarif_file: results.sarif From 7c363050de047e37ca168c74e0a960fd4b097173 Mon Sep 17 00:00:00 2001 From: Rodrigo Locatti Date: Wed, 6 Mar 2024 12:42:22 -0300 Subject: [PATCH 399/523] Add operand types for SPV_NV_raw_access_chains (#5602) This is needed to unblock builds with updated SPIR-V headers. It is not a replacement for #5568. --- include/spirv-tools/libspirv.h | 4 ++++ source/binary.cpp | 5 ++++- source/disassemble.cpp | 1 + source/operand.cpp | 5 +++++ source/text.cpp | 1 + utils/generate_grammar_tables.py | 2 +- 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index 923e85f89e..a7b57b821e 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -303,6 +303,10 @@ typedef enum spv_operand_type_t { SPV_OPERAND_TYPE_STORE_CACHE_CONTROL, // Enum type from SPV_INTEL_maximum_registers SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS, + // Enum type from SPV_NV_raw_access_chains + SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS, + // Optional enum type from SPV_NV_raw_access_chains + SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS, // This is a sentinel value, and does not represent an operand type. // It should come last. diff --git a/source/binary.cpp b/source/binary.cpp index cc7d242b97..cf1f0b7b01 100644 --- a/source/binary.cpp +++ b/source/binary.cpp @@ -711,6 +711,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset, case SPV_OPERAND_TYPE_IMAGE: case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: + case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS: case SPV_OPERAND_TYPE_SELECTION_CONTROL: case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: @@ -721,10 +722,12 @@ spv_result_t Parser::parseOperand(size_t inst_offset, // Map an optional operand type to its corresponding concrete type. if (type == SPV_OPERAND_TYPE_OPTIONAL_IMAGE) parsed_operand.type = SPV_OPERAND_TYPE_IMAGE; - else if (type == SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS) + if (type == SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS) parsed_operand.type = SPV_OPERAND_TYPE_MEMORY_ACCESS; if (type == SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS) parsed_operand.type = SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS; + if (type == SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS) + parsed_operand.type = SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS; // Check validity of set mask bits. Also prepare for operands for those // masks if they have any. To get operand order correct, scan from diff --git a/source/disassemble.cpp b/source/disassemble.cpp index 5173fbf677..f8f6f44a34 100644 --- a/source/disassemble.cpp +++ b/source/disassemble.cpp @@ -425,6 +425,7 @@ void InstructionDisassembler::EmitOperand(const spv_parsed_instruction_t& inst, case SPV_OPERAND_TYPE_SELECTION_CONTROL: case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: + case SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS: EmitMaskOperand(operand.type, word); break; default: diff --git a/source/operand.cpp b/source/operand.cpp index 1762e63568..7848846745 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -222,6 +222,9 @@ const char* spvOperandTypeStr(spv_operand_type_t type) { return "store cache control"; case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS: return "named maximum number of registers"; + case SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS: + case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS: + return "raw access chain operands"; case SPV_OPERAND_TYPE_IMAGE: case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: return "image"; @@ -382,6 +385,7 @@ bool spvOperandIsConcreteMask(spv_operand_type_t type) { case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: case SPV_OPERAND_TYPE_COOPERATIVE_MATRIX_OPERANDS: + case SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS: return true; default: break; @@ -402,6 +406,7 @@ bool spvOperandIsOptional(spv_operand_type_t type) { case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT: case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS: case SPV_OPERAND_TYPE_OPTIONAL_CIV: + case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS: return true; default: break; diff --git a/source/text.cpp b/source/text.cpp index 737c223b53..263bacd7bc 100644 --- a/source/text.cpp +++ b/source/text.cpp @@ -411,6 +411,7 @@ spv_result_t spvTextEncodeOperand(const spvtools::AssemblyGrammar& grammar, case SPV_OPERAND_TYPE_IMAGE: case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: + case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS: case SPV_OPERAND_TYPE_SELECTION_CONTROL: case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: diff --git a/utils/generate_grammar_tables.py b/utils/generate_grammar_tables.py index 48f83c33ab..88534ffed4 100755 --- a/utils/generate_grammar_tables.py +++ b/utils/generate_grammar_tables.py @@ -540,7 +540,7 @@ def generate_operand_kind_table(enums): # We have a few operand kinds that require their optional counterpart to # exist in the operand info table. - optional_enums = ['ImageOperands', 'AccessQualifier', 'MemoryAccess', 'PackedVectorFormat', 'CooperativeMatrixOperands'] + optional_enums = ['ImageOperands', 'AccessQualifier', 'MemoryAccess', 'PackedVectorFormat', 'CooperativeMatrixOperands', 'RawAccessChainOperands'] optional_enums = [e for e in enums if e[0] in optional_enums] enums.extend(optional_enums) From 04896c462d9f3f504c99a4698605b6524af813c1 Mon Sep 17 00:00:00 2001 From: Michael Anttila Date: Thu, 7 Mar 2024 10:31:14 -0500 Subject: [PATCH 400/523] Prepare release v2024.1 (#5605) * Roll external/spirv-headers/ b73e168ca..8b246ff75 (1 commit) https://github.com/KhronosGroup/SPIRV-Headers/compare/b73e168ca5e1...8b246ff75c66 $ git log b73e168ca..8b246ff75 --date=short --no-merges --format='%ad %ae %s' 2024-03-01 rlocatti Add SPV_NV_raw_access_chains (#417) Created with: roll-dep external/spirv-headers * Prepare release 2024.1 --- CHANGES | 32 ++++++++++++++++++++++++++++++++ DEPS | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 48aa87664a..5a771be173 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,37 @@ Revision history for SPIRV-Tools +v2024.1 2024-03-06 + - General + - Add tooling support for SPV_KHR_maximal_reconvergence (#5542) + - Add support for SPV_KHR_float_controls2 (#5543) + - SPV_KHR_quad_control (#5547) + - Fold 64-bit int operations (#5561) + - update image enum tests to remove Kernel capability (#5562) + - Support operand kind for SPV_INTEL_maximum_registers (#5580) + - SPV_NV_shader_atomic_fp16_vector (#5581) + - Support for SPV_QCOM_image_processing2 (#5582) + - Fix access chain struct checks (#5592) + - Optimizer + - opt: add Int16 and Float16 to capability trim pass (#5519) + - Add preserver-interface option to spirv-opt (#5524) + - spirv-opt: Fix OpCompositeExtract relaxation with struct operands (#5536) + - opt: Add VulkanMemoryModelDeviceScope to trim (#5544) + - opt: Add TrimCapabilities pass to spirv-opt tool (#5545) + - Add modify-maximal-reconvergence to spirv-opt help (#5546) + - opt: add SPV_EXT_mesh_shader to opt allowlist (#5551) + - opt: Add OpEntryPoint to DescriptorScalarReplacement pass (#5553) + - opt: prevent meld to merge block with MaximalReconvergence (#5557) + - [OPT] Use new instruction folder for for all opcodes in spec consti folding (#5569) + - [OPT] Identify arrays with unknown length in copy prop arrays (#5570) + - [OPT] Add removed unused interface var pass to legalization passes (#5579) + - Validator + - spirv-val: Re-enable OpControlBarrier VU (#5527) + - spirv-val: Add Mesh Primitive Built-In validaiton (#5529) + - spirv-val: Validate PhysicalStorageBuffer Stage Interface (#5539) + - spirv-val: Multiple interface var with same SC (#5528) + - spirv-val: Revert Validate PhysicalStorageBuffer Stage Interface (#5575) + - spirv-val: Make Constant evaluation consistent (#5587) + v2023.6 2023-12-18 - General - update_build_version.py produce deterministic header. (#5426) diff --git a/DEPS b/DEPS index 01960700b4..d117c59e92 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': 'ed9fc269e2fdb299afe59e912928d31ad3fdcf7d', - 'spirv_headers_revision': 'b73e168ca5e123dcf3dea8a34b19a5130f421ae1', + 'spirv_headers_revision': '8b246ff75c6615ba4532fe4fde20f1be090c3764', } deps = { From d15a7aa25dad142adfbc91caf6fc8261c7752856 Mon Sep 17 00:00:00 2001 From: David Neto Date: Mon, 11 Mar 2024 12:57:43 -0400 Subject: [PATCH 401/523] kokoro: Update bazel to 7.0.2 for Mac builds (#5606) --- kokoro/macos-clang-release-bazel/build.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kokoro/macos-clang-release-bazel/build.sh b/kokoro/macos-clang-release-bazel/build.sh index 74f9e2365f..4bb889ad09 100644 --- a/kokoro/macos-clang-release-bazel/build.sh +++ b/kokoro/macos-clang-release-bazel/build.sh @@ -32,14 +32,14 @@ git config --global --add safe.directory $SRC cd $SRC /usr/bin/python3 utils/git-sync-deps --treeless -# Get bazel 5.0.0 -gsutil cp gs://bazel/5.0.0/release/bazel-5.0.0-darwin-x86_64 . -chmod +x bazel-5.0.0-darwin-x86_64 +# Get bazel 7.0.2 +gsutil cp gs://bazel/7.0.2/release/bazel-7.0.2-darwin-x86_64 . +chmod +x bazel-7.0.2-darwin-x86_64 echo $(date): Build everything... -./bazel-5.0.0-darwin-x86_64 build --cxxopt=-std=c++17 :all +./bazel-7.0.2-darwin-x86_64 build --cxxopt=-std=c++17 :all echo $(date): Build completed. echo $(date): Starting bazel test... -./bazel-5.0.0-darwin-x86_64 test --cxxopt=-std=c++17 :all +./bazel-7.0.2-darwin-x86_64 test --cxxopt=-std=c++17 :all echo $(date): Bazel test completed. From f869d391a5eaff5e121428a568c80823a2cafbda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Petit?= Date: Tue, 12 Mar 2024 09:09:46 +0000 Subject: [PATCH 402/523] [OPT] Fix handling of analyses rebuild (#5608) All tests treat kAnalysisEnd like STL end iterators, which means its value must be greater than that of the last valid Analysis. Change-Id: Ibfaaf60bb450c508af0528dbe9c0729e6aa07b3b Signed-off-by: Kevin Petit --- source/opt/ir_context.cpp | 3 +++ source/opt/ir_context.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/source/opt/ir_context.cpp b/source/opt/ir_context.cpp index 239d316ca8..d864b7c02e 100644 --- a/source/opt/ir_context.cpp +++ b/source/opt/ir_context.cpp @@ -88,6 +88,9 @@ void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) { if (set & kAnalysisDebugInfo) { BuildDebugInfoManager(); } + if (set & kAnalysisLiveness) { + BuildLivenessManager(); + } } void IRContext::InvalidateAnalysesExceptFor( diff --git a/source/opt/ir_context.h b/source/opt/ir_context.h index 5685db809d..ef7c45806a 100644 --- a/source/opt/ir_context.h +++ b/source/opt/ir_context.h @@ -84,7 +84,7 @@ class IRContext { kAnalysisTypes = 1 << 15, kAnalysisDebugInfo = 1 << 16, kAnalysisLiveness = 1 << 17, - kAnalysisEnd = 1 << 17 + kAnalysisEnd = 1 << 18 }; using ProcessFunction = std::function; From 02c79e90829c2d9149725ce0ac9f44c793f712bb Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Wed, 13 Mar 2024 10:21:35 -0700 Subject: [PATCH 403/523] kokoro: Update bazel to 7.0.2 for Linux builds (#5609) --- README.md | 2 +- kokoro/scripts/linux/build-docker.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 042b83da13..e916a2c98a 100644 --- a/README.md +++ b/README.md @@ -426,7 +426,7 @@ targets, you need to install CMake Version 2.8.12 or later. - [Python 3](http://www.python.org/): for utility scripts and running the test suite. - [Bazel](https://bazel.build/) (optional): if building the source with Bazel, -you need to install Bazel Version 5.0.0 on your machine. Other versions may +you need to install Bazel Version 7.0.2 on your machine. Other versions may also work, but are not verified. - [Emscripten SDK](https://emscripten.org) (optional): if building the WebAssembly module. diff --git a/kokoro/scripts/linux/build-docker.sh b/kokoro/scripts/linux/build-docker.sh index a0dc96abcf..e47037d54b 100755 --- a/kokoro/scripts/linux/build-docker.sh +++ b/kokoro/scripts/linux/build-docker.sh @@ -191,7 +191,7 @@ elif [ $TOOL = "android-ndk-build" ]; then echo $(date): ndk-build completed. elif [ $TOOL = "bazel" ]; then - using bazel-5.0.0 + using bazel-7.0.2 echo $(date): Build everything... bazel build --cxxopt=-std=c++17 :all From efb0fce2d6e8b68ec5a0adafccbcab27934efe96 Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Thu, 14 Mar 2024 14:42:12 -0700 Subject: [PATCH 404/523] Use bazel 7 and bzlmod (#5601) * Use bazel 7 and bzlmod Many of our dependencies are now using bazel 7 and the new bzlmod module system. This has been breaking our autoroll; this PR should fix the issues we've been having with that. It may or may not be worthwhile to update effcee to use bzlmod as well; this would let us get rid of WORKSPACE entirely. * Try to force cla check to rerun --- .bazelrc | 3 +++ .bazelversion | 2 +- .gitignore | 1 + BUILD.bazel | 56 +++++++++++++++++++++++++-------------------------- DEPS | 2 +- MODULE.bazel | 7 +++++++ WORKSPACE | 35 +------------------------------- 7 files changed, 42 insertions(+), 64 deletions(-) create mode 100644 MODULE.bazel diff --git a/.bazelrc b/.bazelrc index ff6db819b6..79ad59480f 100644 --- a/.bazelrc +++ b/.bazelrc @@ -1,3 +1,6 @@ +# Enable Bzlmod for every Bazel command +common --enable_bzlmod + build --enable_platform_specific_config build:linux --cxxopt=-std=c++17 build:macos --cxxopt=-std=c++17 diff --git a/.bazelversion b/.bazelversion index 0062ac9718..a8907c025d 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -5.0.0 +7.0.2 diff --git a/.gitignore b/.gitignore index d9c6a1a496..e85cea95d2 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ bazel-out bazel-spirv-tools bazel-SPIRV-Tools bazel-testlogs +MODULE.bazel.lock # Vim [._]*.s[a-w][a-z] diff --git a/BUILD.bazel b/BUILD.bazel index b83fd5aead..24c1c8e48a 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -426,7 +426,7 @@ cc_library( copts = TEST_COPTS, deps = [ ":spirv_tools_internal", - "@com_google_googletest//:gtest", + "@googletest//:gtest", ], ) @@ -446,8 +446,8 @@ cc_library( "tools_util", ":spirv_tools_internal", ":test_lib", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", + "@googletest//:gtest", + "@googletest//:gtest_main", ], ) for f in glob( [ @@ -467,8 +467,8 @@ cc_test( linkstatic = 1, deps = [ ":spirv_tools_opt_internal", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", + "@googletest//:gtest", + "@googletest//:gtest_main", "@spirv_headers//:spirv_cpp11_headers", ], ) @@ -481,8 +481,8 @@ cc_test( linkstatic = 1, deps = [ ":spirv_tools_internal", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", + "@googletest//:gtest", + "@googletest//:gtest_main", ], ) @@ -508,8 +508,8 @@ cc_library( linkstatic = 1, deps = [ ":link_test_lib", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", + "@googletest//:gtest", + "@googletest//:gtest_main", ], ) for f in glob( ["test/link/*_test.cpp"], @@ -525,8 +525,8 @@ cc_library( ":spirv_tools", ":spirv_tools_lint_internal", ":spirv_tools_opt_internal", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", + "@googletest//:gtest", + "@googletest//:gtest_main", ], ) for f in glob( ["test/lint/*_test.cpp"], @@ -550,7 +550,7 @@ cc_library( ":spirv_tools_internal", ":spirv_tools_opt_internal", "@com_google_effcee//:effcee", - "@com_google_googletest//:gtest", + "@googletest//:gtest", ], ) @@ -566,8 +566,8 @@ cc_library( ":spirv_tools_opt_internal", ":test_lib", "@com_google_effcee//:effcee", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", + "@googletest//:gtest", + "@googletest//:gtest_main", ], ) for f in glob(["test/opt/*_test.cpp"])] @@ -580,8 +580,8 @@ cc_library( deps = [ ":opt_test_lib", ":spirv_tools_opt_internal", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", + "@googletest//:gtest", + "@googletest//:gtest_main", ], ) for f in glob( ["test/opt/dominator_tree/*.cpp"], @@ -599,8 +599,8 @@ cc_library( ":spirv_tools", ":spirv_tools_opt_internal", "@com_google_effcee//:effcee", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", + "@googletest//:gtest", + "@googletest//:gtest_main", ], ) for f in glob( ["test/opt/loop_optimizations/*.cpp"], @@ -621,7 +621,7 @@ cc_library( ":spirv_tools_reduce", ":test_lib", ":tools_io", - "@com_google_googletest//:gtest", + "@googletest//:gtest", ], ) @@ -636,7 +636,7 @@ cc_library( ":spirv_tools_internal", ":spirv_tools_opt_internal", ":spirv_tools_reduce", - "@com_google_googletest//:gtest_main", + "@googletest//:gtest_main", ], ) for f in glob(["test/reduce/*_test.cpp"])] @@ -648,8 +648,8 @@ cc_library( linkstatic = 1, deps = [ ":spirv_tools_internal", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", + "@googletest//:gtest", + "@googletest//:gtest_main", ], ) for f in glob(["test/util/*_test.cpp"])] @@ -680,8 +680,8 @@ cc_library( ":spirv_tools_internal", ":test_lib", ":val_test_lib", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", + "@googletest//:gtest", + "@googletest//:gtest_main", ], ) for f in glob( ["test/val/val_*_test.cpp"], @@ -702,8 +702,8 @@ cc_test( ":spirv_tools_internal", ":test_lib", ":val_test_lib", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", + "@googletest//:gtest", + "@googletest//:gtest_main", ], ) @@ -719,7 +719,7 @@ cc_test( deps = [ ":test_lib", ":val_test_lib", - "@com_google_googletest//:gtest", - "@com_google_googletest//:gtest_main", + "@googletest//:gtest", + "@googletest//:gtest_main", ], ) diff --git a/DEPS b/DEPS index d117c59e92..fb314f62dc 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': 'ed9fc269e2fdb299afe59e912928d31ad3fdcf7d', + 're2_revision': 'dbf15a205c5b28fe7e8c43df2e036bbf47c9cb57', 'spirv_headers_revision': '8b246ff75c6615ba4532fe4fde20f1be090c3764', } diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000000..c36fe456fd --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,7 @@ +bazel_dep(name = "bazel_skylib", version = "1.5.0") + +bazel_dep(name = "googletest", dev_dependency = True) +local_path_override( + module_name = "googletest", + path = "external/googletest", +) diff --git a/WORKSPACE b/WORKSPACE index 8f49808900..6e780594c3 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -1,41 +1,8 @@ -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") - -http_archive( - name = "bazel_skylib", - strip_prefix = "bazel-skylib-main", - urls = ["https://github.com/bazelbuild/bazel-skylib/archive/main.zip"], -) - -# Override bazel's default `platforms`, since googletest requires a newer version. This can be removed once we use a newer Bazel version. -http_archive( - name = "platforms", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz", - "https://github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz", - ], - sha256 = "8150406605389ececb6da07cbcb509d5637a3ab9a24bc69b1101531367d89d74", -) - -# `platforms` needs `rules_license` on Windows. This can be removed if `platforms` above is removed. -http_archive( - name = "rules_license", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_license/releases/download/0.0.8/rules_license-0.0.8.tar.gz", - "https://github.com/bazelbuild/rules_license/releases/download/0.0.8/rules_license-0.0.8.tar.gz", - ], - sha256 = "241b06f3097fd186ff468832150d6cc142247dc42a32aaefb56d0099895fd229", -) - local_repository( name = "spirv_headers", path = "external/spirv-headers", ) -local_repository( - name = "com_google_googletest", - path = "external/googletest", -) - local_repository( name = "com_googlesource_code_re2", path = "external/re2", @@ -47,6 +14,6 @@ local_repository( ) local_repository( - name = "com_google_absl", + name = "abseil-cpp", path = "external/abseil_cpp", ) From e39cabca20f6621b8fdde565516a1de47507930d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 18:15:11 -0400 Subject: [PATCH 405/523] build(deps): bump the github-actions group with 2 updates (#5610) Bumps the github-actions group with 2 updates: [actions/checkout](https://github.com/actions/checkout) and [github/codeql-action](https://github.com/github/codeql-action). Updates `actions/checkout` from 4.1.1 to 4.1.2 - [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/b4ffde65f46336ab88eb53be808477a3936bae11...9bb56186c3b09b4f86b1c65136769dd318469633) Updates `github/codeql-action` from 3.24.6 to 3.24.7 - [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/8a470fddafa5cbb6266ee11b37ef4d8aae19c571...3ab4101902695724f9365a384f86c1074d94e18c) --- updated-dependencies: - dependency-name: actions/checkout 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/autoroll.yml | 2 +- .github/workflows/bazel.yml | 2 +- .github/workflows/ios.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/scorecard.yml | 4 ++-- .github/workflows/wasm.yml | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/autoroll.yml b/.github/workflows/autoroll.yml index 8e8c3a4203..e9b3176cf1 100644 --- a/.github/workflows/autoroll.yml +++ b/.github/workflows/autoroll.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 # 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 33840b855c..a0865bf47e 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -18,7 +18,7 @@ jobs: runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: '0' - name: Download dependencies diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 70a0729e54..cc39c9a6cf 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -11,7 +11,7 @@ jobs: matrix: os: [ macos-12, macos-13 ] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - uses: lukka/get-cmake@139aae96315b496d9af1b5e9abe53b15ca7eece8 # v3.28.3 - name: Download dependencies run: python3 utils/git-sync-deps diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f3b3de9199..78750d906e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: prepare-release-job: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - 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 d800df2c05..18e45fb1ff 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -23,7 +23,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: persist-credentials: false @@ -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@8a470fddafa5cbb6266ee11b37ef4d8aae19c571 # v3.24.6 + uses: github/codeql-action/upload-sarif@3ab4101902695724f9365a384f86c1074d94e18c # v3.24.7 with: sarif_file: results.sarif diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 552e56a9db..06ad522b34 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: '0' - name: Build web From f74f4e74c5ab33907642a58ce88ee2128d225d31 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 16:27:52 +0000 Subject: [PATCH 406/523] Roll external/re2/ ed9fc269e..d00d1e937 (2 commits) (#5589) * Roll external/googletest/ 5df0241ea..b479e7a3c (11 commits) https://github.com/google/googletest/compare/5df0241ea488...b479e7a3c161 $ git log 5df0241ea..b479e7a3c --date=short --no-merges --format='%ad %ae %s' 2024-03-11 dcheng Guard Abseil flags usage in googlemock with GTEST_NO_ABSL_FLAGS. 2024-03-07 absl-team Reland: Optimize Google Test process startup 2024-03-05 absl-team Revert Optimize Google Test process startup 2024-03-05 absl-team Optimize Google Test process startup 2024-02-29 absl-team Accept one-shot callables in InvokeArgument. 2024-02-27 absl-team Reland https://github.com/google/googletest/commit/9756ee7cbaef1b6652065616ab832810a6032bbf 2024-02-27 absl-team Make sure that current_test_suite and current_test_info are mutex-protected while writing for thread-safety. 2024-02-23 tmiguelf Fixed gcc linker error 58 2024-02-22 absl-team Revert incorrect update. 2024-02-21 dmauro Rollback https://github.com/google/googletest/commit/9756ee7cbaef1b6652065616ab832810a6032bbf 2024-02-11 155268264+danfabo Get include dirs from target rather than global variables. Created with: roll-dep external/googletest * Roll external/re2/ dbf15a205..108914d28 (3 commits) https://github.com/google/re2/compare/dbf15a205c5b...108914d28a79 $ git log dbf15a205..108914d28 --date=short --no-merges --format='%ad %ae %s' 2024-03-11 junyer `p0deje/setup-bazel` has been transferred to `bazel-contrib`. 2024-03-11 junyer Add Clang 18 to the build matrix. 2024-03-07 junyer Delete an old comment. 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 fb314f62dc..5caea64638 100644 --- a/DEPS +++ b/DEPS @@ -7,12 +7,12 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '5df0241ea4880e5a846775d3efc8b873f7b36c31', + 'googletest_revision': 'b479e7a3c161d7087113a05f8cb034b870313a55', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': 'dbf15a205c5b28fe7e8c43df2e036bbf47c9cb57', + 're2_revision': '108914d28a79243d4300e7e651cd0a0d5883ca0f', 'spirv_headers_revision': '8b246ff75c6615ba4532fe4fde20f1be090c3764', } From f20663ca7fec48fdc88e4c4d7c5889f8b4cc5664 Mon Sep 17 00:00:00 2001 From: Romaric Jodin <89833130+rjodinchr@users.noreply.github.com> Date: Fri, 15 Mar 2024 18:46:42 +0100 Subject: [PATCH 407/523] add support for vulkan-shader-profiler external passes (#5512) --- Android.mk | 1 + BUILD.bazel | 3 +++ BUILD.gn | 4 ++++ include/spirv-tools/libspirv.h | 1 + source/CMakeLists.txt | 1 + source/ext_inst.cpp | 10 +++++++++- source/opt/constants.cpp | 4 ++-- source/table.h | 2 +- 8 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Android.mk b/Android.mk index 3cf3f19b1d..e3e30bb3bb 100644 --- a/Android.mk +++ b/Android.mk @@ -289,6 +289,7 @@ $(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),spv-amd-shader-bal $(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),spv-amd-shader-explicit-vertex-parameter,"")) $(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),spv-amd-shader-trinary-minmax,"")) $(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),nonsemantic.clspvreflection,"")) +$(eval $(call gen_spvtools_vendor_tables,$(SPVTOOLS_OUT_PATH),nonsemantic.vkspreflection,"")) define gen_spvtools_enum_string_mapping $(call generate-file-dir,$(1)/extension_enum.inc.inc) diff --git a/BUILD.bazel b/BUILD.bazel index 24c1c8e48a..48a688e7cd 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -58,6 +58,8 @@ generate_vendor_tables(extension = "debuginfo") generate_vendor_tables(extension = "nonsemantic.clspvreflection") +generate_vendor_tables(extension = "nonsemantic.vkspreflection") + generate_vendor_tables( extension = "opencl.debuginfo.100", operand_kind_prefix = "CLDEBUG100_", @@ -146,6 +148,7 @@ cc_library( ":gen_opencl_tables_unified1", ":gen_vendor_tables_debuginfo", ":gen_vendor_tables_nonsemantic_clspvreflection", + ":gen_vendor_tables_nonsemantic_vkspreflection", ":gen_vendor_tables_nonsemantic_shader_debuginfo_100", ":gen_vendor_tables_opencl_debuginfo_100", ":gen_vendor_tables_spv_amd_gcn_shader", diff --git a/BUILD.gn b/BUILD.gn index 7c42a99a53..5d0ab86798 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -327,6 +327,10 @@ spvtools_vendor_tables = [ "nonsemantic.clspvreflection", "...nil...", ], + [ + "nonsemantic.vkspreflection", + "...nil...", + ], [ "nonsemantic.shader.debuginfo.100", "SHDEBUG100_", diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index a7b57b821e..08cfd6579b 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -333,6 +333,7 @@ typedef enum spv_ext_inst_type_t { SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100, SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION, SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100, + SPV_EXT_INST_TYPE_NONSEMANTIC_VKSPREFLECTION, // Multiple distinct extended instruction set types could return this // value, if they are prefixed with NonSemantic. and are otherwise diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index f4ee3c84cf..d0454c6c70 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -156,6 +156,7 @@ spvtools_vendor_tables("debuginfo" "debuginfo" "") spvtools_vendor_tables("opencl.debuginfo.100" "cldi100" "CLDEBUG100_") spvtools_vendor_tables("nonsemantic.shader.debuginfo.100" "shdi100" "SHDEBUG100_") spvtools_vendor_tables("nonsemantic.clspvreflection" "clspvreflection" "") +spvtools_vendor_tables("nonsemantic.vkspreflection" "vkspreflection" "") spvtools_extinst_lang_headers("DebugInfo" ${DEBUGINFO_GRAMMAR_JSON_FILE}) spvtools_extinst_lang_headers("OpenCLDebugInfo100" ${CLDEBUGINFO100_GRAMMAR_JSON_FILE}) spvtools_extinst_lang_headers("NonSemanticShaderDebugInfo100" ${VKDEBUGINFO100_GRAMMAR_JSON_FILE}) diff --git a/source/ext_inst.cpp b/source/ext_inst.cpp index 4e2795453f..9a5ba84e46 100644 --- a/source/ext_inst.cpp +++ b/source/ext_inst.cpp @@ -30,6 +30,7 @@ #include "glsl.std.450.insts.inc" #include "nonsemantic.clspvreflection.insts.inc" #include "nonsemantic.shader.debuginfo.100.insts.inc" +#include "nonsemantic.vkspreflection.insts.inc" #include "opencl.debuginfo.100.insts.inc" #include "opencl.std.insts.inc" @@ -62,6 +63,9 @@ static const spv_ext_inst_group_t kGroups_1_0[] = { {SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION, ARRAY_SIZE(nonsemantic_clspvreflection_entries), nonsemantic_clspvreflection_entries}, + {SPV_EXT_INST_TYPE_NONSEMANTIC_VKSPREFLECTION, + ARRAY_SIZE(nonsemantic_vkspreflection_entries), + nonsemantic_vkspreflection_entries}, }; static const spv_ext_inst_table_t kTable_1_0 = {ARRAY_SIZE(kGroups_1_0), @@ -138,6 +142,9 @@ spv_ext_inst_type_t spvExtInstImportTypeGet(const char* name) { if (!strncmp("NonSemantic.ClspvReflection.", name, 28)) { return SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION; } + if (!strncmp("NonSemantic.VkspReflection.", name, 27)) { + return SPV_EXT_INST_TYPE_NONSEMANTIC_VKSPREFLECTION; + } // ensure to add any known non-semantic extended instruction sets // above this point, and update spvExtInstIsNonSemantic() if (!strncmp("NonSemantic.", name, 12)) { @@ -149,7 +156,8 @@ spv_ext_inst_type_t spvExtInstImportTypeGet(const char* name) { bool spvExtInstIsNonSemantic(const spv_ext_inst_type_t type) { if (type == SPV_EXT_INST_TYPE_NONSEMANTIC_UNKNOWN || type == SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100 || - type == SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION) { + type == SPV_EXT_INST_TYPE_NONSEMANTIC_CLSPVREFLECTION || + type == SPV_EXT_INST_TYPE_NONSEMANTIC_VKSPREFLECTION) { return true; } return false; diff --git a/source/opt/constants.cpp b/source/opt/constants.cpp index a487a45b88..6eebbb572a 100644 --- a/source/opt/constants.cpp +++ b/source/opt/constants.cpp @@ -498,7 +498,7 @@ const Constant* ConstantManager::GetIntConst(uint64_t val, int32_t bitWidth, int32_t num_of_bit_to_ignore = 64 - bitWidth; val = static_cast(val << num_of_bit_to_ignore) >> num_of_bit_to_ignore; - } else { + } else if (bitWidth < 64) { // Clear the upper bit that are not used. uint64_t mask = ((1ull << bitWidth) - 1); val &= mask; @@ -511,7 +511,7 @@ const Constant* ConstantManager::GetIntConst(uint64_t val, int32_t bitWidth, // If the value is more than 32-bit, we need to split the operands into two // 32-bit integers. return GetConstant( - int_type, {static_cast(val >> 32), static_cast(val)}); + int_type, {static_cast(val), static_cast(val >> 32)}); } uint32_t ConstantManager::GetUIntConstId(uint32_t val) { diff --git a/source/table.h b/source/table.h index 8097f13f77..4f1dc1f843 100644 --- a/source/table.h +++ b/source/table.h @@ -74,7 +74,7 @@ typedef struct spv_ext_inst_desc_t { const uint32_t ext_inst; const uint32_t numCapabilities; const spv::Capability* capabilities; - const spv_operand_type_t operandTypes[16]; // TODO: Smaller/larger? + const spv_operand_type_t operandTypes[40]; // vksp needs at least 40 } spv_ext_inst_desc_t; typedef struct spv_ext_inst_group_t { From c6615779ef8a1eb5ef48fef77bf3eb2cf4f5438d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 16:58:32 +0000 Subject: [PATCH 408/523] Roll external/googletest/ b479e7a3c..c231e6f5b (1 commit) (#5613) * Roll external/googletest/ b479e7a3c..c231e6f5b (1 commit) https://github.com/google/googletest/compare/b479e7a3c161...c231e6f5b152 $ git log b479e7a3c..c231e6f5b --date=short --no-merges --format='%ad %ae %s' 2024-03-14 absl-team Add test for move-only type in `Action` signature Created with: roll-dep external/googletest * Roll external/re2/ 108914d28..db46d1e11 (3 commits) https://github.com/google/re2/compare/108914d28a79...db46d1e11eee $ git log 108914d28..db46d1e11 --date=short --no-merges --format='%ad %ae %s' 2024-03-17 junyer Bump versions of actions to latest releases. 2024-03-17 junyer Fix the link to the Python wrapper. 2024-03-15 oleksandr.red+github doc/mksyntaxgo: use standard generated Go header 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 5caea64638..d421ac7e2d 100644 --- a/DEPS +++ b/DEPS @@ -7,12 +7,12 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': 'b479e7a3c161d7087113a05f8cb034b870313a55', + 'googletest_revision': 'c231e6f5b152029dbd5fa4a9e0c04095035aec3f', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '108914d28a79243d4300e7e651cd0a0d5883ca0f', + 're2_revision': 'db46d1e11eee1ad501e8e08411747468d1d6a87e', 'spirv_headers_revision': '8b246ff75c6615ba4532fe4fde20f1be090c3764', } From 6c3f632a2c5264d6419fdfb07d602ca1bfa35469 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 04:19:53 +0000 Subject: [PATCH 409/523] roll deps (#5614) * Roll external/googletest/ c231e6f5b..eff443c6e (1 commit) https://github.com/google/googletest/compare/c231e6f5b152...eff443c6ef5e $ git log c231e6f5b..eff443c6e --date=short --no-merges --format='%ad %ae %s' 2024-03-16 memdo Add colored output support for Alacritty Created with: roll-dep external/googletest * Roll external/re2/ db46d1e11..6598a8ecd (2 commits) https://github.com/google/re2/compare/db46d1e11eee...6598a8ecd577 $ git log db46d1e11..6598a8ecd --date=short --no-merges --format='%ad %ae %s' 2024-03-18 junyer Make compiling a no-op if it's attempted before adding any patterns. 2024-03-17 junyer Raise `re2.error` instead of crashing. 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 d421ac7e2d..780c565de0 100644 --- a/DEPS +++ b/DEPS @@ -7,12 +7,12 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': 'c231e6f5b152029dbd5fa4a9e0c04095035aec3f', + 'googletest_revision': 'eff443c6ef5eb6ab598bfaae27f9427fdb4f6af7', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': 'db46d1e11eee1ad501e8e08411747468d1d6a87e', + 're2_revision': '6598a8ecd57724c8c7d43b2fca8eb9f9969ce57c', 'spirv_headers_revision': '8b246ff75c6615ba4532fe4fde20f1be090c3764', } From 3a0471c3b6b24517a37e9e44dbe7eefffb5b493e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 12:49:03 -0400 Subject: [PATCH 410/523] build(deps): bump the github-actions group with 1 update (#5615) Bumps the github-actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action). Updates `github/codeql-action` from 3.24.7 to 3.24.8 - [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/3ab4101902695724f9365a384f86c1074d94e18c...05963f47d870e2cb19a537396c1f668a348c7d8f) --- 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 18e45fb1ff..6ca5dfd19b 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@3ab4101902695724f9365a384f86c1074d94e18c # v3.24.7 + uses: github/codeql-action/upload-sarif@05963f47d870e2cb19a537396c1f668a348c7d8f # v3.24.8 with: sarif_file: results.sarif From 3fafcc20e620e60467ff1e851ae9e26c15ed1583 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 03:47:00 +0000 Subject: [PATCH 411/523] Roll external/spirv-headers/ 8b246ff75..04db24d69 (1 commit) (#5617) https://github.com/KhronosGroup/SPIRV-Headers/compare/8b246ff75c66...04db24d69163 $ git log 8b246ff75..04db24d69 --date=short --no-merges --format='%ad %ae %s' 2024-03-20 admin Register spq tools for SPIR-V (#399) 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 780c565de0..1a7fd02986 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': '6598a8ecd57724c8c7d43b2fca8eb9f9969ce57c', - 'spirv_headers_revision': '8b246ff75c6615ba4532fe4fde20f1be090c3764', + 'spirv_headers_revision': '04db24d69163114dacc43097a724aaab7165a5d2', } deps = { From dda7731e91c130e64980d987a02f5c75356400cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 12:13:11 -0400 Subject: [PATCH 412/523] build(deps): bump the github-actions group with 2 updates (#5618) Bumps the github-actions group with 2 updates: [actions/cache](https://github.com/actions/cache) and [lukka/get-cmake](https://github.com/lukka/get-cmake). Updates `actions/cache` from 4.0.1 to 4.0.2 - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/ab5e6d0c87105b4c9c2047343972218f562e4319...0c45773b623bea8c8e75f6c82b208c3cf94ea4f9) Updates `lukka/get-cmake` from 3.28.3 to 3.28.4 - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/139aae96315b496d9af1b5e9abe53b15ca7eece8...70abef71925015c1c8e90a1a6af4185162412d91) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - 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/bazel.yml | 2 +- .github/workflows/ios.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index a0865bf47e..9dabf88a91 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -24,7 +24,7 @@ jobs: - name: Download dependencies run: python3 utils/git-sync-deps - name: Mount Bazel cache - uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319 # v4.0.1 + uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: ~/.bazel/cache key: bazel-cache-${{ runner.os }} diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index cc39c9a6cf..05e6a0e3e2 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@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - - uses: lukka/get-cmake@139aae96315b496d9af1b5e9abe53b15ca7eece8 # v3.28.3 + - uses: lukka/get-cmake@70abef71925015c1c8e90a1a6af4185162412d91 # v3.28.4 - name: Download dependencies run: python3 utils/git-sync-deps # NOTE: The MacOS SDK ships universal binaries. CI should reflect this. From 67451ebf6d4261b77e1794cf6557502ea8cc840e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 17:50:54 +0000 Subject: [PATCH 413/523] Roll external/spirv-headers/ 04db24d69..7d500c4d7 (1 commit) (#5619) https://github.com/KhronosGroup/SPIRV-Headers/compare/04db24d69163...7d500c4d75ae $ git log 04db24d69..7d500c4d7 --date=short --no-merges --format='%ad %ae %s' 2024-03-22 michal Register LLVM SPIR-V Backend as SPIR-V generator (#423) 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 1a7fd02986..4fe37334db 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': '6598a8ecd57724c8c7d43b2fca8eb9f9969ce57c', - 'spirv_headers_revision': '04db24d69163114dacc43097a724aaab7165a5d2', + 'spirv_headers_revision': '7d500c4d75ae3fbd37e1d5a20008ca9c8ee3c860', } deps = { From fc42865562700c887463d9a63512d6a73549ae6e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 14:08:39 -0400 Subject: [PATCH 414/523] build(deps): bump the github-actions group with 2 updates (#5621) Bumps the github-actions group with 2 updates: [lukka/get-cmake](https://github.com/lukka/get-cmake) and [github/codeql-action](https://github.com/github/codeql-action). Updates `lukka/get-cmake` from 3.28.4 to 3.29.0 - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/70abef71925015c1c8e90a1a6af4185162412d91...9438b96ac95a2a8b02548f63800926db324f7c03) Updates `github/codeql-action` from 3.24.8 to 3.24.9 - [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/05963f47d870e2cb19a537396c1f668a348c7d8f...1b1aada464948af03b950897e5eb522f92603cc2) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-type: direct:production update-type: version-update:semver-minor 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/ios.yml | 2 +- .github/workflows/scorecard.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 05e6a0e3e2..40f248095b 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@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - - uses: lukka/get-cmake@70abef71925015c1c8e90a1a6af4185162412d91 # v3.28.4 + - uses: lukka/get-cmake@9438b96ac95a2a8b02548f63800926db324f7c03 # v3.29.0 - name: Download dependencies run: python3 utils/git-sync-deps # NOTE: The MacOS SDK ships universal binaries. CI should reflect this. diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 6ca5dfd19b..7d624c6211 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@05963f47d870e2cb19a537396c1f668a348c7d8f # v3.24.8 + uses: github/codeql-action/upload-sarif@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9 with: sarif_file: results.sarif From fe7bae090629f64115eb41aa8c41df419cef9159 Mon Sep 17 00:00:00 2001 From: Kevin Gibson Date: Mon, 25 Mar 2024 14:21:09 -0700 Subject: [PATCH 415/523] Minor fix to cmakelists to avoid rerunning command each build (#5620) --- CMakeLists.txt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 07be2dfc91..0ba173f1d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -387,7 +387,8 @@ set(SPIRV_SHARED_LIBRARIES "-lSPIRV-Tools-shared") # Build pkg-config file # Use a first-class target so it's regenerated when relevant files are updated. -add_custom_target(spirv-tools-pkg-config ALL +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools.pc COMMAND ${CMAKE_COMMAND} -DCHANGES_FILE=${CMAKE_CURRENT_SOURCE_DIR}/CHANGES -DTEMPLATE_FILE=${CMAKE_CURRENT_SOURCE_DIR}/cmake/SPIRV-Tools.pc.in @@ -397,8 +398,9 @@ add_custom_target(spirv-tools-pkg-config ALL -DCMAKE_INSTALL_INCLUDEDIR=${CMAKE_INSTALL_INCLUDEDIR} -DSPIRV_LIBRARIES=${SPIRV_LIBRARIES} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake - DEPENDS "CHANGES" "cmake/SPIRV-Tools.pc.in" "cmake/write_pkg_config.cmake") -add_custom_target(spirv-tools-shared-pkg-config ALL + DEPENDS "CHANGES" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/SPIRV-Tools.pc.in" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake") +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools-shared.pc COMMAND ${CMAKE_COMMAND} -DCHANGES_FILE=${CMAKE_CURRENT_SOURCE_DIR}/CHANGES -DTEMPLATE_FILE=${CMAKE_CURRENT_SOURCE_DIR}/cmake/SPIRV-Tools-shared.pc.in @@ -408,7 +410,10 @@ add_custom_target(spirv-tools-shared-pkg-config ALL -DCMAKE_INSTALL_INCLUDEDIR=${CMAKE_INSTALL_INCLUDEDIR} -DSPIRV_SHARED_LIBRARIES=${SPIRV_SHARED_LIBRARIES} -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake - DEPENDS "CHANGES" "cmake/SPIRV-Tools-shared.pc.in" "cmake/write_pkg_config.cmake") + DEPENDS "CHANGES" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/SPIRV-Tools-shared.pc.in" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/write_pkg_config.cmake") +add_custom_target(spirv-tools-pkg-config + ALL + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools-shared.pc ${CMAKE_CURRENT_BINARY_DIR}/SPIRV-Tools.pc) # Install pkg-config file if (ENABLE_SPIRV_TOOLS_INSTALL) From 87721a10098c3229a03ba7754734a47fe93d9a10 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 28 Mar 2024 13:53:59 -0700 Subject: [PATCH 416/523] Roll external/spirv-headers/ 7d500c4d7..4f7b471f1 (1 commit) (#5625) https://github.com/KhronosGroup/SPIRV-Headers/compare/7d500c4d75ae...4f7b471f1a66 $ git log 7d500c4d7..4f7b471f1 --date=short --no-merges --format='%ad %ae %s' 2024-03-27 121976986+aejjehint Update bit reservations for loop controsl and memory operands (#424) 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 4fe37334db..aada5f7034 100644 --- a/DEPS +++ b/DEPS @@ -13,7 +13,7 @@ vars = { 'protobuf_revision': 'v21.12', 're2_revision': '6598a8ecd57724c8c7d43b2fca8eb9f9969ce57c', - 'spirv_headers_revision': '7d500c4d75ae3fbd37e1d5a20008ca9c8ee3c860', + 'spirv_headers_revision': '4f7b471f1a66b6d06462cd4ba57628cc0cd087d7', } deps = { From 7fe5f75e581014e920ab5d9a218ea2f37bbaa0d4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 29 Mar 2024 22:34:40 +0000 Subject: [PATCH 417/523] Roll external/re2/ 6598a8ecd..917047f36 (3 commits) (#5626) https://github.com/google/re2/compare/6598a8ecd577...917047f3606d $ git log 6598a8ecd..917047f36 --date=short --no-merges --format='%ad %ae %s' 2024-03-28 junyer Tell Bazel the specific target version of macOS too. Sigh. 2024-03-28 junyer Force a specific target version of macOS. 2024-03-28 junyer Prepare to tag release `2024-04-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 aada5f7034..9dcbb09aa9 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': '6598a8ecd57724c8c7d43b2fca8eb9f9969ce57c', + 're2_revision': '917047f3606d3ba9e2de0d383c3cd80c94ed732c', 'spirv_headers_revision': '4f7b471f1a66b6d06462cd4ba57628cc0cd087d7', } From 58ab8baf72d5abeff0b56e075fde714b16507b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 2 Apr 2024 18:39:12 +0200 Subject: [PATCH 418/523] docs: explain LunarG is the source of truth for releases (#5627) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitHub releases were just the exact same as the LunarG releases, since the same commit were used for both. For this reason, we don't think it brings any value, and will stop publishing new releases on the GitHub page. Signed-off-by: Nathan Gauër --- README.md | 26 +++++++++++++++----------- docs/downloads.md | 29 +++++++++++++++++------------ 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index e916a2c98a..7db5bd42a7 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,13 @@ headers, and XML registry. ## Downloads +The official releases for SPIRV-Tools can be found on LunarG's +[SDK download page](https://vulkan.lunarg.com/sdk/home). + +For convenience, here are also links to the latest builds (HEAD). +Those are untested automated builds. Those are not official releases, nor +are guaranteed to work. Official releases builds are in the Vulkan SDK. + Linux[![Linux Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_linux_clang_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_clang_release.html) MacOS[![MacOS Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_macos_clang_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_macos_clang_release.html) Windows[![Windows Build Status](https://storage.googleapis.com/spirv-tools/badges/build_status_windows_release.svg)](https://storage.googleapis.com/spirv-tools/badges/build_link_windows_vs2019_release.html) @@ -49,17 +56,14 @@ version. An API call reports the software version as a C-style string. ## Releases -Some versions of SPIRV-Tools are tagged as stable releases (see -[tags](https://github.com/KhronosGroup/SPIRV-Tools/tags) on github). -These versions undergo extra testing. -Releases are not directly related to releases (or versions) of -[SPIRV-Headers][spirv-headers]. -Releases of SPIRV-Tools are tested against the version of SPIRV-Headers listed -in the [DEPS](DEPS) file. -The release generally uses the most recent compatible version of SPIRV-Headers -available at the time of release. -No version of SPIRV-Headers other than the one listed in the DEPS file is -guaranteed to work with the SPIRV-Tools release. +The official releases for SPIRV-Tools can be found on LunarG's +[SDK download page](https://vulkan.lunarg.com/sdk/home). + +You can find either the prebuilt, and QA tested binaries, or download the +SDK Config, which lists the commits to use to build the release from scratch. + +GitHub releases are deprecated, and we will not publish new releases until +further notice. ## Supported features diff --git a/docs/downloads.md b/docs/downloads.md index f56b6fe992..0454b9ea6f 100644 --- a/docs/downloads.md +++ b/docs/downloads.md @@ -1,6 +1,22 @@ # Downloads -## Latest builds +## Vulkan SDK + +The official releases for SPIRV-Tools can be found on LunarG's +[SDK download page](https://vulkan.lunarg.com/sdk/home). +The Vulkan SDK is updated approximately every six weeks. + +## Android NDK + +SPIRV-Tools host executables, and library sources are published as +part of the [Android NDK](https://developer.android.com/ndk/downloads). + +## Automated builds + +For convenience, here are also links to the latest builds (HEAD). +Those are untested automated builds. Those are not official releases, nor +are guaranteed to work. Official releases builds are in the Android NDK or +Vulkan SDK. Download the latest builds of the [main](https://github.com/KhronosGroup/SPIRV-Tools/tree/main) branch. @@ -15,14 +31,3 @@ Download the latest builds of the [main](https://github.com/KhronosGroup/SPIRV-T | --- | --- | --- | | [MSVC 2017](https://storage.googleapis.com/spirv-tools/badges/build_link_windows_vs2017_debug.html) | [clang](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_clang_debug.html) | [clang](https://storage.googleapis.com/spirv-tools/badges/build_link_macos_clang_debug.html) | | | [gcc](https://storage.googleapis.com/spirv-tools/badges/build_link_linux_gcc_debug.html) | | - - -## Vulkan SDK - -SPIRV-Tools is published as part of the [LunarG Vulkan SDK](https://www.lunarg.com/vulkan-sdk/). -The Vulkan SDK is updated approximately every six weeks. - -## Android NDK - -SPIRV-Tools host executables, and library sources are published as -part of the [Android NDK](https://developer.android.com/ndk/downloads). From 24f2cdad8ec6ecf02a08e516d9af0d846f72ae99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 13:39:15 -0400 Subject: [PATCH 419/523] build(deps): bump the github-actions group with 1 update (#5634) Bumps the github-actions group with 1 update: [lukka/get-cmake](https://github.com/lukka/get-cmake). Updates `lukka/get-cmake` from 3.29.0 to 3.29.1 - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/9438b96ac95a2a8b02548f63800926db324f7c03...b111a57714ab6e67a65d3f857b72b148554c4262) --- 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 40f248095b..10ee627a0d 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@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - - uses: lukka/get-cmake@9438b96ac95a2a8b02548f63800926db324f7c03 # v3.29.0 + - uses: lukka/get-cmake@b111a57714ab6e67a65d3f857b72b148554c4262 # v3.29.1 - name: Download dependencies run: python3 utils/git-sync-deps # NOTE: The MacOS SDK ships universal binaries. CI should reflect this. From ade1f7cfd7dbe41f30e19dc11cc168a1aa67a34a Mon Sep 17 00:00:00 2001 From: Jeremy Hayes Date: Fri, 5 Apr 2024 11:45:55 -0600 Subject: [PATCH 420/523] Add AliasedPointer decoration (#5635) Fix #5607 When inlining, decorate return variable with AliasedPointer if the storage class of the pointee type is PhysicalStorageBuffer. --- source/opt/inline_pass.cpp | 13 ++++++++++ test/opt/inline_test.cpp | 49 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/source/opt/inline_pass.cpp b/source/opt/inline_pass.cpp index 3f160b24cd..318643341a 100644 --- a/source/opt/inline_pass.cpp +++ b/source/opt/inline_pass.cpp @@ -213,6 +213,19 @@ uint32_t InlinePass::CreateReturnVar( {(uint32_t)spv::StorageClass::Function}}})); new_vars->push_back(std::move(var_inst)); get_decoration_mgr()->CloneDecorations(calleeFn->result_id(), returnVarId); + + // Decorate the return var with AliasedPointer if the storage class of the + // pointee type is PhysicalStorageBuffer. + auto const pointee_type = + type_mgr->GetType(returnVarTypeId)->AsPointer()->pointee_type(); + if (pointee_type->AsPointer() != nullptr) { + if (pointee_type->AsPointer()->storage_class() == + spv::StorageClass::PhysicalStorageBuffer) { + get_decoration_mgr()->AddDecoration( + returnVarId, uint32_t(spv::Decoration::AliasedPointer)); + } + } + return returnVarId; } diff --git a/test/opt/inline_test.cpp b/test/opt/inline_test.cpp index 1e5d9f3b4a..bf791811d5 100644 --- a/test/opt/inline_test.cpp +++ b/test/opt/inline_test.cpp @@ -4422,6 +4422,55 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } +TEST_F(InlineTest, DecorateReturnVariableWithAliasedPointer) { + const std::string text = R"(OpCapability Int64 + OpCapability VariablePointers + OpCapability PhysicalStorageBufferAddresses + OpCapability Shader + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_KHR_variable_pointers" + OpExtension "SPV_KHR_physical_storage_buffer" + OpMemoryModel PhysicalStorageBuffer64 GLSL450 + OpEntryPoint GLCompute %1 "main" + OpExecutionMode %1 LocalSize 8 8 1 + OpDecorate %_ptr_PhysicalStorageBuffer__struct_5 ArrayStride 8 + OpMemberDecorate %_struct_3 0 Offset 0 + OpMemberDecorate %_struct_3 1 Offset 8 + OpDecorate %_ptr_PhysicalStorageBuffer_int ArrayStride 4 + OpMemberDecorate %_struct_5 0 Offset 0 + OpMemberDecorate %_struct_5 1 Offset 4 + OpDecorate %6 Aliased +; CHECK: OpDecorate %22 AliasedPointer + %void = OpTypeVoid + %8 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + OpTypeForwardPointer %_ptr_PhysicalStorageBuffer__struct_5 PhysicalStorageBuffer + %_struct_3 = OpTypeStruct %int %_ptr_PhysicalStorageBuffer__struct_5 +%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int + %_struct_5 = OpTypeStruct %int %int + %11 = OpTypeFunction %_ptr_PhysicalStorageBuffer_int %_ptr_PhysicalStorageBuffer__struct_5 +%_ptr_PhysicalStorageBuffer__struct_5 = OpTypePointer PhysicalStorageBuffer %_struct_5 +%_ptr_Function__struct_3 = OpTypePointer Function %_struct_3 + %1 = OpFunction %void None %8 + %13 = OpLabel + %14 = OpVariable %_ptr_Function__struct_3 Function + %15 = OpLoad %_struct_3 %14 + %16 = OpCompositeExtract %_ptr_PhysicalStorageBuffer__struct_5 %15 1 + %17 = OpFunctionCall %_ptr_PhysicalStorageBuffer_int %18 %16 + OpReturn + OpFunctionEnd + %18 = OpFunction %_ptr_PhysicalStorageBuffer_int None %11 + %6 = OpFunctionParameter %_ptr_PhysicalStorageBuffer__struct_5 + %19 = OpLabel + %20 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %6 %int_0 + OpReturnValue %20 + OpFunctionEnd)"; + + SetTargetEnv(SPV_ENV_VULKAN_1_2); + SinglePassRunAndMatch(text, true); +} + // TODO(greg-lunarg): Add tests to verify handling of these cases: // // Empty modules From 3983d15a1d34fb95656818af0fc89c6260cbf316 Mon Sep 17 00:00:00 2001 From: Diego Novillo Date: Tue, 9 Apr 2024 10:36:21 -0400 Subject: [PATCH 421/523] Fix rebuilding types with circular references (#5623). (#5637) This fixes the problem reported in #5623 using the observation that if we are re-building a type that already exists in the type pool, we should just return that type. This makes type rebuilding more efficient, and it also prevents the type builder from getting itself into infinite recursion (as reported in this issue). In fixing this, I found a couple of other bugs in the type builder: - When rebuilding an Array type, we were not re-building the element type. This caused stale type references in the rebuilt type. - This bug had not been caught by the test, because the test itself had a bug in it: the test was rebuilding types on top of the same ID (the ID counter was never incremented). Initially, the bug in the test caused a failure with the new logic in the builder because we now return types from the pool directly, which causes a failure when two incompatible types are registered under the same ID. Fixing that issue in the test exposed another bug in the rebuilder: we were not re-building the element type for Array types. This was causing a stale type reference inside Array types which was later caught by the type removal logic in the test. --- source/opt/type_manager.cpp | 64 +++++++++++++++++++++------------- source/opt/type_manager.h | 4 ++- test/opt/type_manager_test.cpp | 38 ++++++++++++++++++-- 3 files changed, 79 insertions(+), 27 deletions(-) diff --git a/source/opt/type_manager.cpp b/source/opt/type_manager.cpp index ae320772df..7b609bc776 100644 --- a/source/opt/type_manager.cpp +++ b/source/opt/type_manager.cpp @@ -517,13 +517,24 @@ void TypeManager::CreateDecoration(uint32_t target, context()->get_def_use_mgr()->AnalyzeInstUse(inst); } -Type* TypeManager::RebuildType(const Type& type) { +Type* TypeManager::RebuildType(uint32_t type_id, const Type& type) { + assert(type_id != 0); + // The comparison and hash on the type pool will avoid inserting the rebuilt // type if an equivalent type already exists. The rebuilt type will be deleted // when it goes out of scope at the end of the function in that case. Repeated // insertions of the same Type will, at most, keep one corresponding object in // the type pool. std::unique_ptr rebuilt_ty; + + // If |type_id| is already present in the type pool, return the existing type. + // This saves extra work in the type builder and prevents running into + // circular issues (https://github.com/KhronosGroup/SPIRV-Tools/issues/5623). + Type* pool_ty = GetType(type_id); + if (pool_ty != nullptr) { + return pool_ty; + } + switch (type.kind()) { #define DefineNoSubtypeCase(kind) \ case Type::k##kind: \ @@ -550,43 +561,46 @@ Type* TypeManager::RebuildType(const Type& type) { case Type::kVector: { const Vector* vec_ty = type.AsVector(); const Type* ele_ty = vec_ty->element_type(); - rebuilt_ty = - MakeUnique(RebuildType(*ele_ty), vec_ty->element_count()); + rebuilt_ty = MakeUnique(RebuildType(GetId(ele_ty), *ele_ty), + vec_ty->element_count()); break; } case Type::kMatrix: { const Matrix* mat_ty = type.AsMatrix(); const Type* ele_ty = mat_ty->element_type(); - rebuilt_ty = - MakeUnique(RebuildType(*ele_ty), mat_ty->element_count()); + rebuilt_ty = MakeUnique(RebuildType(GetId(ele_ty), *ele_ty), + mat_ty->element_count()); break; } case Type::kImage: { const Image* image_ty = type.AsImage(); const Type* ele_ty = image_ty->sampled_type(); - rebuilt_ty = - MakeUnique(RebuildType(*ele_ty), image_ty->dim(), - image_ty->depth(), image_ty->is_arrayed(), - image_ty->is_multisampled(), image_ty->sampled(), - image_ty->format(), image_ty->access_qualifier()); + rebuilt_ty = MakeUnique( + RebuildType(GetId(ele_ty), *ele_ty), image_ty->dim(), + image_ty->depth(), image_ty->is_arrayed(), + image_ty->is_multisampled(), image_ty->sampled(), image_ty->format(), + image_ty->access_qualifier()); break; } case Type::kSampledImage: { const SampledImage* image_ty = type.AsSampledImage(); const Type* ele_ty = image_ty->image_type(); - rebuilt_ty = MakeUnique(RebuildType(*ele_ty)); + rebuilt_ty = + MakeUnique(RebuildType(GetId(ele_ty), *ele_ty)); break; } case Type::kArray: { const Array* array_ty = type.AsArray(); - rebuilt_ty = - MakeUnique(array_ty->element_type(), array_ty->length_info()); + const Type* ele_ty = array_ty->element_type(); + rebuilt_ty = MakeUnique(RebuildType(GetId(ele_ty), *ele_ty), + array_ty->length_info()); break; } case Type::kRuntimeArray: { const RuntimeArray* array_ty = type.AsRuntimeArray(); const Type* ele_ty = array_ty->element_type(); - rebuilt_ty = MakeUnique(RebuildType(*ele_ty)); + rebuilt_ty = + MakeUnique(RebuildType(GetId(ele_ty), *ele_ty)); break; } case Type::kStruct: { @@ -594,7 +608,7 @@ Type* TypeManager::RebuildType(const Type& type) { std::vector subtypes; subtypes.reserve(struct_ty->element_types().size()); for (const auto* ele_ty : struct_ty->element_types()) { - subtypes.push_back(RebuildType(*ele_ty)); + subtypes.push_back(RebuildType(GetId(ele_ty), *ele_ty)); } rebuilt_ty = MakeUnique(subtypes); Struct* rebuilt_struct = rebuilt_ty->AsStruct(); @@ -611,7 +625,7 @@ Type* TypeManager::RebuildType(const Type& type) { case Type::kPointer: { const Pointer* pointer_ty = type.AsPointer(); const Type* ele_ty = pointer_ty->pointee_type(); - rebuilt_ty = MakeUnique(RebuildType(*ele_ty), + rebuilt_ty = MakeUnique(RebuildType(GetId(ele_ty), *ele_ty), pointer_ty->storage_class()); break; } @@ -621,9 +635,10 @@ Type* TypeManager::RebuildType(const Type& type) { std::vector param_types; param_types.reserve(function_ty->param_types().size()); for (const auto* param_ty : function_ty->param_types()) { - param_types.push_back(RebuildType(*param_ty)); + param_types.push_back(RebuildType(GetId(param_ty), *param_ty)); } - rebuilt_ty = MakeUnique(RebuildType(*ret_ty), param_types); + rebuilt_ty = MakeUnique(RebuildType(GetId(ret_ty), *ret_ty), + param_types); break; } case Type::kForwardPointer: { @@ -633,7 +648,7 @@ Type* TypeManager::RebuildType(const Type& type) { const Pointer* target_ptr = forward_ptr_ty->target_pointer(); if (target_ptr) { rebuilt_ty->AsForwardPointer()->SetTargetPointer( - RebuildType(*target_ptr)->AsPointer()); + RebuildType(GetId(target_ptr), *target_ptr)->AsPointer()); } break; } @@ -641,16 +656,17 @@ Type* TypeManager::RebuildType(const Type& type) { const CooperativeMatrixNV* cm_type = type.AsCooperativeMatrixNV(); const Type* component_type = cm_type->component_type(); rebuilt_ty = MakeUnique( - RebuildType(*component_type), cm_type->scope_id(), cm_type->rows_id(), - cm_type->columns_id()); + RebuildType(GetId(component_type), *component_type), + cm_type->scope_id(), cm_type->rows_id(), cm_type->columns_id()); break; } case Type::kCooperativeMatrixKHR: { const CooperativeMatrixKHR* cm_type = type.AsCooperativeMatrixKHR(); const Type* component_type = cm_type->component_type(); rebuilt_ty = MakeUnique( - RebuildType(*component_type), cm_type->scope_id(), cm_type->rows_id(), - cm_type->columns_id(), cm_type->use_id()); + RebuildType(GetId(component_type), *component_type), + cm_type->scope_id(), cm_type->rows_id(), cm_type->columns_id(), + cm_type->use_id()); break; } default: @@ -669,7 +685,7 @@ Type* TypeManager::RebuildType(const Type& type) { void TypeManager::RegisterType(uint32_t id, const Type& type) { // Rebuild |type| so it and all its constituent types are owned by the type // pool. - Type* rebuilt = RebuildType(type); + Type* rebuilt = RebuildType(id, type); assert(rebuilt->IsSame(&type)); id_to_type_[id] = rebuilt; if (GetId(rebuilt) == 0) { diff --git a/source/opt/type_manager.h b/source/opt/type_manager.h index a70c371db0..948b691bac 100644 --- a/source/opt/type_manager.h +++ b/source/opt/type_manager.h @@ -260,7 +260,9 @@ class TypeManager { // Returns an equivalent pointer to |type| built in terms of pointers owned by // |type_pool_|. For example, if |type| is a vec3 of bool, it will be rebuilt // replacing the bool subtype with one owned by |type_pool_|. - Type* RebuildType(const Type& type); + // + // The re-built type will have ID |type_id|. + Type* RebuildType(uint32_t type_id, const Type& type); // Completes the incomplete type |type|, by replaces all references to // ForwardPointer by the defining Pointer. diff --git a/test/opt/type_manager_test.cpp b/test/opt/type_manager_test.cpp index 946f06cc08..d4d0fef524 100644 --- a/test/opt/type_manager_test.cpp +++ b/test/opt/type_manager_test.cpp @@ -942,10 +942,11 @@ OpMemoryModel Logical GLSL450 EXPECT_NE(context, nullptr); std::vector> types = GenerateAllTypes(); - uint32_t id = 1u; + uint32_t id = 0u; for (auto& t : types) { - context->get_type_mgr()->RegisterType(id, *t); + context->get_type_mgr()->RegisterType(++id, *t); EXPECT_EQ(*t, *context->get_type_mgr()->GetType(id)); + EXPECT_EQ(id, context->get_type_mgr()->GetId(t.get())); } types.clear(); @@ -1199,6 +1200,39 @@ OpMemoryModel Logical GLSL450 Match(text, context.get()); } +// Structures containing circular type references +// (from https://github.com/KhronosGroup/SPIRV-Tools/issues/5623). +TEST(TypeManager, CircularPointerToStruct) { + const std::string text = R"( + OpCapability VariablePointers + OpCapability PhysicalStorageBufferAddresses + OpCapability Int64 + OpCapability Shader + OpExtension "SPV_KHR_variable_pointers" + OpExtension "SPV_KHR_physical_storage_buffer" + OpMemoryModel PhysicalStorageBuffer64 GLSL450 + OpEntryPoint Fragment %1 "main" + OpExecutionMode %1 OriginUpperLeft + OpExecutionMode %1 DepthReplacing + OpDecorate %1200 ArrayStride 24 + OpMemberDecorate %600 0 Offset 0 + OpMemberDecorate %800 0 Offset 0 + OpMemberDecorate %120 0 Offset 16 + OpTypeForwardPointer %1200 PhysicalStorageBuffer + %600 = OpTypeStruct %1200 + %800 = OpTypeStruct %1200 + %120 = OpTypeStruct %800 + %1200 = OpTypePointer PhysicalStorageBuffer %120 + )"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + TypeManager manager(nullptr, context.get()); + uint32_t id = manager.FindPointerToType(600, spv::StorageClass::Function); + EXPECT_EQ(id, 1201); +} + } // namespace } // namespace analysis } // namespace opt From 6761288d39e2af51d73a5d8edb328dafc2054b1c Mon Sep 17 00:00:00 2001 From: Rodrigo Locatti Date: Wed, 10 Apr 2024 11:40:10 -0300 Subject: [PATCH 422/523] Validator: Support SPV_NV_raw_access_chains (#5568) --- source/opcode.cpp | 3 + source/val/validate_annotation.cpp | 3 +- source/val/validate_decorations.cpp | 8 +- source/val/validate_memory.cpp | 123 +++++ test/val/CMakeLists.txt | 1 + ...val_extension_spv_nv_raw_access_chains.cpp | 510 ++++++++++++++++++ 6 files changed, 644 insertions(+), 4 deletions(-) create mode 100644 test/val/val_extension_spv_nv_raw_access_chains.cpp diff --git a/source/opcode.cpp b/source/opcode.cpp index 38d1a1be6e..787dbb3403 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -295,6 +295,7 @@ bool spvOpcodeReturnsLogicalVariablePointer(const spv::Op opcode) { case spv::Op::OpPtrAccessChain: case spv::Op::OpLoad: case spv::Op::OpConstantNull: + case spv::Op::OpRawAccessChainNV: return true; default: return false; @@ -309,6 +310,7 @@ int32_t spvOpcodeReturnsLogicalPointer(const spv::Op opcode) { case spv::Op::OpFunctionParameter: case spv::Op::OpImageTexelPointer: case spv::Op::OpCopyObject: + case spv::Op::OpRawAccessChainNV: return true; default: return false; @@ -754,6 +756,7 @@ bool spvOpcodeIsAccessChain(spv::Op opcode) { case spv::Op::OpInBoundsAccessChain: case spv::Op::OpPtrAccessChain: case spv::Op::OpInBoundsPtrAccessChain: + case spv::Op::OpRawAccessChainNV: return true; default: return false; diff --git a/source/val/validate_annotation.cpp b/source/val/validate_annotation.cpp index 106004d066..dac3585788 100644 --- a/source/val/validate_annotation.cpp +++ b/source/val/validate_annotation.cpp @@ -161,7 +161,8 @@ spv_result_t ValidateDecorationTarget(ValidationState_t& _, spv::Decoration dec, case spv::Decoration::RestrictPointer: case spv::Decoration::AliasedPointer: if (target->opcode() != spv::Op::OpVariable && - target->opcode() != spv::Op::OpFunctionParameter) { + target->opcode() != spv::Op::OpFunctionParameter && + target->opcode() != spv::Op::OpRawAccessChainNV) { return fail(0) << "must be a memory object declaration"; } if (_.GetIdOpcode(target->type_id()) != spv::Op::OpTypePointer) { diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp index caa4a6f184..bb1fea5502 100644 --- a/source/val/validate_decorations.cpp +++ b/source/val/validate_decorations.cpp @@ -1556,7 +1556,8 @@ spv_result_t CheckNonWritableDecoration(ValidationState_t& vstate, const auto opcode = inst.opcode(); const auto type_id = inst.type_id(); if (opcode != spv::Op::OpVariable && - opcode != spv::Op::OpFunctionParameter) { + opcode != spv::Op::OpFunctionParameter && + opcode != spv::Op::OpRawAccessChainNV) { return vstate.diag(SPV_ERROR_INVALID_ID, &inst) << "Target of NonWritable decoration must be a memory object " "declaration (a variable or a function parameter)"; @@ -1569,10 +1570,11 @@ spv_result_t CheckNonWritableDecoration(ValidationState_t& vstate, vstate.features().nonwritable_var_in_function_or_private) { // New permitted feature in SPIR-V 1.4. } else if ( - // It may point to a UBO, SSBO, or storage image. + // It may point to a UBO, SSBO, storage image, or raw access chain. vstate.IsPointerToUniformBlock(type_id) || vstate.IsPointerToStorageBuffer(type_id) || - vstate.IsPointerToStorageImage(type_id)) { + vstate.IsPointerToStorageImage(type_id) || + opcode == spv::Op::OpRawAccessChainNV) { } else { return vstate.diag(SPV_ERROR_INVALID_ID, &inst) << "Target of NonWritable decoration is invalid: must point to a " diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index c9ecf51a1e..2d6715f423 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -1427,6 +1427,126 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, return SPV_SUCCESS; } +spv_result_t ValidateRawAccessChain(ValidationState_t& _, + const Instruction* inst) { + std::string instr_name = "Op" + std::string(spvOpcodeString(inst->opcode())); + + // The result type must be OpTypePointer. + const auto result_type = _.FindDef(inst->type_id()); + if (spv::Op::OpTypePointer != result_type->opcode()) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "The Result Type of " << instr_name << " " + << _.getIdName(inst->id()) << " must be OpTypePointer. Found Op" + << spvOpcodeString(result_type->opcode()) << '.'; + } + + // The pointed storage class must be valid. + const auto storage_class = result_type->GetOperandAs(1); + if (storage_class != spv::StorageClass::StorageBuffer && + storage_class != spv::StorageClass::PhysicalStorageBuffer && + storage_class != spv::StorageClass::Uniform) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "The Result Type of " << instr_name << " " + << _.getIdName(inst->id()) + << " must point to a storage class of " + "StorageBuffer, PhysicalStorageBuffer, or Uniform."; + } + + // The pointed type must not be one in the list below. + const auto result_type_pointee = + _.FindDef(result_type->GetOperandAs(2)); + if (result_type_pointee->opcode() == spv::Op::OpTypeArray || + result_type_pointee->opcode() == spv::Op::OpTypeMatrix || + result_type_pointee->opcode() == spv::Op::OpTypeStruct) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "The Result Type of " << instr_name << " " + << _.getIdName(inst->id()) + << " must not point to " + "OpTypeArray, OpTypeMatrix, or OpTypeStruct."; + } + + // Validate Stride is a OpConstant. + const auto stride = _.FindDef(inst->GetOperandAs(3)); + if (stride->opcode() != spv::Op::OpConstant) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "The Stride of " << instr_name << " " + << _.getIdName(inst->id()) << " must be OpConstant. Found Op" + << spvOpcodeString(stride->opcode()) << '.'; + } + // Stride type must be OpTypeInt + const auto stride_type = _.FindDef(stride->type_id()); + if (stride_type->opcode() != spv::Op::OpTypeInt) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "The type of Stride of " << instr_name << " " + << _.getIdName(inst->id()) << " must be OpTypeInt. Found Op" + << spvOpcodeString(stride_type->opcode()) << '.'; + } + + // Index and Offset type must be OpTypeInt with a width of 32 + const auto ValidateType = [&](const char* name, + int operandIndex) -> spv_result_t { + const auto value = _.FindDef(inst->GetOperandAs(operandIndex)); + const auto value_type = _.FindDef(value->type_id()); + if (value_type->opcode() != spv::Op::OpTypeInt) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "The type of " << name << " of " << instr_name << " " + << _.getIdName(inst->id()) << " must be OpTypeInt. Found Op" + << spvOpcodeString(value_type->opcode()) << '.'; + } + const auto width = value_type->GetOperandAs(1); + if (width != 32) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "The integer width of " << name << " of " << instr_name + << " " << _.getIdName(inst->id()) << " must be 32. Found " + << width << '.'; + } + return SPV_SUCCESS; + }; + spv_result_t result; + result = ValidateType("Index", 4); + if (result != SPV_SUCCESS) { + return result; + } + result = ValidateType("Offset", 5); + if (result != SPV_SUCCESS) { + return result; + } + + uint32_t access_operands = 0; + if (inst->operands().size() >= 7) { + access_operands = inst->GetOperandAs(6); + } + if (access_operands & + uint32_t(spv::RawAccessChainOperandsMask::RobustnessPerElementNV)) { + uint64_t stride_value = 0; + if (_.EvalConstantValUint64(stride->id(), &stride_value) && + stride_value == 0) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Stride must not be zero when per-element robustness is used."; + } + } + if (access_operands & + uint32_t(spv::RawAccessChainOperandsMask::RobustnessPerComponentNV) || + access_operands & + uint32_t(spv::RawAccessChainOperandsMask::RobustnessPerElementNV)) { + if (storage_class == spv::StorageClass::PhysicalStorageBuffer) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Storage class cannot be PhysicalStorageBuffer when " + "raw access chain robustness is used."; + } + } + if (access_operands & + uint32_t(spv::RawAccessChainOperandsMask::RobustnessPerComponentNV) && + access_operands & + uint32_t(spv::RawAccessChainOperandsMask::RobustnessPerElementNV)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Per-component robustness and per-element robustness are " + "mutually exclusive."; + } + + return SPV_SUCCESS; +} + spv_result_t ValidatePtrAccessChain(ValidationState_t& _, const Instruction* inst) { if (_.addressing_model() == spv::AddressingModel::Logical) { @@ -1866,6 +1986,9 @@ spv_result_t MemoryPass(ValidationState_t& _, const Instruction* inst) { case spv::Op::OpInBoundsPtrAccessChain: if (auto error = ValidateAccessChain(_, inst)) return error; break; + case spv::Op::OpRawAccessChainNV: + if (auto error = ValidateRawAccessChain(_, inst)) return error; + break; case spv::Op::OpArrayLength: if (auto error = ValidateArrayLength(_, inst)) return error; break; diff --git a/test/val/CMakeLists.txt b/test/val/CMakeLists.txt index 62d93bddc1..9d6f6ea6a9 100644 --- a/test/val/CMakeLists.txt +++ b/test/val/CMakeLists.txt @@ -46,6 +46,7 @@ add_spvtools_unittest(TARGET val_abcde val_extension_spv_khr_bit_instructions_test.cpp val_extension_spv_khr_terminate_invocation_test.cpp val_extension_spv_khr_subgroup_rotate_test.cpp + val_extension_spv_nv_raw_access_chains.cpp val_ext_inst_test.cpp val_ext_inst_debug_test.cpp ${VAL_TEST_COMMON_SRCS} diff --git a/test/val/val_extension_spv_nv_raw_access_chains.cpp b/test/val/val_extension_spv_nv_raw_access_chains.cpp new file mode 100644 index 0000000000..f06d7cd4b5 --- /dev/null +++ b/test/val/val_extension_spv_nv_raw_access_chains.cpp @@ -0,0 +1,510 @@ +// Copyright (c) 2024 The Khronos Group 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 + +#include "gmock/gmock.h" +#include "source/spirv_target_env.h" +#include "test/unit_spirv.h" +#include "test/val/val_fixtures.h" + +namespace spvtools { +namespace val { +namespace { + +using ::testing::HasSubstr; + +using ValidateSpvNVRawAccessChains = spvtest::ValidateBase; + +TEST_F(ValidateSpvNVRawAccessChains, Valid) { + const std::string str = R"( + OpCapability Shader + OpCapability RawAccessChainsNV + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_NV_raw_access_chains" + OpMemoryModel Logical GLSL450 + + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + + OpDecorate %intStruct Block + OpMemberDecorate %intStruct 0 Offset 0 + OpDecorate %ssbo DescriptorSet 0 + OpDecorate %ssbo Binding 0 + + %int = OpTypeInt 32 1 + %void = OpTypeVoid + %mainFunctionType = OpTypeFunction %void + %intStruct = OpTypeStruct %int + %intStructPtr = OpTypePointer StorageBuffer %intStruct + %ssbo = OpVariable %intStructPtr StorageBuffer + %intPtr = OpTypePointer StorageBuffer %int + + %int_0 = OpConstant %int 0 + %int_16 = OpConstant %int 16 + + %main = OpFunction %void None %mainFunctionType + %label = OpLabel + %rawChain = OpRawAccessChainNV %intPtr %ssbo %int_16 %int_0 %int_0 RobustnessPerComponentNV + %unused = OpLoad %int %rawChain + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateSpvNVRawAccessChains, NoCapability) { + const std::string str = R"( + OpCapability Shader + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_NV_raw_access_chains" + OpMemoryModel Logical GLSL450 + + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + + OpDecorate %intStruct Block + OpMemberDecorate %intStruct 0 Offset 0 + OpDecorate %ssbo DescriptorSet 0 + OpDecorate %ssbo Binding 0 + + %int = OpTypeInt 32 1 + %void = OpTypeVoid + %mainFunctionType = OpTypeFunction %void + %intStruct = OpTypeStruct %int + %intStructPtr = OpTypePointer StorageBuffer %intStruct + %ssbo = OpVariable %intStructPtr StorageBuffer + %intPtr = OpTypePointer StorageBuffer %int + + %int_0 = OpConstant %int 0 + %int_16 = OpConstant %int 16 + + %main = OpFunction %void None %mainFunctionType + %label = OpLabel + %rawChain = OpRawAccessChainNV %intPtr %ssbo %int_16 %int_0 %int_0 RobustnessPerComponentNV + %unused = OpLoad %int %rawChain + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_CAPABILITY, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("requires one of these capabilities: RawAccessChainsNV")); +} + +TEST_F(ValidateSpvNVRawAccessChains, NoExtension) { + const std::string str = R"( + OpCapability Shader + OpCapability RawAccessChainsNV + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpMemoryModel Logical GLSL450 + + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + + OpDecorate %intStruct Block + OpMemberDecorate %intStruct 0 Offset 0 + OpDecorate %ssbo DescriptorSet 0 + OpDecorate %ssbo Binding 0 + + %int = OpTypeInt 32 1 + %void = OpTypeVoid + %mainFunctionType = OpTypeFunction %void + %intStruct = OpTypeStruct %int + %intStructPtr = OpTypePointer StorageBuffer %intStruct + %ssbo = OpVariable %intStructPtr StorageBuffer + %intPtr = OpTypePointer StorageBuffer %int + + %int_0 = OpConstant %int 0 + %int_16 = OpConstant %int 16 + + %main = OpFunction %void None %mainFunctionType + %label = OpLabel + %rawChain = OpRawAccessChainNV %intPtr %ssbo %int_16 %int_0 %int_0 RobustnessPerComponentNV + %unused = OpLoad %int %rawChain + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + EXPECT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("requires one of these extensions: SPV_NV_raw_access_chains")); +} + +TEST_F(ValidateSpvNVRawAccessChains, ReturnTypeNotPointer) { + const std::string str = R"( + OpCapability Shader + OpCapability RawAccessChainsNV + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_NV_raw_access_chains" + OpMemoryModel Logical GLSL450 + + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + + OpDecorate %intStruct Block + OpMemberDecorate %intStruct 0 Offset 0 + OpDecorate %ssbo DescriptorSet 0 + OpDecorate %ssbo Binding 0 + + %int = OpTypeInt 32 1 + %void = OpTypeVoid + %mainFunctionType = OpTypeFunction %void + %intStruct = OpTypeStruct %int + %intStructPtr = OpTypePointer StorageBuffer %intStruct + %ssbo = OpVariable %intStructPtr StorageBuffer + + %int_0 = OpConstant %int 0 + %int_16 = OpConstant %int 16 + + %main = OpFunction %void None %mainFunctionType + %label = OpLabel + %rawChain = OpRawAccessChainNV %int %ssbo %int_16 %int_0 %int_0 RobustnessPerComponentNV + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must be OpTypePointer. Found OpTypeInt")); +} + +TEST_F(ValidateSpvNVRawAccessChains, Workgroup) { + const std::string str = R"( + OpCapability Shader + OpCapability RawAccessChainsNV + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_NV_raw_access_chains" + OpMemoryModel Logical GLSL450 + + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + + OpDecorate %intStruct Block + OpMemberDecorate %intStruct 0 Offset 0 + + %int = OpTypeInt 32 1 + %void = OpTypeVoid + %mainFunctionType = OpTypeFunction %void + %intStruct = OpTypeStruct %int + %intStructPtr = OpTypePointer Workgroup %intStruct + %ssbo = OpVariable %intStructPtr Workgroup + %intPtr = OpTypePointer Workgroup %int + + %int_0 = OpConstant %int 0 + %int_16 = OpConstant %int 16 + + %main = OpFunction %void None %mainFunctionType + %label = OpLabel + %rawChain = OpRawAccessChainNV %intPtr %ssbo %int_16 %int_0 %int_0 RobustnessPerComponentNV + %unused = OpLoad %int %rawChain + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must point to a storage class of")); +} + +TEST_F(ValidateSpvNVRawAccessChains, ReturnTypeArray) { + const std::string str = R"( + OpCapability Shader + OpCapability RawAccessChainsNV + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_NV_raw_access_chains" + OpMemoryModel Logical GLSL450 + + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + + OpDecorate %intStruct Block + OpMemberDecorate %intStruct 0 Offset 0 + OpDecorate %ssbo DescriptorSet 0 + OpDecorate %ssbo Binding 0 + + %int = OpTypeInt 32 1 + %void = OpTypeVoid + %mainFunctionType = OpTypeFunction %void + %intStruct = OpTypeStruct %int + %intStructPtr = OpTypePointer StorageBuffer %intStruct + %ssbo = OpVariable %intStructPtr StorageBuffer + %int_1 = OpConstant %int 1 + %intArray = OpTypeArray %int %int_1 + %intArrayPtr = OpTypePointer StorageBuffer %intArray + + %int_0 = OpConstant %int 0 + %int_16 = OpConstant %int 16 + + %main = OpFunction %void None %mainFunctionType + %label = OpLabel + %rawChain = OpRawAccessChainNV %intArrayPtr %ssbo %int_16 %int_0 %int_0 RobustnessPerComponentNV + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must not point to")); +} + +TEST_F(ValidateSpvNVRawAccessChains, VariableStride) { + const std::string str = R"( + OpCapability Shader + OpCapability RawAccessChainsNV + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_NV_raw_access_chains" + OpMemoryModel Logical GLSL450 + + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + + OpDecorate %intStruct Block + OpMemberDecorate %intStruct 0 Offset 0 + OpDecorate %ssbo DescriptorSet 0 + OpDecorate %ssbo Binding 0 + + %int = OpTypeInt 32 1 + %void = OpTypeVoid + %mainFunctionType = OpTypeFunction %void + %intStruct = OpTypeStruct %int + %intStructPtr = OpTypePointer StorageBuffer %intStruct + %ssbo = OpVariable %intStructPtr StorageBuffer + %intPtr = OpTypePointer StorageBuffer %int + + %int_0 = OpConstant %int 0 + + %main = OpFunction %void None %mainFunctionType + %label = OpLabel + %stride = OpIAdd %int %int_0 %int_0 + %rawChain = OpRawAccessChainNV %intPtr %ssbo %stride %int_0 %int_0 RobustnessPerComponentNV + %unused = OpLoad %int %rawChain + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be OpConstant")); +} + +TEST_F(ValidateSpvNVRawAccessChains, RobustnessPerElementZeroStride) { + const std::string str = R"( + OpCapability Shader + OpCapability RawAccessChainsNV + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_NV_raw_access_chains" + OpMemoryModel Logical GLSL450 + + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + + OpDecorate %intStruct Block + OpMemberDecorate %intStruct 0 Offset 0 + OpDecorate %ssbo DescriptorSet 0 + OpDecorate %ssbo Binding 0 + + %int = OpTypeInt 32 1 + %void = OpTypeVoid + %mainFunctionType = OpTypeFunction %void + %intStruct = OpTypeStruct %int + %intStructPtr = OpTypePointer StorageBuffer %intStruct + %ssbo = OpVariable %intStructPtr StorageBuffer + %intPtr = OpTypePointer StorageBuffer %int + + %int_0 = OpConstant %int 0 + + %main = OpFunction %void None %mainFunctionType + %label = OpLabel + %rawChain = OpRawAccessChainNV %intPtr %ssbo %int_0 %int_0 %int_0 RobustnessPerElementNV + %unused = OpLoad %int %rawChain + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Stride must not be zero when per-element robustness is used")); +} + +TEST_F(ValidateSpvNVRawAccessChains, BothRobustness) { + const std::string str = R"( + OpCapability Shader + OpCapability RawAccessChainsNV + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_NV_raw_access_chains" + OpMemoryModel Logical GLSL450 + + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + + OpDecorate %intStruct Block + OpMemberDecorate %intStruct 0 Offset 0 + OpDecorate %ssbo DescriptorSet 0 + OpDecorate %ssbo Binding 0 + + %int = OpTypeInt 32 1 + %void = OpTypeVoid + %mainFunctionType = OpTypeFunction %void + %intStruct = OpTypeStruct %int + %intStructPtr = OpTypePointer StorageBuffer %intStruct + %ssbo = OpVariable %intStructPtr StorageBuffer + %intPtr = OpTypePointer StorageBuffer %int + + %int_0 = OpConstant %int 0 + %int_16 = OpConstant %int 16 + + %main = OpFunction %void None %mainFunctionType + %label = OpLabel + %rawChain = OpRawAccessChainNV %intPtr %ssbo %int_16 %int_0 %int_0 RobustnessPerElementNV|RobustnessPerComponentNV + %unused = OpLoad %int %rawChain + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Per-component robustness and per-element robustness " + "are mutually exclusive")); +} + +TEST_F(ValidateSpvNVRawAccessChains, StrideFloat) { + const std::string str = R"( + OpCapability Shader + OpCapability RawAccessChainsNV + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_NV_raw_access_chains" + OpMemoryModel Logical GLSL450 + + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + + OpDecorate %intStruct Block + OpMemberDecorate %intStruct 0 Offset 0 + OpDecorate %ssbo DescriptorSet 0 + OpDecorate %ssbo Binding 0 + + %int = OpTypeInt 32 1 + %float = OpTypeFloat 32 + %void = OpTypeVoid + %mainFunctionType = OpTypeFunction %void + %intStruct = OpTypeStruct %int + %intStructPtr = OpTypePointer StorageBuffer %intStruct + %ssbo = OpVariable %intStructPtr StorageBuffer + %intPtr = OpTypePointer StorageBuffer %int + + %int_0 = OpConstant %int 0 + %float_16 = OpConstant %float 16 + + %main = OpFunction %void None %mainFunctionType + %label = OpLabel + %rawChain = OpRawAccessChainNV %intPtr %ssbo %float_16 %int_0 %int_0 RobustnessPerComponentNV + %unused = OpLoad %int %rawChain + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("must be OpTypeInt")); +} + +TEST_F(ValidateSpvNVRawAccessChains, IndexType) { + const std::string str = R"( + OpCapability Shader + OpCapability RawAccessChainsNV + OpCapability Int64 + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_NV_raw_access_chains" + OpMemoryModel Logical GLSL450 + + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + + OpDecorate %intStruct Block + OpMemberDecorate %intStruct 0 Offset 0 + OpDecorate %ssbo DescriptorSet 0 + OpDecorate %ssbo Binding 0 + + %int = OpTypeInt 32 1 + %long = OpTypeInt 64 1 + %void = OpTypeVoid + %mainFunctionType = OpTypeFunction %void + %intStruct = OpTypeStruct %int + %intStructPtr = OpTypePointer StorageBuffer %intStruct + %ssbo = OpVariable %intStructPtr StorageBuffer + %intPtr = OpTypePointer StorageBuffer %int + + %int_0 = OpConstant %int 0 + %int_16 = OpConstant %int 16 + %long_0 = OpConstant %long 0 + + %main = OpFunction %void None %mainFunctionType + %label = OpLabel + %rawChain = OpRawAccessChainNV %intPtr %ssbo %int_16 %long_0 %int_0 RobustnessPerComponentNV + %unused = OpLoad %int %rawChain + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("The integer width of Index")); +} + +TEST_F(ValidateSpvNVRawAccessChains, OffsetType) { + const std::string str = R"( + OpCapability Shader + OpCapability RawAccessChainsNV + OpCapability Int64 + OpExtension "SPV_KHR_storage_buffer_storage_class" + OpExtension "SPV_NV_raw_access_chains" + OpMemoryModel Logical GLSL450 + + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + + OpDecorate %intStruct Block + OpMemberDecorate %intStruct 0 Offset 0 + OpDecorate %ssbo DescriptorSet 0 + OpDecorate %ssbo Binding 0 + + %int = OpTypeInt 32 1 + %long = OpTypeInt 64 1 + %void = OpTypeVoid + %mainFunctionType = OpTypeFunction %void + %intStruct = OpTypeStruct %int + %intStructPtr = OpTypePointer StorageBuffer %intStruct + %ssbo = OpVariable %intStructPtr StorageBuffer + %intPtr = OpTypePointer StorageBuffer %int + + %int_0 = OpConstant %int 0 + %int_16 = OpConstant %int 16 + %long_0 = OpConstant %long 0 + + %main = OpFunction %void None %mainFunctionType + %label = OpLabel + %rawChain = OpRawAccessChainNV %intPtr %ssbo %int_16 %int_0 %long_0 RobustnessPerComponentNV + %unused = OpLoad %int %rawChain + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), HasSubstr("The integer width of Offset")); +} + +} // namespace +} // namespace val +} // namespace spvtools From 02470f606fe1571de808cb773d8c521ab201aaff Mon Sep 17 00:00:00 2001 From: alan-baker Date: Fri, 12 Apr 2024 08:51:41 -0400 Subject: [PATCH 423/523] Validate duplicate decorations and execution modes (#5641) * Disallow duplicate decorations generally * Only FuncParamAttr and UserSemantic can be applied to the same target multiple times * Unchecked: completely duplicate UserSemantic and FuncParamAttr * Disallow duplicate execution modes generally * Exceptions for float controls, float controls2 and some intel execution modes * Fix invalid fuzzer transforms --- ...ormation_add_no_contraction_decoration.cpp | 5 + .../transformation_add_relaxed_decoration.cpp | 6 + source/val/validate.cpp | 3 + source/val/validate.h | 7 + source/val/validate_decorations.cpp | 13 +- source/val/validate_interfaces.cpp | 15 +- source/val/validate_mode_setting.cpp | 66 ++++++++ ...ion_add_no_contraction_decoration_test.cpp | 8 +- ...sformation_add_relaxed_decoration_test.cpp | 6 +- test/val/val_interfaces_test.cpp | 25 +-- test/val/val_modes_test.cpp | 156 ++++++++++++++++++ 11 files changed, 265 insertions(+), 45 deletions(-) diff --git a/source/fuzz/transformation_add_no_contraction_decoration.cpp b/source/fuzz/transformation_add_no_contraction_decoration.cpp index 07a31e5cb5..87393e95b0 100644 --- a/source/fuzz/transformation_add_no_contraction_decoration.cpp +++ b/source/fuzz/transformation_add_no_contraction_decoration.cpp @@ -36,6 +36,11 @@ bool TransformationAddNoContractionDecoration::IsApplicable( if (!instr) { return false; } + // |instr| must not be decorated with NoContraction. + if (ir_context->get_decoration_mgr()->HasDecoration( + message_.result_id(), spv::Decoration::NoContraction)) { + return false; + } // The instruction must be arithmetic. return IsArithmetic(instr->opcode()); } diff --git a/source/fuzz/transformation_add_relaxed_decoration.cpp b/source/fuzz/transformation_add_relaxed_decoration.cpp index 6cd4ecbb3f..601546c978 100644 --- a/source/fuzz/transformation_add_relaxed_decoration.cpp +++ b/source/fuzz/transformation_add_relaxed_decoration.cpp @@ -36,6 +36,11 @@ bool TransformationAddRelaxedDecoration::IsApplicable( if (!instr) { return false; } + // |instr| must not be decorated with RelaxedPrecision. + if (ir_context->get_decoration_mgr()->HasDecoration( + message_.result_id(), spv::Decoration::RelaxedPrecision)) { + return false; + } opt::BasicBlock* cur_block = ir_context->get_instr_block(instr); // The instruction must have a block. if (cur_block == nullptr) { @@ -46,6 +51,7 @@ bool TransformationAddRelaxedDecoration::IsApplicable( cur_block->id()))) { return false; } + // The instruction must be numeric. return IsNumeric(instr->opcode()); } diff --git a/source/val/validate.cpp b/source/val/validate.cpp index ccf26fbf1d..32368075c5 100644 --- a/source/val/validate.cpp +++ b/source/val/validate.cpp @@ -144,6 +144,9 @@ spv_result_t ValidateEntryPoints(ValidationState_t& _) { if (auto error = ValidateFloatControls2(_)) { return error; } + if (auto error = ValidateDuplicateExecutionModes(_)) { + return error; + } return SPV_SUCCESS; } diff --git a/source/val/validate.h b/source/val/validate.h index 52267c8ab6..78093ce5fd 100644 --- a/source/val/validate.h +++ b/source/val/validate.h @@ -94,6 +94,13 @@ spv_result_t ValidateInterfaces(ValidationState_t& _); /// @return SPV_SUCCESS if no errors are found. spv_result_t ValidateFloatControls2(ValidationState_t& _); +/// @brief Validates duplicated execution modes for each entry point. +/// +/// @param[in] _ the validation state of the module +/// +/// @return SPV_SUCCESS if no errors are found. +spv_result_t ValidateDuplicateExecutionModes(ValidationState_t& _); + /// @brief Validates memory instructions /// /// @param[in] _ the validation state of the module diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp index bb1fea5502..0a7df65811 100644 --- a/source/val/validate_decorations.cpp +++ b/source/val/validate_decorations.cpp @@ -1325,21 +1325,14 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { // Returns true if |decoration| cannot be applied to the same id more than once. bool AtMostOncePerId(spv::Decoration decoration) { - return decoration == spv::Decoration::ArrayStride; + return decoration != spv::Decoration::UserSemantic && + decoration != spv::Decoration::FuncParamAttr; } // Returns true if |decoration| cannot be applied to the same member more than // once. bool AtMostOncePerMember(spv::Decoration decoration) { - switch (decoration) { - case spv::Decoration::Offset: - case spv::Decoration::MatrixStride: - case spv::Decoration::RowMajor: - case spv::Decoration::ColMajor: - return true; - default: - return false; - } + return decoration != spv::Decoration::UserSemantic; } spv_result_t CheckDecorationsCompatibility(ValidationState_t& vstate) { diff --git a/source/val/validate_interfaces.cpp b/source/val/validate_interfaces.cpp index 54ebfd7885..ace548aa1a 100644 --- a/source/val/validate_interfaces.cpp +++ b/source/val/validate_interfaces.cpp @@ -254,37 +254,24 @@ spv_result_t GetLocationsForVariable( // equal. Also track Patch and PerTaskNV decorations. bool has_location = false; uint32_t location = 0; - bool has_component = false; uint32_t component = 0; bool has_index = false; uint32_t index = 0; bool has_patch = false; bool has_per_task_nv = false; bool has_per_vertex_khr = false; + // Duplicate Location, Component, Index are checked elsewhere. for (auto& dec : _.id_decorations(variable->id())) { if (dec.dec_type() == spv::Decoration::Location) { - if (has_location && dec.params()[0] != location) { - return _.diag(SPV_ERROR_INVALID_DATA, variable) - << "Variable has conflicting location decorations"; - } has_location = true; location = dec.params()[0]; } else if (dec.dec_type() == spv::Decoration::Component) { - if (has_component && dec.params()[0] != component) { - return _.diag(SPV_ERROR_INVALID_DATA, variable) - << "Variable has conflicting component decorations"; - } - has_component = true; component = dec.params()[0]; } else if (dec.dec_type() == spv::Decoration::Index) { if (!is_output || !is_fragment) { return _.diag(SPV_ERROR_INVALID_DATA, variable) << "Index can only be applied to Fragment output variables"; } - if (has_index && dec.params()[0] != index) { - return _.diag(SPV_ERROR_INVALID_DATA, variable) - << "Variable has conflicting index decorations"; - } has_index = true; index = dec.params()[0]; } else if (dec.dec_type() == spv::Decoration::BuiltIn) { diff --git a/source/val/validate_mode_setting.cpp b/source/val/validate_mode_setting.cpp index 199d8ed455..8502fda534 100644 --- a/source/val/validate_mode_setting.cpp +++ b/source/val/validate_mode_setting.cpp @@ -724,6 +724,25 @@ spv_result_t ValidateMemoryModel(ValidationState_t& _, return SPV_SUCCESS; } +bool PerEntryExecutionMode(spv::ExecutionMode mode) { + switch (mode) { + // These execution modes can be specified multiple times per entry point. + case spv::ExecutionMode::DenormPreserve: + case spv::ExecutionMode::DenormFlushToZero: + case spv::ExecutionMode::SignedZeroInfNanPreserve: + case spv::ExecutionMode::RoundingModeRTE: + case spv::ExecutionMode::RoundingModeRTZ: + case spv::ExecutionMode::FPFastMathDefault: + case spv::ExecutionMode::RoundingModeRTPINTEL: + case spv::ExecutionMode::RoundingModeRTNINTEL: + case spv::ExecutionMode::FloatingPointModeALTINTEL: + case spv::ExecutionMode::FloatingPointModeIEEEINTEL: + return false; + default: + return true; + } +} + } // namespace spv_result_t ValidateFloatControls2(ValidationState_t& _) { @@ -808,5 +827,52 @@ spv_result_t ModeSettingPass(ValidationState_t& _, const Instruction* inst) { return SPV_SUCCESS; } +spv_result_t ValidateDuplicateExecutionModes(ValidationState_t& _) { + using PerEntryKey = std::tuple; + using PerOperandKey = std::tuple; + std::set seen_per_entry; + std::set seen_per_operand; + + const auto lookupMode = [&_](spv::ExecutionMode mode) -> std::string { + spv_operand_desc desc = nullptr; + if (_.grammar().lookupOperand(SPV_OPERAND_TYPE_EXECUTION_MODE, + static_cast(mode), + &desc) == SPV_SUCCESS) { + return std::string(desc->name); + } + return "Unknown"; + }; + + for (const auto& inst : _.ordered_instructions()) { + if (inst.opcode() != spv::Op::OpExecutionMode && + inst.opcode() != spv::Op::OpExecutionModeId) { + continue; + } + + const auto entry = inst.GetOperandAs(0); + const auto mode = inst.GetOperandAs(1); + if (PerEntryExecutionMode(mode)) { + if (!seen_per_entry.insert(std::make_tuple(mode, entry)).second) { + return _.diag(SPV_ERROR_INVALID_ID, &inst) + << lookupMode(mode) + << " execution mode must not be specified multiple times per " + "entry point"; + } + } else { + // Execution modes allowed multiple times all take a single operand. + const auto operand = inst.GetOperandAs(2); + if (!seen_per_operand.insert(std::make_tuple(mode, entry, operand)) + .second) { + return _.diag(SPV_ERROR_INVALID_ID, &inst) + << lookupMode(mode) + << " execution mode must not be specified multiple times for " + "the same entry point and operands"; + } + } + } + + return SPV_SUCCESS; +} + } // namespace val } // namespace spvtools diff --git a/test/fuzz/transformation_add_no_contraction_decoration_test.cpp b/test/fuzz/transformation_add_no_contraction_decoration_test.cpp index 4fc9d2d56f..1280b815e0 100644 --- a/test/fuzz/transformation_add_no_contraction_decoration_test.cpp +++ b/test/fuzz/transformation_add_no_contraction_decoration_test.cpp @@ -36,7 +36,6 @@ TEST(TransformationAddNoContractionDecorationTest, BasicScenarios) { OpName %8 "x" OpName %10 "y" OpName %14 "i" - OpDecorate %32 NoContraction %2 = OpTypeVoid %3 = OpTypeFunction %2 %6 = OpTypeFloat 32 @@ -110,9 +109,8 @@ TEST(TransformationAddNoContractionDecorationTest, BasicScenarios) { ASSERT_FALSE(TransformationAddNoContractionDecoration(24).IsApplicable( context.get(), transformation_context)); - // It is valid to add NoContraction to each of these ids (and it's fine to - // have duplicates of the decoration, in the case of 32). - for (uint32_t result_id : {32u, 32u, 27u, 29u, 39u}) { + // It is valid to add NoContraction to each of these ids. + for (uint32_t result_id : {32u, 27u, 29u, 39u}) { TransformationAddNoContractionDecoration transformation(result_id); ASSERT_TRUE( transformation.IsApplicable(context.get(), transformation_context)); @@ -134,8 +132,6 @@ TEST(TransformationAddNoContractionDecorationTest, BasicScenarios) { OpName %10 "y" OpName %14 "i" OpDecorate %32 NoContraction - OpDecorate %32 NoContraction - OpDecorate %32 NoContraction OpDecorate %27 NoContraction OpDecorate %29 NoContraction OpDecorate %39 NoContraction diff --git a/test/fuzz/transformation_add_relaxed_decoration_test.cpp b/test/fuzz/transformation_add_relaxed_decoration_test.cpp index c4408827f5..979eeb7227 100644 --- a/test/fuzz/transformation_add_relaxed_decoration_test.cpp +++ b/test/fuzz/transformation_add_relaxed_decoration_test.cpp @@ -86,9 +86,8 @@ TEST(TransformationAddRelaxedDecorationTest, BasicScenarios) { // Invalid: 28 is in a dead block, but returns bool (not numeric). ASSERT_FALSE(TransformationAddRelaxedDecoration(28).IsApplicable( context.get(), transformation_context)); - // It is valid to add RelaxedPrecision to 25 (and it's fine to - // have a duplicate). - for (uint32_t result_id : {25u, 25u}) { + // It is valid to add RelaxedPrecision to 25 + for (uint32_t result_id : {25u}) { TransformationAddRelaxedDecoration transformation(result_id); ASSERT_TRUE( transformation.IsApplicable(context.get(), transformation_context)); @@ -110,7 +109,6 @@ TEST(TransformationAddRelaxedDecorationTest, BasicScenarios) { OpName %10 "b" OpName %14 "c" OpDecorate %25 RelaxedPrecision - OpDecorate %25 RelaxedPrecision %2 = OpTypeVoid %3 = OpTypeFunction %2 %6 = OpTypeInt 32 1 diff --git a/test/val/val_interfaces_test.cpp b/test/val/val_interfaces_test.cpp index d75c20cf29..4f62be799d 100644 --- a/test/val/val_interfaces_test.cpp +++ b/test/val/val_interfaces_test.cpp @@ -419,9 +419,10 @@ OpFunctionEnd )"; CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Variable has conflicting location decorations")); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("decorated with Location multiple times is not allowed")); } TEST_F(ValidateInterfacesTest, VulkanLocationsVariableAndMemberAssigned) { @@ -505,9 +506,10 @@ OpFunctionEnd )"; CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Member index 1 has conflicting location assignments")); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("decorated with Location multiple times is not allowed")); } TEST_F(ValidateInterfacesTest, VulkanLocationsMissingAssignmentStructMember) { @@ -1157,9 +1159,10 @@ OpFunctionEnd )"; CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("Variable has conflicting component decorations")); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("decorated with Component multiple times is not allowed")); } TEST_F(ValidateInterfacesTest, @@ -1186,10 +1189,10 @@ OpFunctionEnd )"; CompileSuccessfully(text, SPV_ENV_VULKAN_1_0); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT( getDiagnosticString(), - HasSubstr("Member index 0 has conflicting component assignments")); + HasSubstr("decorated with Component multiple times is not allowed")); } TEST_F(ValidateInterfacesTest, VulkanLocationsVariableConflictOutputIndex1) { diff --git a/test/val/val_modes_test.cpp b/test/val/val_modes_test.cpp index a0ea4288dc..83a050377c 100644 --- a/test/val/val_modes_test.cpp +++ b/test/val/val_modes_test.cpp @@ -1027,6 +1027,162 @@ OpExecutionModeId %main LocalSizeId %int_1 %int_1 %int_1 "constant instructions.")); } +using AllowMultipleExecutionModes = spvtest::ValidateBase; + +TEST_P(AllowMultipleExecutionModes, DifferentOperand) { + const std::string mode = GetParam(); + const std::string spirv = R"( +OpCapability Shader +OpCapability DenormPreserve +OpCapability DenormFlushToZero +OpCapability SignedZeroInfNanPreserve +OpCapability RoundingModeRTE +OpCapability RoundingModeRTZ +OpExtension "SPV_KHR_float_controls" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main )" + mode + + R"( 16 +OpExecutionMode %main )" + mode + + R"( 32 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(AllowMultipleExecutionModes, SameOperand) { + const std::string mode = GetParam(); + const std::string spirv = R"( +OpCapability Shader +OpCapability DenormPreserve +OpCapability DenormFlushToZero +OpCapability SignedZeroInfNanPreserve +OpCapability RoundingModeRTE +OpCapability RoundingModeRTZ +OpExtension "SPV_KHR_float_controls" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionMode %main )" + mode + + R"( 32 +OpExecutionMode %main )" + mode + + R"( 32 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("execution mode must not be specified multiple times " + "for the same entry point and operands")); +} + +INSTANTIATE_TEST_SUITE_P(MultipleFloatControlsExecModes, + AllowMultipleExecutionModes, + Values("DenormPreserve", "DenormFlushToZero", + "SignedZeroInfNanPreserve", "RoundingModeRTE", + "RoundingModeRTZ")); + +using MultipleExecModes = spvtest::ValidateBase; + +TEST_P(MultipleExecModes, DuplicateMode) { + const std::string mode = GetParam(); + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpExecutionMode %main )" + mode + + R"( +OpExecutionMode %main )" + mode + + R"( +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("execution mode must not be specified multiple times " + "per entry point")); +} + +INSTANTIATE_TEST_SUITE_P(MultipleFragmentExecMode, MultipleExecModes, + Values("DepthReplacing", "DepthGreater", "DepthLess", + "DepthUnchanged")); + +TEST_F(ValidateMode, FloatControls2FPFastMathDefaultSameOperand) { + const std::string spirv = R"( +OpCapability Shader +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionModeId %main FPFastMathDefault %float %none +OpExecutionModeId %main FPFastMathDefault %float %none +%void = OpTypeVoid +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%none = OpConstant %int 0 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("execution mode must not be specified multiple times " + "for the same entry point and operands")); +} + +TEST_F(ValidateMode, FloatControls2FPFastMathDefaultDifferentOperand) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Float16 +OpCapability FloatControls2 +OpExtension "SPV_KHR_float_controls2" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpExecutionModeId %main FPFastMathDefault %float %none +OpExecutionModeId %main FPFastMathDefault %half %none +%void = OpTypeVoid +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%none = OpConstant %int 0 +%half = OpTypeFloat 16 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_2); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_2)); +} + TEST_F(ValidateMode, FragmentShaderInterlockVertexBad) { const std::string spirv = R"( OpCapability Shader From 2904985aee4de2fd67d697242a267f5ec31814ce Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Mon, 15 Apr 2024 23:56:12 +0900 Subject: [PATCH 424/523] spirv-val: Add Vulkan check for Rect Dim in OpTypeImage (#5644) --- source/val/validate_image.cpp | 10 +++++++++- source/val/validation_state.cpp | 2 ++ test/val/val_image_test.cpp | 15 +++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index f62c3a26c3..bfcb310db5 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -914,7 +914,15 @@ spv_result_t ValidateTypeImage(ValidationState_t& _, const Instruction* inst) { if (info.dim == spv::Dim::SubpassData && info.arrayed != 0) { return _.diag(SPV_ERROR_INVALID_DATA, inst) - << _.VkErrorID(6214) << "Dim SubpassData requires Arrayed to be 0"; + << _.VkErrorID(6214) + << "Dim SubpassData requires Arrayed to be 0 in the Vulkan " + "environment"; + } + + if (info.dim == spv::Dim::Rect) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(9638) + << "Dim must not be Rect in the Vulkan environment"; } } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 896849930e..87322d2b96 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -2351,6 +2351,8 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-08722); case 8973: return VUID_WRAP(VUID-StandaloneSpirv-Pointer-08973); + case 9638: + return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-09638); default: return ""; // unknown id } diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index 35b76fc5b5..44ccf2d641 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -786,6 +786,21 @@ TEST_F(ValidateImage, TypeImageWrongArrayForSubpassDataVulkan) { HasSubstr("Dim SubpassData requires Arrayed to be 0")); } +TEST_F(ValidateImage, TypeImageDimRectVulkan) { + const std::string code = GetShaderHeader("OpCapability InputAttachment\n") + + R"( +%img_type = OpTypeImage %f32 Rect 0 1 0 2 Unknown +)" + TrivialMain(); + + CompileSuccessfully(code.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, + ValidateInstructions(SPV_ENV_VULKAN_1_0)); + // Can't actually hit VUID-StandaloneSpirv-OpTypeImage-09638 + EXPECT_THAT( + getDiagnosticString(), + AnyVUID("TypeImage requires one of these capabilities: SampledRect")); +} + TEST_F(ValidateImage, TypeImageWrongSampledTypeForTileImageDataEXT) { const std::string code = GetShaderHeader( "OpCapability TileImageColorReadAccessEXT\n" From 67a3ed67057297e8dce0a96628cb1ba892bf64a0 Mon Sep 17 00:00:00 2001 From: Natalie Chouinard Date: Thu, 18 Apr 2024 16:04:58 -0400 Subject: [PATCH 425/523] opt: add GroupNonUniformPartitionedNV capability to trim pass (#5648) --- source/opt/trim_capabilities_pass.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index 3a8460f3b2..81c07b8227 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -98,7 +98,8 @@ class TrimCapabilitiesPass : public Pass { spv::Capability::StoragePushConstant16, spv::Capability::StorageUniform16, spv::Capability::StorageUniformBufferBlock16, - spv::Capability::VulkanMemoryModelDeviceScope + spv::Capability::VulkanMemoryModelDeviceScope, + spv::Capability::GroupNonUniformPartitionedNV // clang-format on }; From 53c07360640bd017cfaa58d21a3429e8d3fad6c3 Mon Sep 17 00:00:00 2001 From: Wooyoung Kim Date: Thu, 18 Apr 2024 14:30:20 -0700 Subject: [PATCH 426/523] A fix to support of SPV_QCOM_image_processing2 (#5646) Fixing validation of decorations attached to texture/sampler operands of OpImageBlockMatchWindowSSDQCOM and OpImageBlockMatchWindowSADQCOM --- source/val/validate_image.cpp | 65 +++++++++++++++++++++++++++++------ test/val/val_image_test.cpp | 16 ++++----- 2 files changed, 60 insertions(+), 21 deletions(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index bfcb310db5..a1a76ea274 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -2169,7 +2169,8 @@ 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) { + bool is_intf_obj = (ld_inst->opcode() == spv::Op::OpSampledImage); + if (is_intf_obj == true) { si_inst = ld_inst; int t_idx = si_inst->GetOperandAs(2); // texture ld_inst = _.FindDef(t_idx); @@ -2186,6 +2187,56 @@ spv_result_t ValidateImageProcessingQCOMDecoration(ValidationState_t& _, int id, return SPV_SUCCESS; } +spv_result_t ValidateImageProcessing2QCOMWindowDecoration(ValidationState_t& _, + int id) { + const Instruction* ld_inst = _.FindDef(id); + bool is_intf_obj = (ld_inst->opcode() != spv::Op::OpSampledImage); + if (is_intf_obj == true) { + 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 + spv::Decoration decor = spv::Decoration::BlockMatchTextureQCOM; + if (!_.HasDecoration(texture_id, decor)) { + return _.diag(SPV_ERROR_INVALID_DATA, ld_inst) + << "Missing decoration " << _.SpvDecorationString(decor); + } + decor = spv::Decoration::BlockMatchSamplerQCOM; + if (!_.HasDecoration(texture_id, decor)) { + return _.diag(SPV_ERROR_INVALID_DATA, ld_inst) + << "Missing decoration " << _.SpvDecorationString(decor); + } + } else { + const Instruction* si_inst = ld_inst; + int t_idx = si_inst->GetOperandAs(2); // texture + const Instruction* t_ld_inst = _.FindDef(t_idx); + if (t_ld_inst->opcode() != spv::Op::OpLoad) { + return _.diag(SPV_ERROR_INVALID_DATA, t_ld_inst) + << "Expect to see OpLoad"; + } + int texture_id = t_ld_inst->GetOperandAs(2); // variable to load + spv::Decoration decor = spv::Decoration::BlockMatchTextureQCOM; + if (!_.HasDecoration(texture_id, decor)) { + return _.diag(SPV_ERROR_INVALID_DATA, ld_inst) + << "Missing decoration " << _.SpvDecorationString(decor); + } + int s_idx = si_inst->GetOperandAs(3); // sampler + const Instruction* s_ld_inst = _.FindDef(s_idx); + if (s_ld_inst->opcode() != spv::Op::OpLoad) { + return _.diag(SPV_ERROR_INVALID_DATA, s_ld_inst) + << "Expect to see OpLoad"; + } + int sampler_id = s_ld_inst->GetOperandAs(2); // variable to load + decor = spv::Decoration::BlockMatchSamplerQCOM; + if (!_.HasDecoration(sampler_id, decor)) { + return _.diag(SPV_ERROR_INVALID_DATA, ld_inst) + << "Missing decoration " << _.SpvDecorationString(decor); + } + } + + return SPV_SUCCESS; +} + spv_result_t ValidateImageProcessingQCOM(ValidationState_t& _, const Instruction* inst) { spv_result_t res = SPV_SUCCESS; @@ -2211,18 +2262,10 @@ spv_result_t ValidateImageProcessingQCOM(ValidationState_t& _, case spv::Op::OpImageBlockMatchWindowSSDQCOM: case spv::Op::OpImageBlockMatchWindowSADQCOM: { int tgt_idx = inst->GetOperandAs(2); // target - res = ValidateImageProcessingQCOMDecoration( - _, tgt_idx, spv::Decoration::BlockMatchTextureQCOM); - if (res != SPV_SUCCESS) break; - res = ValidateImageProcessingQCOMDecoration( - _, tgt_idx, spv::Decoration::BlockMatchSamplerQCOM); + res = ValidateImageProcessing2QCOMWindowDecoration(_, tgt_idx); if (res != SPV_SUCCESS) break; int ref_idx = inst->GetOperandAs(4); // reference - res = ValidateImageProcessingQCOMDecoration( - _, ref_idx, spv::Decoration::BlockMatchTextureQCOM); - if (res != SPV_SUCCESS) break; - res = ValidateImageProcessingQCOMDecoration( - _, ref_idx, spv::Decoration::BlockMatchSamplerQCOM); + res = ValidateImageProcessing2QCOMWindowDecoration(_, ref_idx); break; } case spv::Op::OpImageBlockMatchGatherSSDQCOM: diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index 44ccf2d641..77b042f04c 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -8332,9 +8332,9 @@ TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADNoDecorRefNIT) { OpDecorate %4 DescriptorSet 0 OpDecorate %4 Binding 1 OpDecorate %4 BlockMatchTextureQCOM - OpDecorate %4 BlockMatchSamplerQCOM OpDecorate %5 DescriptorSet 0 OpDecorate %5 Binding 3 + OpDecorate %5 BlockMatchSamplerQCOM OpDecorate %6 DescriptorSet 0 OpDecorate %6 Binding 2 OpDecorate %6 BlockMatchSamplerQCOM @@ -8816,9 +8816,9 @@ TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDNoDecorRefNIT) { OpDecorate %4 DescriptorSet 0 OpDecorate %4 Binding 1 OpDecorate %4 BlockMatchTextureQCOM - OpDecorate %4 BlockMatchSamplerQCOM OpDecorate %5 DescriptorSet 0 OpDecorate %5 Binding 3 + OpDecorate %5 BlockMatchSamplerQCOM OpDecorate %6 DescriptorSet 0 OpDecorate %6 Binding 2 OpDecorate %6 BlockMatchSamplerQCOM @@ -9557,9 +9557,8 @@ TEST_F(ValidateImage, OpDecorate %104 DescriptorSet 0 OpDecorate %104 Binding 2 OpDecorate %102 BlockMatchTextureQCOM - OpDecorate %102 BlockMatchSamplerQCOM + OpDecorate %103 BlockMatchSamplerQCOM OpDecorate %104 BlockMatchTextureQCOM - OpDecorate %104 BlockMatchSamplerQCOM %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 @@ -9632,9 +9631,8 @@ TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSADInvalidUseRefNI) { OpDecorate %104 DescriptorSet 0 OpDecorate %104 Binding 2 OpDecorate %102 BlockMatchTextureQCOM - OpDecorate %102 BlockMatchSamplerQCOM + OpDecorate %103 BlockMatchSamplerQCOM OpDecorate %104 BlockMatchTextureQCOM - OpDecorate %104 BlockMatchSamplerQCOM %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 @@ -9847,9 +9845,8 @@ TEST_F(ValidateImage, OpDecorate %104 DescriptorSet 0 OpDecorate %104 Binding 2 OpDecorate %102 BlockMatchTextureQCOM - OpDecorate %102 BlockMatchSamplerQCOM + OpDecorate %103 BlockMatchSamplerQCOM OpDecorate %104 BlockMatchTextureQCOM - OpDecorate %104 BlockMatchSamplerQCOM %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 @@ -9922,9 +9919,8 @@ TEST_F(ValidateImage, QCOMImageProcessing2BlockMatchWindowSSDInvalidUseRefNI) { OpDecorate %104 DescriptorSet 0 OpDecorate %104 Binding 2 OpDecorate %102 BlockMatchTextureQCOM - OpDecorate %102 BlockMatchSamplerQCOM + OpDecorate %103 BlockMatchSamplerQCOM OpDecorate %104 BlockMatchTextureQCOM - OpDecorate %104 BlockMatchSamplerQCOM %void = OpTypeVoid %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 From dadb3012d51702cccae71967f9f2acaec8f393d5 Mon Sep 17 00:00:00 2001 From: Sven van Haastregt Date: Thu, 18 Apr 2024 23:31:34 +0200 Subject: [PATCH 427/523] Add SPIRV_TOOLS_EXPORT to public C++ API (#5591) In contrast to the C API, the C++ API did not have symbol visibility specified. An application using the C++ API would fail to link against a shared SPIRV-Tools library built with `-fvisibility=hidden`. Mark all classes in the public `.hpp` files with `SPIRV_TOOLS_EXPORT`. Add `SPIRV_TOOLS_LOCAL` to hide nested structs containing implementation details. Signed-off-by: Sven van Haastregt --- include/spirv-tools/libspirv.h | 4 ++++ include/spirv-tools/libspirv.hpp | 15 ++++++++------- include/spirv-tools/linker.hpp | 19 ++++++++++--------- include/spirv-tools/linter.hpp | 4 ++-- include/spirv-tools/optimizer.hpp | 6 +++--- 5 files changed, 27 insertions(+), 21 deletions(-) diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index 08cfd6579b..83b1a8e9b6 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -33,15 +33,19 @@ extern "C" { #else #define SPIRV_TOOLS_EXPORT __declspec(dllimport) #endif +#define SPIRV_TOOLS_LOCAL #else #if defined(SPIRV_TOOLS_IMPLEMENTATION) #define SPIRV_TOOLS_EXPORT __attribute__((visibility("default"))) +#define SPIRV_TOOLS_LOCAL __attribute__((visibility("hidden"))) #else #define SPIRV_TOOLS_EXPORT +#define SPIRV_TOOLS_LOCAL #endif #endif #else #define SPIRV_TOOLS_EXPORT +#define SPIRV_TOOLS_LOCAL #endif // Helpers diff --git a/include/spirv-tools/libspirv.hpp b/include/spirv-tools/libspirv.hpp index ee6c8469a0..59ff82b17c 100644 --- a/include/spirv-tools/libspirv.hpp +++ b/include/spirv-tools/libspirv.hpp @@ -37,7 +37,7 @@ using InstructionParser = std::function; // C++ RAII wrapper around the C context object spv_context. -class Context { +class SPIRV_TOOLS_EXPORT Context { public: // Constructs a context targeting the given environment |env|. // @@ -73,7 +73,7 @@ class Context { }; // A RAII wrapper around a validator options object. -class ValidatorOptions { +class SPIRV_TOOLS_EXPORT ValidatorOptions { public: ValidatorOptions() : options_(spvValidatorOptionsCreate()) {} ~ValidatorOptions() { spvValidatorOptionsDestroy(options_); } @@ -163,7 +163,7 @@ class ValidatorOptions { }; // A C++ wrapper around an optimization options object. -class OptimizerOptions { +class SPIRV_TOOLS_EXPORT OptimizerOptions { public: OptimizerOptions() : options_(spvOptimizerOptionsCreate()) {} ~OptimizerOptions() { spvOptimizerOptionsDestroy(options_); } @@ -205,7 +205,7 @@ class OptimizerOptions { }; // A C++ wrapper around a reducer options object. -class ReducerOptions { +class SPIRV_TOOLS_EXPORT ReducerOptions { public: ReducerOptions() : options_(spvReducerOptionsCreate()) {} ~ReducerOptions() { spvReducerOptionsDestroy(options_); } @@ -236,7 +236,7 @@ class ReducerOptions { }; // A C++ wrapper around a fuzzer options object. -class FuzzerOptions { +class SPIRV_TOOLS_EXPORT FuzzerOptions { public: FuzzerOptions() : options_(spvFuzzerOptionsCreate()) {} ~FuzzerOptions() { spvFuzzerOptionsDestroy(options_); } @@ -283,7 +283,7 @@ class FuzzerOptions { // provides methods for assembling, disassembling, and validating. // // Instances of this class provide basic thread-safety guarantee. -class SpirvTools { +class SPIRV_TOOLS_EXPORT SpirvTools { public: enum { // Default assembling option used by assemble(): @@ -388,7 +388,8 @@ class SpirvTools { bool IsValid() const; private: - struct Impl; // Opaque struct for holding the data fields used by this class. + struct SPIRV_TOOLS_LOCAL + Impl; // Opaque struct for holding the data fields used by this class. std::unique_ptr impl_; // Unique pointer to implementation data. }; diff --git a/include/spirv-tools/linker.hpp b/include/spirv-tools/linker.hpp index 5b60cb9f95..6ba6e9654a 100644 --- a/include/spirv-tools/linker.hpp +++ b/include/spirv-tools/linker.hpp @@ -24,7 +24,7 @@ namespace spvtools { -class LinkerOptions { +class SPIRV_TOOLS_EXPORT LinkerOptions { public: // Returns whether a library or an executable should be produced by the // linking phase. @@ -84,14 +84,15 @@ class LinkerOptions { // * Some entry points were defined multiple times; // * Some imported symbols did not have an exported counterpart; // * Possibly other reasons. -spv_result_t Link(const Context& context, - const std::vector>& binaries, - std::vector* linked_binary, - const LinkerOptions& options = LinkerOptions()); -spv_result_t Link(const Context& context, const uint32_t* const* binaries, - const size_t* binary_sizes, size_t num_binaries, - std::vector* linked_binary, - const LinkerOptions& options = LinkerOptions()); +SPIRV_TOOLS_EXPORT spv_result_t +Link(const Context& context, const std::vector>& binaries, + std::vector* linked_binary, + const LinkerOptions& options = LinkerOptions()); +SPIRV_TOOLS_EXPORT spv_result_t +Link(const Context& context, const uint32_t* const* binaries, + const size_t* binary_sizes, size_t num_binaries, + std::vector* linked_binary, + const LinkerOptions& options = LinkerOptions()); } // namespace spvtools diff --git a/include/spirv-tools/linter.hpp b/include/spirv-tools/linter.hpp index 52ed5a4672..ccbcf0c179 100644 --- a/include/spirv-tools/linter.hpp +++ b/include/spirv-tools/linter.hpp @@ -24,7 +24,7 @@ namespace spvtools { // provides a method for linting. // // Instances of this class provides basic thread-safety guarantee. -class Linter { +class SPIRV_TOOLS_EXPORT Linter { public: explicit Linter(spv_target_env env); @@ -40,7 +40,7 @@ class Linter { bool Run(const uint32_t* binary, size_t binary_size); private: - struct Impl; + struct SPIRV_TOOLS_LOCAL Impl; std::unique_ptr impl_; }; } // namespace spvtools diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp index 926e438fe2..a3119d9b43 100644 --- a/include/spirv-tools/optimizer.hpp +++ b/include/spirv-tools/optimizer.hpp @@ -37,14 +37,14 @@ struct DescriptorSetAndBinding; // provides methods for registering optimization passes and optimizing. // // Instances of this class provides basic thread-safety guarantee. -class Optimizer { +class SPIRV_TOOLS_EXPORT Optimizer { public: // The token for an optimization pass. It is returned via one of the // Create*Pass() standalone functions at the end of this header file and // consumed by the RegisterPass() method. Tokens are one-time objects that // only support move; copying is not allowed. struct PassToken { - struct Impl; // Opaque struct for holding internal data. + struct SPIRV_TOOLS_LOCAL Impl; // Opaque struct for holding internal data. PassToken(std::unique_ptr); @@ -239,7 +239,7 @@ class Optimizer { Optimizer& SetValidateAfterAll(bool validate); private: - struct Impl; // Opaque struct for holding internal data. + struct SPIRV_TOOLS_LOCAL Impl; // Opaque struct for holding internal data. std::unique_ptr impl_; // Unique pointer to internal data. }; From be6fb2a54c797ef6d355f5fc0bcc0180f7e035b8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Apr 2024 13:41:20 -0400 Subject: [PATCH 428/523] build(deps): bump the github-actions group across 1 directory with 4 updates (#5650) Bumps the github-actions group with 4 updates in the / directory: [actions/checkout](https://github.com/actions/checkout), [lukka/get-cmake](https://github.com/lukka/get-cmake), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [github/codeql-action](https://github.com/github/codeql-action). Updates `actions/checkout` from 4.1.2 to 4.1.3 - [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/9bb56186c3b09b4f86b1c65136769dd318469633...1d96c772d19495a3b5c517cd2bc0cb401ea0529f) Updates `lukka/get-cmake` from 3.29.1 to 3.29.2 - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/b111a57714ab6e67a65d3f857b72b148554c4262...4931ab1fc1604964c055eb330edb3f6b26ba0cfa) Updates `actions/upload-artifact` from 4.3.1 to 4.3.2 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/5d5d22a31266ced268874388b861e4b58bb5c2f3...1746f4ab65b179e0ea60a494b83293b640dd5bba) Updates `github/codeql-action` from 3.24.9 to 3.25.1 - [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/1b1aada464948af03b950897e5eb522f92603cc2...c7f9125735019aa87cfc361530512d50ea439c71) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: lukka/get-cmake dependency-type: direct:production update-type: version-update:semver-patch 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/ios.yml | 4 ++-- .github/workflows/release.yml | 2 +- .github/workflows/scorecard.yml | 6 +++--- .github/workflows/wasm.yml | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/autoroll.yml b/.github/workflows/autoroll.yml index e9b3176cf1..ed33622be1 100644 --- a/.github/workflows/autoroll.yml +++ b/.github/workflows/autoroll.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 # 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 9dabf88a91..43c99d667b 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -18,7 +18,7 @@ jobs: runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 with: fetch-depth: '0' - name: Download dependencies diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 10ee627a0d..feb64a7755 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -11,8 +11,8 @@ jobs: matrix: os: [ macos-12, macos-13 ] steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - - uses: lukka/get-cmake@b111a57714ab6e67a65d3f857b72b148554c4262 # v3.29.1 + - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: lukka/get-cmake@4931ab1fc1604964c055eb330edb3f6b26ba0cfa # v3.29.2 - name: Download dependencies run: python3 utils/git-sync-deps # NOTE: The MacOS SDK ships universal binaries. CI should reflect this. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 78750d906e..583c8f1fd6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: prepare-release-job: runs-on: ubuntu-latest steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 - 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 7d624c6211..adcfa76773 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -23,7 +23,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 with: persist-credentials: false @@ -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@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + uses: actions/upload-artifact@1746f4ab65b179e0ea60a494b83293b640dd5bba # v4.3.2 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@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9 + uses: github/codeql-action/upload-sarif@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1 with: sarif_file: results.sarif diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 06ad522b34..6807b3d1eb 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 with: fetch-depth: '0' - name: Build web From dd4b663e13c07fea4fbb3f70c1c91c86731099f7 Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Mon, 22 Apr 2024 12:29:56 -0700 Subject: [PATCH 429/523] Prepare release v2024.2 (#5651) * Roll external/googletest/ eff443c6e..5a37b517a (13 commits) https://github.com/google/googletest/compare/eff443c6ef5e...5a37b517ad4a Created with: roll-dep external/googletest * Prepare release v2024.2 --- CHANGES | 15 +++++++++++++++ DEPS | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 5a771be173..102703a87e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,20 @@ Revision history for SPIRV-Tools +v2024.2 2024-04-22 + - General + - Add SPIRV_TOOLS_EXPORT to public C++ API (#5591) + - Use bazel 7 and bzlmod (#5601) + - Optimizer + - opt: add GroupNonUniformPartitionedNV capability to trim pass (#5648) + - Fix rebuilding types with circular references. (#5637) + - Add AliasedPointer decoration (#5635) + - add support for vulkan-shader-profiler external passes (#5512) + - Validator + - A fix to support of SPV_QCOM_image_processing2 (#5646) + - spirv-val: Add Vulkan check for Rect Dim in OpTypeImage (#5644) + - Validate duplicate decorations and execution modes (#5641) + - Validator: Support SPV_NV_raw_access_chains (#5568) + v2024.1 2024-03-06 - General - Add tooling support for SPV_KHR_maximal_reconvergence (#5542) diff --git a/DEPS b/DEPS index 9dcbb09aa9..8413d1beb9 100644 --- a/DEPS +++ b/DEPS @@ -7,7 +7,7 @@ vars = { 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': 'eff443c6ef5eb6ab598bfaae27f9427fdb4f6af7', + 'googletest_revision': '5a37b517ad4ab6738556f0284c256cae1466c5b4', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From 57a42e6c1dfa44ca96a662044bd43637d1d4822e Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Wed, 1 May 2024 01:29:22 +0900 Subject: [PATCH 430/523] spirv-val: Separate Location check for tess patch (#5654) --- source/val/validate_interfaces.cpp | 22 ++++++++++ test/val/val_interfaces_test.cpp | 66 ++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/source/val/validate_interfaces.cpp b/source/val/validate_interfaces.cpp index ace548aa1a..8f10b9d07f 100644 --- a/source/val/validate_interfaces.cpp +++ b/source/val/validate_interfaces.cpp @@ -519,6 +519,8 @@ spv_result_t ValidateLocations(ValidationState_t& _, std::unordered_set input_locations; std::unordered_set output_locations_index0; std::unordered_set output_locations_index1; + std::unordered_set patch_locations_index0; + std::unordered_set patch_locations_index1; std::unordered_set seen; for (uint32_t i = 3; i < entry_point->operands().size(); ++i) { auto interface_id = entry_point->GetOperandAs(i); @@ -534,6 +536,26 @@ spv_result_t ValidateLocations(ValidationState_t& _, continue; } + // The two Tessellation stages have a "Patch" variable that interface with + // the Location mechanism, but are not suppose to be tied to the "normal" + // input/output Location. + // TODO - SPIR-V allows the Patch decoration to be applied to struct + // members, but is not allowed in GLSL/HLSL + bool has_patch = false; + for (auto& dec : _.id_decorations(interface_var->id())) { + if (dec.dec_type() == spv::Decoration::Patch) { + has_patch = true; + if (auto error = GetLocationsForVariable(_, entry_point, interface_var, + &patch_locations_index0, + &patch_locations_index1)) + return error; + break; + } + } + if (has_patch) { + continue; + } + auto locations = (storage_class == spv::StorageClass::Input) ? &input_locations : &output_locations_index0; diff --git a/test/val/val_interfaces_test.cpp b/test/val/val_interfaces_test.cpp index 4f62be799d..40e67184d5 100644 --- a/test/val/val_interfaces_test.cpp +++ b/test/val/val_interfaces_test.cpp @@ -623,6 +623,72 @@ OpFunctionEnd "at location 1")); } +TEST_F(ValidateInterfacesTest, VulkanPatchAndNonPatchOverlap) { + const std::string text = R"( + OpCapability Tessellation + OpMemoryModel Logical GLSL450 + OpEntryPoint TessellationControl %main "main" %a %b + OpExecutionMode %main OutputVertices 4 + OpDecorate %a Location 0 + OpDecorate %b Patch + OpDecorate %b Location 0 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 + %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 + %a = OpVariable %_ptr_Output__arr_float_uint_4 Output +%_ptr_Output_float = OpTypePointer Output %float + %b = OpVariable %_ptr_Output_float Output + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_2)); +} + +TEST_F(ValidateInterfacesTest, VulkanPatchOverlap) { + const std::string text = R"( + OpCapability Tessellation + OpMemoryModel Logical GLSL450 + OpEntryPoint TessellationControl %main "main" %a %b %c + OpExecutionMode %main OutputVertices 4 + OpDecorate %a Location 0 + OpDecorate %b Patch + OpDecorate %b Location 6 + OpDecorate %c Patch + OpDecorate %c Location 6 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 + %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 + %a = OpVariable %_ptr_Output__arr_float_uint_4 Output +%_ptr_Output_float = OpTypePointer Output %float + %b = OpVariable %_ptr_Output_float Output + %c = OpVariable %_ptr_Output_float Output + %main = OpFunction %void None %3 + %5 = OpLabel + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(text, SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-08722")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Entry-point has conflicting output location " + "assignment at location 6, component 0")); +} + TEST_F(ValidateInterfacesTest, VulkanLocationsSameLocationInputAndOutputNoConflict) { const std::string text = R"( From bfc3a15683d5174840eaf8c5d21065f60fe70a10 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Apr 2024 12:54:12 -0400 Subject: [PATCH 431/523] build(deps): bump the github-actions group across 1 directory with 3 updates (#5656) Bumps the github-actions group with 3 updates in the / directory: [actions/checkout](https://github.com/actions/checkout), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [github/codeql-action](https://github.com/github/codeql-action). Updates `actions/checkout` from 4.1.3 to 4.1.4 - [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/1d96c772d19495a3b5c517cd2bc0cb401ea0529f...0ad4b8fadaa221de15dcec353f45205ec38ea70b) Updates `actions/upload-artifact` from 4.3.2 to 4.3.3 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/1746f4ab65b179e0ea60a494b83293b640dd5bba...65462800fd760344b1a7b4382951275a0abb4808) Updates `github/codeql-action` from 3.25.1 to 3.25.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/c7f9125735019aa87cfc361530512d50ea439c71...d39d31e687223d841ef683f52467bd88e9b21c14) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch 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-patch 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/ios.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/scorecard.yml | 6 +++--- .github/workflows/wasm.yml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/autoroll.yml b/.github/workflows/autoroll.yml index ed33622be1..3954928d99 100644 --- a/.github/workflows/autoroll.yml +++ b/.github/workflows/autoroll.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 # 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 43c99d667b..ee8a9d531e 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -18,7 +18,7 @@ jobs: runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 with: fetch-depth: '0' - name: Download dependencies diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index feb64a7755..87ccd2d169 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -11,7 +11,7 @@ jobs: matrix: os: [ macos-12, macos-13 ] steps: - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - uses: lukka/get-cmake@4931ab1fc1604964c055eb330edb3f6b26ba0cfa # v3.29.2 - name: Download dependencies run: python3 utils/git-sync-deps diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 583c8f1fd6..22cf61e963 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: prepare-release-job: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - 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 adcfa76773..efda65dbbc 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -23,7 +23,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 with: persist-credentials: false @@ -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@1746f4ab65b179e0ea60a494b83293b640dd5bba # v4.3.2 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.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@c7f9125735019aa87cfc361530512d50ea439c71 # v3.25.1 + uses: github/codeql-action/upload-sarif@d39d31e687223d841ef683f52467bd88e9b21c14 # v3.25.3 with: sarif_file: results.sarif diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 6807b3d1eb..5eeec6109d 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 with: fetch-depth: '0' - name: Build web From 9241a58a8028c49510bc174b6c970e3c2b4b8e51 Mon Sep 17 00:00:00 2001 From: Jeremy Gebben Date: Thu, 2 May 2024 16:52:17 -0600 Subject: [PATCH 432/523] opt: Remove bindless and buff addr instrumentation passes (#5657) These were only used by Vulkan-Validation layers, but they have been replaced by other code for several months. --- Android.mk | 2 - BUILD.gn | 4 - include/spirv-tools/instrument.hpp | 9 +- include/spirv-tools/optimizer.hpp | 47 - source/opt/CMakeLists.txt | 4 - source/opt/inst_bindless_check_pass.cpp | 761 ---- source/opt/inst_bindless_check_pass.h | 130 - source/opt/inst_buff_addr_check_pass.cpp | 331 -- source/opt/inst_buff_addr_check_pass.h | 130 - source/opt/optimizer.cpp | 20 - source/opt/passes.h | 2 - test/opt/CMakeLists.txt | 2 - test/opt/inst_bindless_check_test.cpp | 5312 ---------------------- test/opt/inst_buff_addr_check_test.cpp | 772 ---- 14 files changed, 1 insertion(+), 7525 deletions(-) delete mode 100644 source/opt/inst_bindless_check_pass.cpp delete mode 100644 source/opt/inst_bindless_check_pass.h delete mode 100644 source/opt/inst_buff_addr_check_pass.cpp delete mode 100644 source/opt/inst_buff_addr_check_pass.h delete mode 100644 test/opt/inst_bindless_check_test.cpp delete mode 100644 test/opt/inst_buff_addr_check_test.cpp diff --git a/Android.mk b/Android.mk index e3e30bb3bb..2357864708 100644 --- a/Android.mk +++ b/Android.mk @@ -128,8 +128,6 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/inline_pass.cpp \ source/opt/inline_exhaustive_pass.cpp \ source/opt/inline_opaque_pass.cpp \ - source/opt/inst_bindless_check_pass.cpp \ - source/opt/inst_buff_addr_check_pass.cpp \ source/opt/inst_debug_printf_pass.cpp \ source/opt/instruction.cpp \ source/opt/instruction_list.cpp \ diff --git a/BUILD.gn b/BUILD.gn index 5d0ab86798..1a0f534fbb 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -681,10 +681,6 @@ static_library("spvtools_opt") { "source/opt/inline_opaque_pass.h", "source/opt/inline_pass.cpp", "source/opt/inline_pass.h", - "source/opt/inst_bindless_check_pass.cpp", - "source/opt/inst_bindless_check_pass.h", - "source/opt/inst_buff_addr_check_pass.cpp", - "source/opt/inst_buff_addr_check_pass.h", "source/opt/inst_debug_printf_pass.cpp", "source/opt/inst_debug_printf_pass.h", "source/opt/instruction.cpp", diff --git a/include/spirv-tools/instrument.hpp b/include/spirv-tools/instrument.hpp index 0a6e6306ec..d72a5d876c 100644 --- a/include/spirv-tools/instrument.hpp +++ b/include/spirv-tools/instrument.hpp @@ -22,8 +22,6 @@ // This file provides an external interface for applications that wish to // communicate with shaders instrumented by passes created by: // -// CreateInstBindlessCheckPass -// CreateInstBuffAddrCheckPass // CreateInstDebugPrintfPass // // More detailed documentation of these routines can be found in optimizer.hpp @@ -34,17 +32,12 @@ namespace spvtools { // // The following values provide offsets into the output buffer struct // generated by InstrumentPass::GenDebugStreamWrite. This method is utilized -// by InstBindlessCheckPass, InstBuffAddrCheckPass, and InstDebugPrintfPass. +// by InstDebugPrintfPass. // // The 1st member of the debug output buffer contains a set of flags // controlling the behavior of instrumentation code. static const int kDebugOutputFlagsOffset = 0; -// Values stored at kDebugOutputFlagsOffset -enum kInstFlags : unsigned int { - kInstBufferOOBEnable = 0x1, -}; - // The 2nd member of the debug output buffer contains the next available word // in the data stream to be written. Shaders will atomically read and update // this value so as not to overwrite each others records. This value must be diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp index a3119d9b43..e8ac260904 100644 --- a/include/spirv-tools/optimizer.hpp +++ b/include/spirv-tools/optimizer.hpp @@ -747,53 +747,6 @@ Optimizer::PassToken CreateReduceLoadSizePass( // them into a single instruction where possible. Optimizer::PassToken CreateCombineAccessChainsPass(); -// Create a pass to instrument bindless descriptor checking -// This pass instruments all bindless references to check that descriptor -// array indices are inbounds, and if the descriptor indexing extension is -// enabled, that the descriptor has been initialized. If the reference is -// invalid, a record is written to the debug output buffer (if space allows) -// and a null value is returned. This pass is designed to support bindless -// validation in the Vulkan validation layers. -// -// TODO(greg-lunarg): Add support for buffer references. Currently only does -// checking for image references. -// -// Dead code elimination should be run after this pass as the original, -// potentially invalid code is not removed and could cause undefined behavior, -// including crashes. It may also be beneficial to run Simplification -// (ie Constant Propagation), DeadBranchElim and BlockMerge after this pass to -// optimize instrument code involving the testing of compile-time constants. -// It is also generally recommended that this pass (and all -// instrumentation passes) be run after any legalization and optimization -// passes. This will give better analysis for the instrumentation and avoid -// potentially de-optimizing the instrument code, for example, inlining -// the debug record output function throughout the module. -// -// The instrumentation will write |shader_id| in each output record -// to identify the shader module which generated the record. -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 -// all referenced bytes fall in a valid buffer. If the reference is -// invalid, a record is written to the debug output buffer (if space allows) -// and a null value is returned. This pass is designed to support buffer -// address validation in the Vulkan validation layers. -// -// Dead code elimination should be run after this pass as the original, -// potentially invalid code is not removed and could cause undefined behavior, -// including crashes. Instruction simplification would likely also be -// beneficial. It is also generally recommended that this pass (and all -// instrumentation passes) be run after any legalization and optimization -// passes. This will give better analysis for the instrumentation and avoid -// 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 -// to identify the shader module which generated the record. -Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t shader_id); - // Create a pass to instrument OpDebugPrintf instructions. // This pass replaces all OpDebugPrintf instructions with instructions to write // a record containing the string id and the all specified values into a special diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt index 4e7d92d5ea..3994403eaa 100644 --- a/source/opt/CMakeLists.txt +++ b/source/opt/CMakeLists.txt @@ -64,8 +64,6 @@ set(SPIRV_TOOLS_OPT_SOURCES inline_exhaustive_pass.h inline_opaque_pass.h inline_pass.h - inst_bindless_check_pass.h - inst_buff_addr_check_pass.h inst_debug_printf_pass.h instruction.h instruction_list.h @@ -186,8 +184,6 @@ set(SPIRV_TOOLS_OPT_SOURCES inline_exhaustive_pass.cpp inline_opaque_pass.cpp inline_pass.cpp - inst_bindless_check_pass.cpp - inst_buff_addr_check_pass.cpp inst_debug_printf_pass.cpp instruction.cpp instruction_list.cpp diff --git a/source/opt/inst_bindless_check_pass.cpp b/source/opt/inst_bindless_check_pass.cpp deleted file mode 100644 index 8e7d4f83e8..0000000000 --- a/source/opt/inst_bindless_check_pass.cpp +++ /dev/null @@ -1,761 +0,0 @@ -// Copyright (c) 2018 The Khronos Group Inc. -// Copyright (c) 2018 Valve Corporation -// Copyright (c) 2018 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 "inst_bindless_check_pass.h" - -#include "source/spirv_constant.h" - -namespace spvtools { -namespace opt { -namespace { -// Input Operand Indices -constexpr int kSpvImageSampleImageIdInIdx = 0; -constexpr int kSpvSampledImageImageIdInIdx = 0; -constexpr int kSpvSampledImageSamplerIdInIdx = 1; -constexpr int kSpvImageSampledImageIdInIdx = 0; -constexpr int kSpvCopyObjectOperandIdInIdx = 0; -constexpr int kSpvLoadPtrIdInIdx = 0; -constexpr int kSpvAccessChainBaseIdInIdx = 0; -constexpr int kSpvAccessChainIndex0IdInIdx = 1; -constexpr int kSpvTypeArrayTypeIdInIdx = 0; -constexpr int kSpvVariableStorageClassInIdx = 0; -constexpr int kSpvTypePtrTypeIdInIdx = 1; -constexpr int kSpvTypeImageDim = 1; -constexpr int kSpvTypeImageDepth = 2; -constexpr int kSpvTypeImageArrayed = 3; -constexpr int kSpvTypeImageMS = 4; -} // namespace - -// This is a stub function for use with Import linkage -// clang-format off -// GLSL: -//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() { - enum { - kShaderId = 0, - kInstructionIndex = 1, - kStageInfo = 2, - kDescSet = 3, - kDescBinding = 4, - kDescIndex = 5, - kByteOffset = 6, - kNumArgs - }; - if (check_desc_func_id_ != 0) { - return check_desc_func_id_; - } - - 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(kNumArgs, uint_type); - param_types[2] = v4uint_type; - - const uint32_t func_id = TakeNextId(); - std::unique_ptr func = - StartFunction(func_id, type_mgr->GetBoolType(), param_types); - - func->SetFunctionEnd(EndFunction()); - - 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); - - check_desc_func_id_ = func_id; - // Make sure function doesn't get processed by - // InstrumentPass::InstProcessCallTreeFromRoots() - param2output_func_id_[3] = func_id; - return check_desc_func_id_; -} - -// clang-format off -// GLSL: -// result = inst_bindless_check_desc(shader_id, inst_idx, stage_info, desc_set, binding, desc_idx, offset); -// -// clang-format on -uint32_t InstBindlessCheckPass::GenDescCheckCall( - uint32_t inst_idx, uint32_t stage_idx, uint32_t var_id, - uint32_t desc_idx_id, uint32_t offset_id, InstructionBuilder* builder) { - const uint32_t func_id = GenDescCheckFunctionId(); - const std::vector args = { - builder->GetUintConstantId(shader_id_), - builder->GetUintConstantId(inst_idx), - GenStageInfo(stage_idx, builder), - builder->GetUintConstantId(var2desc_set_[var_id]), - builder->GetUintConstantId(var2binding_[var_id]), - GenUintCastCode(desc_idx_id, builder), - offset_id}; - return GenReadFunctionCall(GetBoolId(), func_id, args, builder); -} - -uint32_t InstBindlessCheckPass::CloneOriginalImage( - uint32_t old_image_id, InstructionBuilder* builder) { - Instruction* new_image_inst; - Instruction* old_image_inst = get_def_use_mgr()->GetDef(old_image_id); - if (old_image_inst->opcode() == spv::Op::OpLoad) { - new_image_inst = builder->AddLoad( - old_image_inst->type_id(), - old_image_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx)); - } else if (old_image_inst->opcode() == spv::Op::OpSampledImage) { - uint32_t clone_id = CloneOriginalImage( - old_image_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx), - builder); - new_image_inst = builder->AddBinaryOp( - old_image_inst->type_id(), spv::Op::OpSampledImage, clone_id, - old_image_inst->GetSingleWordInOperand(kSpvSampledImageSamplerIdInIdx)); - } else if (old_image_inst->opcode() == spv::Op::OpImage) { - uint32_t clone_id = CloneOriginalImage( - old_image_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx), - builder); - new_image_inst = builder->AddUnaryOp(old_image_inst->type_id(), - spv::Op::OpImage, clone_id); - } else { - assert(old_image_inst->opcode() == spv::Op::OpCopyObject && - "expecting OpCopyObject"); - uint32_t clone_id = CloneOriginalImage( - old_image_inst->GetSingleWordInOperand(kSpvCopyObjectOperandIdInIdx), - builder); - // Since we are cloning, no need to create new copy - new_image_inst = get_def_use_mgr()->GetDef(clone_id); - } - uid2offset_[new_image_inst->unique_id()] = - uid2offset_[old_image_inst->unique_id()]; - uint32_t new_image_id = new_image_inst->result_id(); - get_decoration_mgr()->CloneDecorations(old_image_id, new_image_id); - return new_image_id; -} - -uint32_t InstBindlessCheckPass::CloneOriginalReference( - RefAnalysis* ref, InstructionBuilder* builder) { - // If original is image based, start by cloning descriptor load - uint32_t new_image_id = 0; - if (ref->desc_load_id != 0) { - uint32_t old_image_id = - ref->ref_inst->GetSingleWordInOperand(kSpvImageSampleImageIdInIdx); - new_image_id = CloneOriginalImage(old_image_id, builder); - } - // Clone original reference - std::unique_ptr new_ref_inst(ref->ref_inst->Clone(context())); - uint32_t ref_result_id = ref->ref_inst->result_id(); - uint32_t new_ref_id = 0; - if (ref_result_id != 0) { - new_ref_id = TakeNextId(); - new_ref_inst->SetResultId(new_ref_id); - } - // Update new ref with new image if created - if (new_image_id != 0) - new_ref_inst->SetInOperand(kSpvImageSampleImageIdInIdx, {new_image_id}); - // Register new reference and add to new block - Instruction* added_inst = builder->AddInstruction(std::move(new_ref_inst)); - uid2offset_[added_inst->unique_id()] = - uid2offset_[ref->ref_inst->unique_id()]; - if (new_ref_id != 0) - get_decoration_mgr()->CloneDecorations(ref_result_id, new_ref_id); - return new_ref_id; -} - -uint32_t InstBindlessCheckPass::GetImageId(Instruction* inst) { - switch (inst->opcode()) { - case spv::Op::OpImageSampleImplicitLod: - case spv::Op::OpImageSampleExplicitLod: - case spv::Op::OpImageSampleDrefImplicitLod: - case spv::Op::OpImageSampleDrefExplicitLod: - case spv::Op::OpImageSampleProjImplicitLod: - case spv::Op::OpImageSampleProjExplicitLod: - case spv::Op::OpImageSampleProjDrefImplicitLod: - case spv::Op::OpImageSampleProjDrefExplicitLod: - case spv::Op::OpImageGather: - case spv::Op::OpImageDrefGather: - case spv::Op::OpImageQueryLod: - case spv::Op::OpImageSparseSampleImplicitLod: - case spv::Op::OpImageSparseSampleExplicitLod: - case spv::Op::OpImageSparseSampleDrefImplicitLod: - case spv::Op::OpImageSparseSampleDrefExplicitLod: - case spv::Op::OpImageSparseSampleProjImplicitLod: - case spv::Op::OpImageSparseSampleProjExplicitLod: - case spv::Op::OpImageSparseSampleProjDrefImplicitLod: - case spv::Op::OpImageSparseSampleProjDrefExplicitLod: - case spv::Op::OpImageSparseGather: - case spv::Op::OpImageSparseDrefGather: - case spv::Op::OpImageFetch: - case spv::Op::OpImageRead: - case spv::Op::OpImageQueryFormat: - case spv::Op::OpImageQueryOrder: - case spv::Op::OpImageQuerySizeLod: - case spv::Op::OpImageQuerySize: - case spv::Op::OpImageQueryLevels: - case spv::Op::OpImageQuerySamples: - case spv::Op::OpImageSparseFetch: - case spv::Op::OpImageSparseRead: - case spv::Op::OpImageWrite: - return inst->GetSingleWordInOperand(kSpvImageSampleImageIdInIdx); - default: - break; - } - return 0; -} - -Instruction* InstBindlessCheckPass::GetPointeeTypeInst(Instruction* ptr_inst) { - uint32_t pte_ty_id = GetPointeeTypeId(ptr_inst); - return get_def_use_mgr()->GetDef(pte_ty_id); -} - -bool InstBindlessCheckPass::AnalyzeDescriptorReference(Instruction* ref_inst, - RefAnalysis* ref) { - ref->ref_inst = ref_inst; - if (ref_inst->opcode() == spv::Op::OpLoad || - ref_inst->opcode() == spv::Op::OpStore) { - ref->desc_load_id = 0; - ref->ptr_id = ref_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx); - Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref->ptr_id); - if (ptr_inst->opcode() != spv::Op::OpAccessChain) return false; - ref->var_id = ptr_inst->GetSingleWordInOperand(kSpvAccessChainBaseIdInIdx); - Instruction* var_inst = get_def_use_mgr()->GetDef(ref->var_id); - if (var_inst->opcode() != spv::Op::OpVariable) return false; - spv::StorageClass storage_class = spv::StorageClass( - var_inst->GetSingleWordInOperand(kSpvVariableStorageClassInIdx)); - switch (storage_class) { - case spv::StorageClass::Uniform: - case spv::StorageClass::StorageBuffer: - break; - default: - return false; - break; - } - // Check for deprecated storage block form - if (storage_class == spv::StorageClass::Uniform) { - uint32_t var_ty_id = var_inst->type_id(); - Instruction* var_ty_inst = get_def_use_mgr()->GetDef(var_ty_id); - uint32_t ptr_ty_id = - var_ty_inst->GetSingleWordInOperand(kSpvTypePtrTypeIdInIdx); - Instruction* ptr_ty_inst = get_def_use_mgr()->GetDef(ptr_ty_id); - spv::Op ptr_ty_op = ptr_ty_inst->opcode(); - uint32_t block_ty_id = - (ptr_ty_op == spv::Op::OpTypeArray || - ptr_ty_op == spv::Op::OpTypeRuntimeArray) - ? ptr_ty_inst->GetSingleWordInOperand(kSpvTypeArrayTypeIdInIdx) - : ptr_ty_id; - assert(get_def_use_mgr()->GetDef(block_ty_id)->opcode() == - spv::Op::OpTypeStruct && - "unexpected block type"); - bool block_found = get_decoration_mgr()->FindDecoration( - block_ty_id, uint32_t(spv::Decoration::Block), - [](const Instruction&) { return true; }); - if (!block_found) { - // If block decoration not found, verify deprecated form of SSBO - bool buffer_block_found = get_decoration_mgr()->FindDecoration( - block_ty_id, uint32_t(spv::Decoration::BufferBlock), - [](const Instruction&) { return true; }); - USE_ASSERT(buffer_block_found && "block decoration not found"); - storage_class = spv::StorageClass::StorageBuffer; - } - } - ref->strg_class = uint32_t(storage_class); - Instruction* desc_type_inst = GetPointeeTypeInst(var_inst); - switch (desc_type_inst->opcode()) { - case spv::Op::OpTypeArray: - case spv::Op::OpTypeRuntimeArray: - // A load through a descriptor array will have at least 3 operands. We - // do not want to instrument loads of descriptors here which are part of - // an image-based reference. - if (ptr_inst->NumInOperands() < 3) return false; - ref->desc_idx_id = - ptr_inst->GetSingleWordInOperand(kSpvAccessChainIndex0IdInIdx); - break; - default: - break; - } - auto decos = - context()->get_decoration_mgr()->GetDecorationsFor(ref->var_id, false); - for (const auto& deco : decos) { - spv::Decoration d = spv::Decoration(deco->GetSingleWordInOperand(1u)); - if (d == spv::Decoration::DescriptorSet) { - ref->set = deco->GetSingleWordInOperand(2u); - } else if (d == spv::Decoration::Binding) { - ref->binding = deco->GetSingleWordInOperand(2u); - } - } - return true; - } - // Reference is not load or store. If not an image-based reference, return. - ref->image_id = GetImageId(ref_inst); - if (ref->image_id == 0) return false; - // Search for descriptor load - uint32_t desc_load_id = ref->image_id; - Instruction* desc_load_inst; - for (;;) { - desc_load_inst = get_def_use_mgr()->GetDef(desc_load_id); - if (desc_load_inst->opcode() == spv::Op::OpSampledImage) - desc_load_id = - desc_load_inst->GetSingleWordInOperand(kSpvSampledImageImageIdInIdx); - else if (desc_load_inst->opcode() == spv::Op::OpImage) - desc_load_id = - desc_load_inst->GetSingleWordInOperand(kSpvImageSampledImageIdInIdx); - else if (desc_load_inst->opcode() == spv::Op::OpCopyObject) - desc_load_id = - desc_load_inst->GetSingleWordInOperand(kSpvCopyObjectOperandIdInIdx); - else - break; - } - if (desc_load_inst->opcode() != spv::Op::OpLoad) { - // TODO(greg-lunarg): Handle additional possibilities? - return false; - } - ref->desc_load_id = desc_load_id; - ref->ptr_id = desc_load_inst->GetSingleWordInOperand(kSpvLoadPtrIdInIdx); - Instruction* ptr_inst = get_def_use_mgr()->GetDef(ref->ptr_id); - if (ptr_inst->opcode() == spv::Op::OpVariable) { - ref->desc_idx_id = 0; - ref->var_id = ref->ptr_id; - } else if (ptr_inst->opcode() == spv::Op::OpAccessChain) { - if (ptr_inst->NumInOperands() != 2) { - assert(false && "unexpected bindless index number"); - return false; - } - ref->desc_idx_id = - ptr_inst->GetSingleWordInOperand(kSpvAccessChainIndex0IdInIdx); - ref->var_id = ptr_inst->GetSingleWordInOperand(kSpvAccessChainBaseIdInIdx); - Instruction* var_inst = get_def_use_mgr()->GetDef(ref->var_id); - if (var_inst->opcode() != spv::Op::OpVariable) { - assert(false && "unexpected bindless base"); - return false; - } - } else { - // TODO(greg-lunarg): Handle additional possibilities? - return false; - } - auto decos = - context()->get_decoration_mgr()->GetDecorationsFor(ref->var_id, false); - for (const auto& deco : decos) { - spv::Decoration d = spv::Decoration(deco->GetSingleWordInOperand(1u)); - if (d == spv::Decoration::DescriptorSet) { - ref->set = deco->GetSingleWordInOperand(2u); - } else if (d == spv::Decoration::Binding) { - ref->binding = deco->GetSingleWordInOperand(2u); - } - } - return true; -} - -uint32_t InstBindlessCheckPass::FindStride(uint32_t ty_id, - uint32_t stride_deco) { - uint32_t stride = 0xdeadbeef; - bool found = get_decoration_mgr()->FindDecoration( - ty_id, stride_deco, [&stride](const Instruction& deco_inst) { - stride = deco_inst.GetSingleWordInOperand(2u); - return true; - }); - USE_ASSERT(found && "stride not found"); - return stride; -} - -uint32_t InstBindlessCheckPass::ByteSize(uint32_t ty_id, uint32_t matrix_stride, - bool col_major, bool in_matrix) { - analysis::TypeManager* type_mgr = context()->get_type_mgr(); - const analysis::Type* sz_ty = type_mgr->GetType(ty_id); - if (sz_ty->kind() == analysis::Type::kPointer) { - // Assuming PhysicalStorageBuffer pointer - return 8; - } - if (sz_ty->kind() == analysis::Type::kMatrix) { - assert(matrix_stride != 0 && "missing matrix stride"); - const analysis::Matrix* m_ty = sz_ty->AsMatrix(); - if (col_major) { - return m_ty->element_count() * matrix_stride; - } else { - const analysis::Vector* v_ty = m_ty->element_type()->AsVector(); - return v_ty->element_count() * matrix_stride; - } - } - uint32_t size = 1; - if (sz_ty->kind() == analysis::Type::kVector) { - const analysis::Vector* v_ty = sz_ty->AsVector(); - size = v_ty->element_count(); - const analysis::Type* comp_ty = v_ty->element_type(); - // if vector in row major matrix, the vector is strided so return the - // number of bytes spanned by the vector - if (in_matrix && !col_major && matrix_stride > 0) { - uint32_t comp_ty_id = type_mgr->GetId(comp_ty); - return (size - 1) * matrix_stride + ByteSize(comp_ty_id, 0, false, false); - } - sz_ty = comp_ty; - } - switch (sz_ty->kind()) { - case analysis::Type::kFloat: { - const analysis::Float* f_ty = sz_ty->AsFloat(); - size *= f_ty->width(); - } break; - case analysis::Type::kInteger: { - const analysis::Integer* i_ty = sz_ty->AsInteger(); - size *= i_ty->width(); - } break; - default: { assert(false && "unexpected type"); } break; - } - size /= 8; - return size; -} - -uint32_t InstBindlessCheckPass::GenLastByteIdx(RefAnalysis* ref, - InstructionBuilder* builder) { - // Find outermost buffer type and its access chain index - Instruction* var_inst = get_def_use_mgr()->GetDef(ref->var_id); - Instruction* desc_ty_inst = GetPointeeTypeInst(var_inst); - uint32_t buff_ty_id; - uint32_t ac_in_idx = 1; - switch (desc_ty_inst->opcode()) { - case spv::Op::OpTypeArray: - case spv::Op::OpTypeRuntimeArray: - buff_ty_id = desc_ty_inst->GetSingleWordInOperand(0); - ++ac_in_idx; - break; - default: - assert(desc_ty_inst->opcode() == spv::Op::OpTypeStruct && - "unexpected descriptor type"); - buff_ty_id = desc_ty_inst->result_id(); - break; - } - // Process remaining access chain indices - Instruction* ac_inst = get_def_use_mgr()->GetDef(ref->ptr_id); - uint32_t curr_ty_id = buff_ty_id; - uint32_t sum_id = 0u; - uint32_t matrix_stride = 0u; - bool col_major = false; - uint32_t matrix_stride_id = 0u; - bool in_matrix = false; - while (ac_in_idx < ac_inst->NumInOperands()) { - uint32_t curr_idx_id = ac_inst->GetSingleWordInOperand(ac_in_idx); - Instruction* curr_ty_inst = get_def_use_mgr()->GetDef(curr_ty_id); - uint32_t curr_offset_id = 0; - switch (curr_ty_inst->opcode()) { - case spv::Op::OpTypeArray: - case spv::Op::OpTypeRuntimeArray: { - // Get array stride and multiply by current index - uint32_t arr_stride = - FindStride(curr_ty_id, uint32_t(spv::Decoration::ArrayStride)); - uint32_t arr_stride_id = builder->GetUintConstantId(arr_stride); - uint32_t curr_idx_32b_id = Gen32BitCvtCode(curr_idx_id, builder); - Instruction* curr_offset_inst = builder->AddBinaryOp( - GetUintId(), spv::Op::OpIMul, arr_stride_id, curr_idx_32b_id); - curr_offset_id = curr_offset_inst->result_id(); - // Get element type for next step - curr_ty_id = curr_ty_inst->GetSingleWordInOperand(0); - } break; - case spv::Op::OpTypeMatrix: { - assert(matrix_stride != 0 && "missing matrix stride"); - matrix_stride_id = builder->GetUintConstantId(matrix_stride); - uint32_t vec_ty_id = curr_ty_inst->GetSingleWordInOperand(0); - // If column major, multiply column index by matrix stride, otherwise - // by vector component size and save matrix stride for vector (row) - // index - uint32_t col_stride_id; - if (col_major) { - col_stride_id = matrix_stride_id; - } else { - Instruction* vec_ty_inst = get_def_use_mgr()->GetDef(vec_ty_id); - uint32_t comp_ty_id = vec_ty_inst->GetSingleWordInOperand(0u); - uint32_t col_stride = ByteSize(comp_ty_id, 0u, false, false); - col_stride_id = builder->GetUintConstantId(col_stride); - } - uint32_t curr_idx_32b_id = Gen32BitCvtCode(curr_idx_id, builder); - Instruction* curr_offset_inst = builder->AddBinaryOp( - GetUintId(), spv::Op::OpIMul, col_stride_id, curr_idx_32b_id); - curr_offset_id = curr_offset_inst->result_id(); - // Get element type for next step - curr_ty_id = vec_ty_id; - in_matrix = true; - } break; - case spv::Op::OpTypeVector: { - // If inside a row major matrix type, multiply index by matrix stride, - // else multiply by component size - uint32_t comp_ty_id = curr_ty_inst->GetSingleWordInOperand(0u); - uint32_t curr_idx_32b_id = Gen32BitCvtCode(curr_idx_id, builder); - if (in_matrix && !col_major) { - Instruction* curr_offset_inst = builder->AddBinaryOp( - GetUintId(), spv::Op::OpIMul, matrix_stride_id, curr_idx_32b_id); - curr_offset_id = curr_offset_inst->result_id(); - } else { - uint32_t comp_ty_sz = ByteSize(comp_ty_id, 0u, false, false); - uint32_t comp_ty_sz_id = builder->GetUintConstantId(comp_ty_sz); - Instruction* curr_offset_inst = builder->AddBinaryOp( - GetUintId(), spv::Op::OpIMul, comp_ty_sz_id, curr_idx_32b_id); - curr_offset_id = curr_offset_inst->result_id(); - } - // Get element type for next step - curr_ty_id = comp_ty_id; - } break; - case spv::Op::OpTypeStruct: { - // Get buffer byte offset for the referenced member - Instruction* curr_idx_inst = get_def_use_mgr()->GetDef(curr_idx_id); - assert(curr_idx_inst->opcode() == spv::Op::OpConstant && - "unexpected struct index"); - uint32_t member_idx = curr_idx_inst->GetSingleWordInOperand(0); - uint32_t member_offset = 0xdeadbeef; - bool found = get_decoration_mgr()->FindDecoration( - curr_ty_id, uint32_t(spv::Decoration::Offset), - [&member_idx, &member_offset](const Instruction& deco_inst) { - if (deco_inst.GetSingleWordInOperand(1u) != member_idx) - return false; - member_offset = deco_inst.GetSingleWordInOperand(3u); - return true; - }); - USE_ASSERT(found && "member offset not found"); - curr_offset_id = builder->GetUintConstantId(member_offset); - // Look for matrix stride for this member if there is one. The matrix - // stride is not on the matrix type, but in a OpMemberDecorate on the - // enclosing struct type at the member index. If none found, reset - // stride to 0. - found = get_decoration_mgr()->FindDecoration( - curr_ty_id, uint32_t(spv::Decoration::MatrixStride), - [&member_idx, &matrix_stride](const Instruction& deco_inst) { - if (deco_inst.GetSingleWordInOperand(1u) != member_idx) - return false; - matrix_stride = deco_inst.GetSingleWordInOperand(3u); - return true; - }); - if (!found) matrix_stride = 0; - // Look for column major decoration - found = get_decoration_mgr()->FindDecoration( - curr_ty_id, uint32_t(spv::Decoration::ColMajor), - [&member_idx, &col_major](const Instruction& deco_inst) { - if (deco_inst.GetSingleWordInOperand(1u) != member_idx) - return false; - col_major = true; - return true; - }); - if (!found) col_major = false; - // Get element type for next step - curr_ty_id = curr_ty_inst->GetSingleWordInOperand(member_idx); - } break; - default: { assert(false && "unexpected non-composite type"); } break; - } - if (sum_id == 0) - sum_id = curr_offset_id; - else { - Instruction* sum_inst = - builder->AddIAdd(GetUintId(), sum_id, curr_offset_id); - sum_id = sum_inst->result_id(); - } - ++ac_in_idx; - } - // Add in offset of last byte of referenced object - uint32_t bsize = ByteSize(curr_ty_id, matrix_stride, col_major, in_matrix); - uint32_t last = bsize - 1; - uint32_t last_id = builder->GetUintConstantId(last); - Instruction* sum_inst = builder->AddIAdd(GetUintId(), sum_id, last_id); - return sum_inst->result_id(); -} - -void InstBindlessCheckPass::GenCheckCode( - uint32_t check_id, RefAnalysis* ref, - std::vector>* new_blocks) { - BasicBlock* back_blk_ptr = &*new_blocks->back(); - InstructionBuilder builder( - context(), back_blk_ptr, - IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); - // Gen conditional branch on check_id. Valid branch generates original - // reference. Invalid generates debug output and zero result (if needed). - uint32_t merge_blk_id = TakeNextId(); - uint32_t valid_blk_id = TakeNextId(); - uint32_t invalid_blk_id = TakeNextId(); - std::unique_ptr merge_label(NewLabel(merge_blk_id)); - std::unique_ptr valid_label(NewLabel(valid_blk_id)); - std::unique_ptr invalid_label(NewLabel(invalid_blk_id)); - (void)builder.AddConditionalBranch( - check_id, valid_blk_id, invalid_blk_id, merge_blk_id, - uint32_t(spv::SelectionControlMask::MaskNone)); - // Gen valid bounds branch - std::unique_ptr new_blk_ptr( - new BasicBlock(std::move(valid_label))); - builder.SetInsertPoint(&*new_blk_ptr); - uint32_t new_ref_id = CloneOriginalReference(ref, &builder); - uint32_t null_id = 0; - uint32_t ref_type_id = ref->ref_inst->type_id(); - (void)builder.AddBranch(merge_blk_id); - new_blocks->push_back(std::move(new_blk_ptr)); - // Gen invalid block - new_blk_ptr.reset(new BasicBlock(std::move(invalid_label))); - builder.SetInsertPoint(&*new_blk_ptr); - - // 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(); - analysis::Type* ref_type = type_mgr->GetType(ref_type_id); - if (ref_type->AsPointer() != nullptr) { - context()->AddCapability(spv::Capability::Int64); - uint32_t null_u64_id = GetNullId(GetUint64Id()); - Instruction* null_ptr_inst = builder.AddUnaryOp( - ref_type_id, spv::Op::OpConvertUToPtr, null_u64_id); - null_id = null_ptr_inst->result_id(); - } else { - null_id = GetNullId(ref_type_id); - } - } - // Remember last invalid block id - uint32_t last_invalid_blk_id = new_blk_ptr->GetLabelInst()->result_id(); - // Gen zero for invalid reference - (void)builder.AddBranch(merge_blk_id); - new_blocks->push_back(std::move(new_blk_ptr)); - // Gen merge block - new_blk_ptr.reset(new BasicBlock(std::move(merge_label))); - builder.SetInsertPoint(&*new_blk_ptr); - // Gen phi of new reference and zero, if necessary, and replace the - // result id of the original reference with that of the Phi. Kill original - // reference. - if (new_ref_id != 0) { - Instruction* phi_inst = builder.AddPhi( - ref_type_id, {new_ref_id, valid_blk_id, null_id, last_invalid_blk_id}); - context()->ReplaceAllUsesWith(ref->ref_inst->result_id(), - phi_inst->result_id()); - } - new_blocks->push_back(std::move(new_blk_ptr)); - context()->KillInst(ref->ref_inst); -} - -void InstBindlessCheckPass::GenDescCheckCode( - BasicBlock::iterator ref_inst_itr, - UptrVectorIterator ref_block_itr, uint32_t stage_idx, - std::vector>* new_blocks) { - // Look for reference through descriptor. If not, return. - RefAnalysis ref; - if (!AnalyzeDescriptorReference(&*ref_inst_itr, &ref)) return; - std::unique_ptr new_blk_ptr; - // Move original block's preceding instructions into first new block - MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr); - InstructionBuilder builder( - context(), &*new_blk_ptr, - IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); - new_blocks->push_back(std::move(new_blk_ptr)); - // Determine if we can only do initialization check - uint32_t ref_id = builder.GetUintConstantId(0u); - spv::Op op = ref.ref_inst->opcode(); - if (ref.desc_load_id != 0) { - uint32_t num_in_oprnds = ref.ref_inst->NumInOperands(); - if ((op == spv::Op::OpImageRead && num_in_oprnds == 2) || - (op == spv::Op::OpImageFetch && num_in_oprnds == 2) || - (op == spv::Op::OpImageWrite && num_in_oprnds == 3)) { - Instruction* image_inst = get_def_use_mgr()->GetDef(ref.image_id); - uint32_t image_ty_id = image_inst->type_id(); - Instruction* image_ty_inst = get_def_use_mgr()->GetDef(image_ty_id); - if (spv::Dim(image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDim)) == - spv::Dim::Buffer) { - if ((image_ty_inst->GetSingleWordInOperand(kSpvTypeImageDepth) == 0) && - (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageArrayed) == - 0) && - (image_ty_inst->GetSingleWordInOperand(kSpvTypeImageMS) == 0)) { - ref_id = GenUintCastCode(ref.ref_inst->GetSingleWordInOperand(1), - &builder); - } - } - } - } else { - // For now, only do bounds check for non-aggregate types. Otherwise - // just do descriptor initialization check. - // TODO(greg-lunarg): Do bounds check for aggregate loads and stores - Instruction* ref_ptr_inst = get_def_use_mgr()->GetDef(ref.ptr_id); - Instruction* pte_type_inst = GetPointeeTypeInst(ref_ptr_inst); - spv::Op pte_type_op = pte_type_inst->opcode(); - if (pte_type_op != spv::Op::OpTypeArray && - pte_type_op != spv::Op::OpTypeRuntimeArray && - pte_type_op != spv::Op::OpTypeStruct) { - ref_id = GenLastByteIdx(&ref, &builder); - } - } - // Read initialization/bounds from debug input buffer. If index id not yet - // set, binding is single descriptor, so set index to constant 0. - if (ref.desc_idx_id == 0) ref.desc_idx_id = builder.GetUintConstantId(0u); - uint32_t check_id = - GenDescCheckCall(ref.ref_inst->unique_id(), stage_idx, ref.var_id, - ref.desc_idx_id, ref_id, &builder); - - // Generate runtime initialization/bounds test code with true branch - // being full reference and false branch being zero - // for the referenced value. - GenCheckCode(check_id, &ref, new_blocks); - - // Move original block's remaining code into remainder/merge block and add - // to new blocks - BasicBlock* back_blk_ptr = &*new_blocks->back(); - MovePostludeCode(ref_block_itr, back_blk_ptr); -} - -void InstBindlessCheckPass::InitializeInstBindlessCheck() { - // Initialize base class - InitializeInstrument(); - for (auto& anno : get_module()->annotations()) { - if (anno.opcode() == spv::Op::OpDecorate) { - if (spv::Decoration(anno.GetSingleWordInOperand(1u)) == - spv::Decoration::DescriptorSet) { - var2desc_set_[anno.GetSingleWordInOperand(0u)] = - anno.GetSingleWordInOperand(2u); - } else if (spv::Decoration(anno.GetSingleWordInOperand(1u)) == - spv::Decoration::Binding) { - var2binding_[anno.GetSingleWordInOperand(0u)] = - anno.GetSingleWordInOperand(2u); - } - } - } -} - -Pass::Status InstBindlessCheckPass::ProcessImpl() { - // The memory model and linkage must always be updated for spirv-link to work - // correctly. - AddStorageBufferExt(); - if (!get_feature_mgr()->HasExtension(kSPV_KHR_physical_storage_buffer)) { - context()->AddExtension("SPV_KHR_physical_storage_buffer"); - } - - context()->AddCapability(spv::Capability::PhysicalStorageBufferAddresses); - Instruction* memory_model = get_module()->GetMemoryModel(); - memory_model->SetInOperand( - 0u, {uint32_t(spv::AddressingModel::PhysicalStorageBuffer64)}); - - context()->AddCapability(spv::Capability::Linkage); - - InstProcessFunction pfn = - [this](BasicBlock::iterator ref_inst_itr, - UptrVectorIterator ref_block_itr, uint32_t stage_idx, - std::vector>* new_blocks) { - return GenDescCheckCode(ref_inst_itr, ref_block_itr, stage_idx, - new_blocks); - }; - - InstProcessEntryPointCallTree(pfn); - // This pass always changes the memory model, so that linking will work - // properly. - return Status::SuccessWithChange; -} - -Pass::Status InstBindlessCheckPass::Process() { - InitializeInstBindlessCheck(); - return ProcessImpl(); -} - -} // namespace opt -} // namespace spvtools diff --git a/source/opt/inst_bindless_check_pass.h b/source/opt/inst_bindless_check_pass.h deleted file mode 100644 index 243cba7671..0000000000 --- a/source/opt/inst_bindless_check_pass.h +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) 2018 The Khronos Group Inc. -// Copyright (c) 2018 Valve Corporation -// Copyright (c) 2018 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. - -#ifndef LIBSPIRV_OPT_INST_BINDLESS_CHECK_PASS_H_ -#define LIBSPIRV_OPT_INST_BINDLESS_CHECK_PASS_H_ - -#include "instrument_pass.h" - -namespace spvtools { -namespace opt { - -// This class/pass is designed to support the bindless (descriptor indexing) -// GPU-assisted validation layer of -// https://github.com/KhronosGroup/Vulkan-ValidationLayers. Its internal and -// external design may change as the layer evolves. -class InstBindlessCheckPass : public InstrumentPass { - public: - InstBindlessCheckPass(uint32_t shader_id) - : InstrumentPass(0, shader_id, true, true) {} - - ~InstBindlessCheckPass() override = default; - - // See optimizer.hpp for pass user documentation. - Status Process() override; - - const char* name() const override { return "inst-bindless-check-pass"; } - - private: - void GenDescCheckCode(BasicBlock::iterator ref_inst_itr, - UptrVectorIterator ref_block_itr, - uint32_t stage_idx, - std::vector>* new_blocks); - - uint32_t GenDescCheckFunctionId(); - - uint32_t GenDescCheckCall(uint32_t inst_idx, uint32_t stage_idx, - uint32_t var_id, uint32_t index_id, - uint32_t byte_offset, InstructionBuilder* builder); - - // Analysis data for descriptor reference components, generated by - // AnalyzeDescriptorReference. It is necessary and sufficient for further - // analysis and regeneration of the reference. - typedef struct RefAnalysis { - uint32_t desc_load_id{0}; - uint32_t image_id{0}; - uint32_t load_id{0}; - uint32_t ptr_id{0}; - uint32_t var_id{0}; - uint32_t set{0}; - uint32_t binding{0}; - uint32_t desc_idx_id{0}; - uint32_t strg_class{0}; - Instruction* ref_inst{nullptr}; - } RefAnalysis; - - // Return size of type |ty_id| in bytes. Use |matrix_stride| and |col_major| - // for matrix type, or for vector type if vector is |in_matrix|. - uint32_t ByteSize(uint32_t ty_id, uint32_t matrix_stride, bool col_major, - bool in_matrix); - - // Return stride of type |ty_id| with decoration |stride_deco|. Return 0 - // if not found - uint32_t FindStride(uint32_t ty_id, uint32_t stride_deco); - - // Generate index of last byte referenced by buffer reference |ref| - uint32_t GenLastByteIdx(RefAnalysis* ref, InstructionBuilder* builder); - - // Clone original image computation starting at |image_id| into |builder|. - // This may generate more than one instruction if necessary. - uint32_t CloneOriginalImage(uint32_t image_id, InstructionBuilder* builder); - - // Clone original original reference encapsulated by |ref| into |builder|. - // This may generate more than one instruction if necessary. - uint32_t CloneOriginalReference(RefAnalysis* ref, - InstructionBuilder* builder); - - // If |inst| references through an image, return the id of the image it - // references through. Else return 0. - uint32_t GetImageId(Instruction* inst); - - // Get pointee type inst of pointer value |ptr_inst|. - Instruction* GetPointeeTypeInst(Instruction* ptr_inst); - - // Analyze descriptor reference |ref_inst| and save components into |ref|. - // Return true if |ref_inst| is a descriptor reference, false otherwise. - bool AnalyzeDescriptorReference(Instruction* ref_inst, RefAnalysis* ref); - - // Generate instrumentation code for generic test result |check_id|, starting - // with |builder| of block |new_blk_ptr|, adding new blocks to |new_blocks|. - // Generate conditional branch to a valid or invalid branch. Generate valid - // block which does original reference |ref|. Generate invalid block which - // 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, RefAnalysis* ref, - std::vector>* new_blocks); - - // Initialize state for instrumenting bindless checking - void InitializeInstBindlessCheck(); - - // Apply GenDescIdxCheckCode to every instruction in module. Then apply - // GenDescInitCheckCode to every instruction in module. - Pass::Status ProcessImpl(); - - // Mapping from variable to descriptor set - std::unordered_map var2desc_set_; - - // Mapping from variable to binding - std::unordered_map var2binding_; - - uint32_t check_desc_func_id_{0}; -}; - -} // namespace opt -} // namespace spvtools - -#endif // LIBSPIRV_OPT_INST_BINDLESS_CHECK_PASS_H_ diff --git a/source/opt/inst_buff_addr_check_pass.cpp b/source/opt/inst_buff_addr_check_pass.cpp deleted file mode 100644 index e6c550878a..0000000000 --- a/source/opt/inst_buff_addr_check_pass.cpp +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright (c) 2019 The Khronos Group Inc. -// Copyright (c) 2019 Valve Corporation -// Copyright (c) 2019 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 "inst_buff_addr_check_pass.h" - -namespace spvtools { -namespace opt { - -uint32_t InstBuffAddrCheckPass::CloneOriginalReference( - Instruction* ref_inst, InstructionBuilder* builder) { - // Clone original ref with new result id (if load) - assert((ref_inst->opcode() == spv::Op::OpLoad || - ref_inst->opcode() == spv::Op::OpStore) && - "unexpected ref"); - std::unique_ptr new_ref_inst(ref_inst->Clone(context())); - uint32_t ref_result_id = ref_inst->result_id(); - uint32_t new_ref_id = 0; - if (ref_result_id != 0) { - new_ref_id = TakeNextId(); - new_ref_inst->SetResultId(new_ref_id); - } - // Register new reference and add to new block - Instruction* added_inst = builder->AddInstruction(std::move(new_ref_inst)); - uid2offset_[added_inst->unique_id()] = uid2offset_[ref_inst->unique_id()]; - if (new_ref_id != 0) - get_decoration_mgr()->CloneDecorations(ref_result_id, new_ref_id); - return new_ref_id; -} - -bool InstBuffAddrCheckPass::IsPhysicalBuffAddrReference(Instruction* ref_inst) { - if (ref_inst->opcode() != spv::Op::OpLoad && - ref_inst->opcode() != spv::Op::OpStore) - return false; - uint32_t ptr_id = ref_inst->GetSingleWordInOperand(0); - analysis::DefUseManager* du_mgr = get_def_use_mgr(); - Instruction* ptr_inst = du_mgr->GetDef(ptr_id); - if (ptr_inst->opcode() != spv::Op::OpAccessChain) return false; - uint32_t ptr_ty_id = ptr_inst->type_id(); - Instruction* ptr_ty_inst = du_mgr->GetDef(ptr_ty_id); - if (spv::StorageClass(ptr_ty_inst->GetSingleWordInOperand(0)) != - spv::StorageClass::PhysicalStorageBufferEXT) - return false; - return true; -} - -// TODO(greg-lunarg): Refactor with InstBindlessCheckPass::GenCheckCode() ?? -void InstBuffAddrCheckPass::GenCheckCode( - uint32_t check_id, Instruction* ref_inst, - std::vector>* new_blocks) { - BasicBlock* back_blk_ptr = &*new_blocks->back(); - InstructionBuilder builder( - context(), back_blk_ptr, - IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); - // Gen conditional branch on check_id. Valid branch generates original - // reference. Invalid generates debug output and zero result (if needed). - uint32_t merge_blk_id = TakeNextId(); - uint32_t valid_blk_id = TakeNextId(); - uint32_t invalid_blk_id = TakeNextId(); - std::unique_ptr merge_label(NewLabel(merge_blk_id)); - std::unique_ptr valid_label(NewLabel(valid_blk_id)); - std::unique_ptr invalid_label(NewLabel(invalid_blk_id)); - (void)builder.AddConditionalBranch( - check_id, valid_blk_id, invalid_blk_id, merge_blk_id, - uint32_t(spv::SelectionControlMask::MaskNone)); - // Gen valid branch - std::unique_ptr new_blk_ptr( - new BasicBlock(std::move(valid_label))); - builder.SetInsertPoint(&*new_blk_ptr); - uint32_t new_ref_id = CloneOriginalReference(ref_inst, &builder); - (void)builder.AddBranch(merge_blk_id); - new_blocks->push_back(std::move(new_blk_ptr)); - // Gen invalid block - new_blk_ptr.reset(new BasicBlock(std::move(invalid_label))); - builder.SetInsertPoint(&*new_blk_ptr); - // 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; - if (new_ref_id != 0) { - uint32_t ref_type_id = ref_inst->type_id(); - analysis::TypeManager* type_mgr = context()->get_type_mgr(); - analysis::Type* ref_type = type_mgr->GetType(ref_type_id); - if (ref_type->AsPointer() != nullptr) { - uint32_t null_u64_id = GetNullId(GetUint64Id()); - Instruction* null_ptr_inst = builder.AddUnaryOp( - ref_type_id, spv::Op::OpConvertUToPtr, null_u64_id); - null_id = null_ptr_inst->result_id(); - } else { - null_id = GetNullId(ref_type_id); - } - } - (void)builder.AddBranch(merge_blk_id); - new_blocks->push_back(std::move(new_blk_ptr)); - // Gen merge block - new_blk_ptr.reset(new BasicBlock(std::move(merge_label))); - builder.SetInsertPoint(&*new_blk_ptr); - // Gen phi of new reference and zero, if necessary, and replace the - // result id of the original reference with that of the Phi. Kill original - // reference. - if (new_ref_id != 0) { - Instruction* phi_inst = - builder.AddPhi(ref_inst->type_id(), - {new_ref_id, valid_blk_id, null_id, invalid_blk_id}); - context()->ReplaceAllUsesWith(ref_inst->result_id(), phi_inst->result_id()); - } - new_blocks->push_back(std::move(new_blk_ptr)); - context()->KillInst(ref_inst); -} - -uint32_t InstBuffAddrCheckPass::GetTypeLength(uint32_t type_id) { - Instruction* type_inst = get_def_use_mgr()->GetDef(type_id); - switch (type_inst->opcode()) { - case spv::Op::OpTypeFloat: - case spv::Op::OpTypeInt: - return type_inst->GetSingleWordInOperand(0) / 8u; - case spv::Op::OpTypeVector: - case spv::Op::OpTypeMatrix: - return type_inst->GetSingleWordInOperand(1) * - GetTypeLength(type_inst->GetSingleWordInOperand(0)); - case spv::Op::OpTypePointer: - assert(spv::StorageClass(type_inst->GetSingleWordInOperand(0)) == - spv::StorageClass::PhysicalStorageBufferEXT && - "unexpected pointer type"); - return 8u; - case spv::Op::OpTypeArray: { - uint32_t const_id = type_inst->GetSingleWordInOperand(1); - Instruction* const_inst = get_def_use_mgr()->GetDef(const_id); - uint32_t cnt = const_inst->GetSingleWordInOperand(0); - return cnt * GetTypeLength(type_inst->GetSingleWordInOperand(0)); - } - case spv::Op::OpTypeStruct: { - // Figure out the location of the last byte of the last member of the - // structure. - uint32_t last_offset = 0, last_len = 0; - - get_decoration_mgr()->ForEachDecoration( - type_id, uint32_t(spv::Decoration::Offset), - [&last_offset](const Instruction& deco_inst) { - last_offset = deco_inst.GetSingleWordInOperand(3); - }); - type_inst->ForEachInId([&last_len, this](const uint32_t* iid) { - last_len = GetTypeLength(*iid); - }); - return last_offset + last_len; - } - case spv::Op::OpTypeRuntimeArray: - default: - assert(false && "unexpected type"); - return 0; - } -} - -void InstBuffAddrCheckPass::AddParam(uint32_t type_id, - std::vector* param_vec, - std::unique_ptr* input_func) { - uint32_t pid = TakeNextId(); - param_vec->push_back(pid); - std::unique_ptr param_inst(new Instruction( - get_module()->context(), spv::Op::OpFunctionParameter, type_id, pid, {})); - get_def_use_mgr()->AnalyzeInstDefUse(&*param_inst); - (*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() { - 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 stage_idx) { - // Enable Int64 if necessary - // Convert reference pointer to uint64 - 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); - const uint32_t ref_ptr_ty_id = ref_ptr_inst->type_id(); - Instruction* ref_ptr_ty_inst = du_mgr->GetDef(ref_ptr_ty_id); - const uint32_t ref_len = - GetTypeLength(ref_ptr_ty_inst->GetSingleWordInOperand(1)); - // Gen call to search and test function - 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( - BasicBlock::iterator ref_inst_itr, - UptrVectorIterator ref_block_itr, uint32_t stage_idx, - std::vector>* new_blocks) { - // Look for reference through indexed descriptor. If found, analyze and - // save components. If not, return. - Instruction* ref_inst = &*ref_inst_itr; - if (!IsPhysicalBuffAddrReference(ref_inst)) return; - // Move original block's preceding instructions into first new block - std::unique_ptr new_blk_ptr; - MovePreludeCode(ref_inst_itr, ref_block_itr, &new_blk_ptr); - InstructionBuilder builder( - context(), &*new_blk_ptr, - IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); - new_blocks->push_back(std::move(new_blk_ptr)); - // 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, 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, 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(); - MovePostludeCode(ref_block_itr, back_blk_ptr); -} - -void InstBuffAddrCheckPass::InitInstBuffAddrCheck() { - // Initialize base class - InitializeInstrument(); - // Initialize class - search_test_func_id_ = 0; -} - -Pass::Status InstBuffAddrCheckPass::ProcessImpl() { - // The memory model and linkage must always be updated for spirv-link to work - // correctly. - AddStorageBufferExt(); - if (!get_feature_mgr()->HasExtension(kSPV_KHR_physical_storage_buffer)) { - context()->AddExtension("SPV_KHR_physical_storage_buffer"); - } - - context()->AddCapability(spv::Capability::PhysicalStorageBufferAddresses); - Instruction* memory_model = get_module()->GetMemoryModel(); - memory_model->SetInOperand( - 0u, {uint32_t(spv::AddressingModel::PhysicalStorageBuffer64)}); - - context()->AddCapability(spv::Capability::Int64); - context()->AddCapability(spv::Capability::Linkage); - // Perform bindless bounds check on each entry point function in module - InstProcessFunction pfn = - [this](BasicBlock::iterator ref_inst_itr, - UptrVectorIterator ref_block_itr, uint32_t stage_idx, - std::vector>* new_blocks) { - return GenBuffAddrCheckCode(ref_inst_itr, ref_block_itr, stage_idx, - new_blocks); - }; - InstProcessEntryPointCallTree(pfn); - // This pass always changes the memory model, so that linking will work - // properly. - return Status::SuccessWithChange; -} - -Pass::Status InstBuffAddrCheckPass::Process() { - InitInstBuffAddrCheck(); - return ProcessImpl(); -} - -} // namespace opt -} // namespace spvtools diff --git a/source/opt/inst_buff_addr_check_pass.h b/source/opt/inst_buff_addr_check_pass.h deleted file mode 100644 index f07f98a0f2..0000000000 --- a/source/opt/inst_buff_addr_check_pass.h +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright (c) 2019 The Khronos Group Inc. -// Copyright (c) 2019 Valve Corporation -// Copyright (c) 2019 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. - -#ifndef LIBSPIRV_OPT_INST_BUFFER_ADDRESS_PASS_H_ -#define LIBSPIRV_OPT_INST_BUFFER_ADDRESS_PASS_H_ - -#include "instrument_pass.h" - -namespace spvtools { -namespace opt { - -// This class/pass is designed to support the GPU-assisted validation layer of -// the Buffer Device Address (BDA) extension in -// https://github.com/KhronosGroup/Vulkan-ValidationLayers. The internal and -// external design of this class may change as the layer evolves. -class InstBuffAddrCheckPass : public InstrumentPass { - public: - // For test harness only - InstBuffAddrCheckPass() : InstrumentPass(0, 23, false, true) {} - // For all other interfaces - InstBuffAddrCheckPass(uint32_t shader_id) - : InstrumentPass(0, shader_id, false, true) {} - - ~InstBuffAddrCheckPass() override = default; - - // See optimizer.hpp for pass user documentation. - Status Process() override; - - const char* name() const override { return "inst-buff-addr-check-pass"; } - - private: - // Return byte length of type |type_id|. Must be int, float, vector, matrix, - // struct, array or physical pointer. Uses std430 alignment and sizes. - uint32_t GetTypeLength(uint32_t type_id); - - // Add |type_id| param to |input_func| and add id to |param_vec|. - void AddParam(uint32_t type_id, std::vector* param_vec, - std::unique_ptr* input_func); - - // Return id for search and test function. Generate it if not already gen'd. - uint32_t GetSearchAndTestFuncId(); - - // Generate code into |builder| to do search of the BDA debug input buffer - // for the buffer used by |ref_inst| and test that all bytes of reference - // 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 stage_idx); - - // This function does checking instrumentation on a single - // instruction which references through a physical storage buffer address. - // GenBuffAddrCheckCode generates code that checks that all bytes that - // are referenced fall within a buffer that was queried via - // the Vulkan API call vkGetBufferDeviceAddressEXT(). - // - // The function is designed to be passed to - // InstrumentPass::InstProcessEntryPointCallTree(), which applies the - // function to each instruction in a module and replaces the instruction - // with instrumented code if warranted. - // - // If |ref_inst_itr| is a physical storage buffer reference, return in - // |new_blocks| the result of instrumenting it with validation code within - // its block at |ref_block_itr|. The validation code first executes a check - // for the specific condition called for. If the check passes, it executes - // the remainder of the reference, otherwise writes a record to the debug - // output buffer stream including |function_idx, instruction_idx, stage_idx| - // and replaces the reference with the null value of the original type. The - // block at |ref_block_itr| can just be replaced with the blocks in - // |new_blocks|, which will contain at least two blocks. The last block will - // comprise all instructions following |ref_inst_itr|, - // preceded by a phi instruction if needed. - // - // This instrumentation function utilizes GenDebugStreamWrite() to write its - // error records. The validation-specific part of the error record will - // have the format: - // - // Validation Error Code (=kInstErrorBuffAddr) - // Buffer Address (lowest 32 bits) - // Buffer Address (highest 32 bits) - // - void GenBuffAddrCheckCode( - BasicBlock::iterator ref_inst_itr, - UptrVectorIterator ref_block_itr, uint32_t stage_idx, - std::vector>* new_blocks); - - // Return true if |ref_inst| is a physical buffer address reference, false - // otherwise. - bool IsPhysicalBuffAddrReference(Instruction* ref_inst); - - // Clone original reference |ref_inst| into |builder| and return id of result - uint32_t CloneOriginalReference(Instruction* ref_inst, - InstructionBuilder* builder); - - // Generate instrumentation code for boolean test result |check_id|, - // adding new blocks to |new_blocks|. Generate conditional branch to valid - // or invalid reference blocks. Generate valid reference block which does - // original reference |ref_inst|. Then generate invalid reference block which - // 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, Instruction* ref_inst, - std::vector>* new_blocks); - - // Initialize state for instrumenting physical buffer address checking - void InitInstBuffAddrCheck(); - - // Apply GenBuffAddrCheckCode to every instruction in module. - Pass::Status ProcessImpl(); - - // Id of search and test function, if already gen'd, else zero. - uint32_t search_test_func_id_; -}; - -} // namespace opt -} // namespace spvtools - -#endif // LIBSPIRV_OPT_INST_BUFFER_ADDRESS_PASS_H_ diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index c4c2b0f554..e29bbf7b27 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -451,16 +451,6 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag, RegisterPass(CreateWorkaround1209Pass()); } else if (pass_name == "replace-invalid-opcode") { RegisterPass(CreateReplaceInvalidOpcodePass()); - } else if (pass_name == "inst-bindless-check" || - pass_name == "inst-desc-idx-check" || - pass_name == "inst-buff-oob-check") { - // preserve legacy names - RegisterPass(CreateInstBindlessCheckPass(23)); - RegisterPass(CreateSimplificationPass()); - RegisterPass(CreateDeadBranchElimPass()); - RegisterPass(CreateBlockMergePass()); - } else if (pass_name == "inst-buff-addr-check") { - RegisterPass(CreateInstBuffAddrCheckPass(23)); } else if (pass_name == "convert-relaxed-to-half") { RegisterPass(CreateConvertRelaxedToHalfPass()); } else if (pass_name == "relax-float-ops") { @@ -1023,22 +1013,12 @@ Optimizer::PassToken CreateUpgradeMemoryModelPass() { MakeUnique()); } -Optimizer::PassToken CreateInstBindlessCheckPass(uint32_t shader_id) { - return MakeUnique( - MakeUnique(shader_id)); -} - Optimizer::PassToken CreateInstDebugPrintfPass(uint32_t desc_set, uint32_t shader_id) { return MakeUnique( MakeUnique(desc_set, shader_id)); } -Optimizer::PassToken CreateInstBuffAddrCheckPass(uint32_t shader_id) { - return MakeUnique( - MakeUnique(shader_id)); -} - Optimizer::PassToken CreateConvertRelaxedToHalfPass() { return MakeUnique( MakeUnique()); diff --git a/source/opt/passes.h b/source/opt/passes.h index 9d027fbf4c..8b6755f413 100644 --- a/source/opt/passes.h +++ b/source/opt/passes.h @@ -48,8 +48,6 @@ #include "source/opt/if_conversion.h" #include "source/opt/inline_exhaustive_pass.h" #include "source/opt/inline_opaque_pass.h" -#include "source/opt/inst_bindless_check_pass.h" -#include "source/opt/inst_buff_addr_check_pass.h" #include "source/opt/inst_debug_printf_pass.h" #include "source/opt/interface_var_sroa.h" #include "source/opt/interp_fixup_pass.h" diff --git a/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt index 92d266bba3..384f361040 100644 --- a/test/opt/CMakeLists.txt +++ b/test/opt/CMakeLists.txt @@ -60,8 +60,6 @@ add_spvtools_unittest(TARGET opt inline_opaque_test.cpp inline_test.cpp insert_extract_elim_test.cpp - inst_bindless_check_test.cpp - inst_buff_addr_check_test.cpp inst_debug_printf_test.cpp instruction_list_test.cpp instruction_test.cpp diff --git a/test/opt/inst_bindless_check_test.cpp b/test/opt/inst_bindless_check_test.cpp deleted file mode 100644 index 08da367fd5..0000000000 --- a/test/opt/inst_bindless_check_test.cpp +++ /dev/null @@ -1,5312 +0,0 @@ -// Copyright (c) 2017-2022 Valve Corporation -// Copyright (c) 2017-2022 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. - -#include -#include - -#include "test/opt/pass_fixture.h" -#include "test/opt/pass_utils.h" - -namespace spvtools { -namespace opt { -namespace { - -using InstBindlessTest = PassTest<::testing::Test>; - -static const std::string kFuncName = "inst_bindless_check_desc"; - -static const std::string kImportDeco = R"( -;CHECK: OpDecorate %)" + kFuncName + R"( LinkageAttributes ")" + - kFuncName + R"(" Import -)"; - -static const std::string kImportStub = R"( -;CHECK: %)" + kFuncName + R"( = OpFunction %bool None {{%\w+}} -;CHECK: OpFunctionEnd -)"; - -TEST_F(InstBindlessTest, Simple) { - // Texture2D g_tColor[128]; - // - // layout(push_constant) cbuffer PerViewConstantBuffer_t - // { - // uint g_nDataIdx; - // }; - // - // SamplerState g_sAniso; - // - // struct PS_INPUT - // { - // float2 vTextureCoords : TEXCOORD2; - // }; - // - // struct PS_OUTPUT - // { - // float4 vColor : SV_Target0; - // }; - // - // PS_OUTPUT MainPs(PS_INPUT i) - // { - // PS_OUTPUT ps_output; - // ps_output.vColor = - // g_tColor[ g_nDataIdx ].Sample(g_sAniso, i.vTextureCoords.xy); - // return ps_output; - // } - - const std::string entry = R"( -OpCapability Shader -;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 -OpExecutionMode %MainPs OriginUpperLeft -OpSource HLSL 500 -)"; - - // clang-format off - const std::string names_annots = R"( -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 3 -OpDecorate %g_tColor Binding 0 -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)" -+ kImportDeco + -R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -)"; - - const std::string consts_types_vars = R"( -%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 -%PerViewConstantBuffer_t = OpTypeStruct %uint -%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t -%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant -%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint -%_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16 -%24 = OpTypeSampler -%_ptr_UniformConstant_24 = OpTypePointer UniformConstant %24 -%g_sAniso = OpVariable %_ptr_UniformConstant_24 UniformConstant -%26 = 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 -;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -)"; - - const std::string main_func = R"( -%MainPs = OpFunction %void None %10 -%29 = OpLabel -%30 = OpLoad %v2float %i_vTextureCoords -%31 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 -%32 = OpLoad %uint %31 -%33 = OpAccessChain %_ptr_UniformConstant_16 %g_tColor %32 -%34 = OpLoad %16 %33 -%35 = OpLoad %24 %g_sAniso -%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 %)" + 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 -)"; - // clang-format on - - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch( - entry + names_annots + consts_types_vars + kImportStub + main_func, true, - 23u); -} - -TEST_F(InstBindlessTest, InstrumentMultipleInstructions) { - // Texture2D g_tColor[128]; - // - // layout(push_constant) cbuffer PerViewConstantBuffer_t - // { - // uint g_nDataIdx; - // uint g_nDataIdx2; - // }; - // - // SamplerState g_sAniso; - // - // struct PS_INPUT - // { - // float2 vTextureCoords : TEXCOORD2; - // }; - // - // struct PS_OUTPUT - // { - // float4 vColor : SV_Target0; - // }; - // - // PS_OUTPUT MainPs(PS_INPUT i) - // { - // PS_OUTPUT ps_output; - // - // float t = g_tColor[g_nDataIdx ].Sample(g_sAniso, i.vTextureCoords.xy); - // float t2 = g_tColor[g_nDataIdx2].Sample(g_sAniso, i.vTextureCoords.xy); - // ps_output.vColor = t + t2; - // return ps_output; - // } - - // clang-format off - const std::string defs = R"( -OpCapability Shader -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 -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 3 -OpDecorate %g_tColor Binding 4 -OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 -OpMemberDecorate %PerViewConstantBuffer_t 1 Offset 4 -OpDecorate %PerViewConstantBuffer_t Block -OpDecorate %g_sAniso DescriptorSet 3 -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 -%int_1 = OpConstant %int 1 -%17 = OpTypeImage %float 2D 0 0 0 1 Unknown -%uint = OpTypeInt 32 0 -%uint_128 = OpConstant %uint 128 -%_arr_17_uint_128 = OpTypeArray %17 %uint_128 -%_ptr_UniformConstant__arr_17_uint_128 = OpTypePointer UniformConstant %_arr_17_uint_128 -%g_tColor = OpVariable %_ptr_UniformConstant__arr_17_uint_128 UniformConstant -%PerViewConstantBuffer_t = OpTypeStruct %uint %uint -%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t -%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant -%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint -%_ptr_UniformConstant_17 = OpTypePointer UniformConstant %17 -%25 = OpTypeSampler -%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25 -%g_sAniso = OpVariable %_ptr_UniformConstant_25 UniformConstant -%27 = OpTypeSampledImage %17 -%_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 -;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 -)"; - - 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 -%33 = OpLoad %uint %32 -%34 = OpAccessChain %_ptr_UniformConstant_17 %g_tColor %33 -%35 = OpLoad %17 %34 -%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 %)" + 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 -%42 = OpLoad %17 %41 -%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 %)" + 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 -)"; - // clang-format on - - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, InstrumentOpImage) { - // This test verifies that the pass will correctly instrument shader - // using OpImage. This test was created by editing the SPIR-V - // from the Simple test. - - // clang-format off - const std::string defs = R"( -OpCapability Shader -OpCapability StorageImageReadWithoutFormat -;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 -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 %i_vTextureCoords "i.vTextureCoords" -OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" -OpDecorate %g_tColor DescriptorSet 3 -OpDecorate %g_tColor Binding 9 -OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 -OpDecorate %PerViewConstantBuffer_t Block -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 -%v4float = OpTypeVector %float 4 -%int = OpTypeInt 32 1 -%v2int = OpTypeVector %int 2 -%int_0 = OpConstant %int 0 -%20 = OpTypeImage %float 2D 0 0 0 0 Unknown -%uint = OpTypeInt 32 0 -%uint_128 = OpConstant %uint 128 -%39 = OpTypeSampledImage %20 -%_arr_39_uint_128 = OpTypeArray %39 %uint_128 -%_ptr_UniformConstant__arr_39_uint_128 = OpTypePointer UniformConstant %_arr_39_uint_128 -%g_tColor = OpVariable %_ptr_UniformConstant__arr_39_uint_128 UniformConstant -%PerViewConstantBuffer_t = OpTypeStruct %uint -%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t -%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant -%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint -%_ptr_UniformConstant_39 = OpTypePointer UniformConstant %39 -%_ptr_Input_v2int = OpTypePointer Input %v2int -%i_vTextureCoords = OpVariable %_ptr_Input_v2int Input -%_ptr_Output_v4float = OpTypePointer Output %v4float -%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -)"; - - const std::string main_func = R"( -%MainPs = OpFunction %void None %3 -%5 = OpLabel -%53 = OpLoad %v2int %i_vTextureCoords -%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 -%64 = OpLoad %uint %63 -%65 = OpAccessChain %_ptr_UniformConstant_39 %g_tColor %64 -%66 = OpLoad %39 %65 -%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 %)" + 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 -)"; - // clang-format on - - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, InstrumentSampledImage) { - // This test verifies that the pass will correctly instrument shader - // using sampled image. This test was created by editing the SPIR-V - // from the Simple test. - - // clang-format off - const std::string defs = R"( -OpCapability Shader -;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 -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 %i_vTextureCoords "i.vTextureCoords" -OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" -OpDecorate %g_tColor DescriptorSet 4 -OpDecorate %g_tColor Binding 11 -OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 -OpDecorate %PerViewConstantBuffer_t Block -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 -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%20 = OpTypeImage %float 2D 0 0 0 1 Unknown -%uint = OpTypeInt 32 0 -%uint_128 = OpConstant %uint 128 -%39 = OpTypeSampledImage %20 -%_arr_39_uint_128 = OpTypeArray %39 %uint_128 -%_ptr_UniformConstant__arr_39_uint_128 = OpTypePointer UniformConstant %_arr_39_uint_128 -%g_tColor = OpVariable %_ptr_UniformConstant__arr_39_uint_128 UniformConstant -%PerViewConstantBuffer_t = OpTypeStruct %uint -%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t -%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant -%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint -%_ptr_UniformConstant_39 = OpTypePointer UniformConstant %39 -%_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 -;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -)"; - - const std::string main_func = R"( -%MainPs = OpFunction %void None %3 -%5 = OpLabel -%53 = OpLoad %v2float %i_vTextureCoords -%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 -%64 = OpLoad %uint %63 -%65 = OpAccessChain %_ptr_UniformConstant_39 %g_tColor %64 -%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 %)" + 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 -)"; - // clang-format on - - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, InstrumentImageWrite) { - // This test verifies that the pass will correctly instrument shader - // doing bindless image write. This test was created by editing the SPIR-V - // from the Simple test. - - // clang-format off - const std::string defs = R"( -OpCapability Shader -OpCapability StorageImageWriteWithoutFormat -;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 -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 %i_vTextureCoords "i.vTextureCoords" -OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" -OpDecorate %g_tColor DescriptorSet 30 -OpDecorate %g_tColor Binding 2 -OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 -OpDecorate %PerViewConstantBuffer_t Block -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 -%int = OpTypeInt 32 1 -%v2int = OpTypeVector %int 2 -%int_0 = OpConstant %int 0 -%20 = OpTypeImage %float 2D 0 0 0 0 Unknown -%uint = OpTypeInt 32 0 -%uint_128 = OpConstant %uint 128 -%80 = OpConstantNull %v4float -%_arr_20_uint_128 = OpTypeArray %20 %uint_128 -%_ptr_UniformConstant__arr_20_uint_128 = OpTypePointer UniformConstant %_arr_20_uint_128 -%g_tColor = OpVariable %_ptr_UniformConstant__arr_20_uint_128 UniformConstant -%PerViewConstantBuffer_t = OpTypeStruct %uint -%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t -%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant -%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint -%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20 -%_ptr_Input_v2int = OpTypePointer Input %v2int -%i_vTextureCoords = OpVariable %_ptr_Input_v2int Input -%_ptr_Output_v4float = OpTypePointer Output %v4float -%_entryPointOutput_vColor = OpVariable %_ptr_Output_v4float Output -;CHECK: %v4uint = OpTypeVector %uint 4 -;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -)"; - - const std::string main_func = R"( -%MainPs = OpFunction %void None %3 -%5 = OpLabel -%53 = OpLoad %v2int %i_vTextureCoords -%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 -%64 = OpLoad %uint %63 -%65 = OpAccessChain %_ptr_UniformConstant_20 %g_tColor %64 -%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 %)" + 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 -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, InstrumentVertexSimple) { - // This test verifies that the pass will correctly instrument shader - // doing bindless image write. This test was created by editing the SPIR-V - // from the Simple test. - - // clang-format off - const std::string defs = R"( -OpCapability Shader -OpCapability Sampled1D -;CHECK: OpCapability Linkage -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Vertex %main "main" %_ %coords2D -OpSource GLSL 450 -OpName %main "main" -OpName %lod "lod" -OpName %coords1D "coords1D" -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 %_ "" -OpName %texSampler1D "texSampler1D" -OpName %foo "foo" -OpMemberName %foo 0 "g_idx" -OpName %__0 "" -OpName %coords2D "coords2D" -)" + 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 -OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance -OpDecorate %gl_PerVertex Block -OpDecorate %texSampler1D DescriptorSet 2 -OpDecorate %texSampler1D Binding 13 -OpMemberDecorate %foo 0 Offset 0 -OpDecorate %foo Block -OpDecorate %__0 DescriptorSet 7 -OpDecorate %__0 Binding 5 -OpDecorate %coords2D Location 0 -%void = OpTypeVoid -%3 = OpTypeFunction %void -%float = OpTypeFloat 32 -%_ptr_Function_float = OpTypePointer Function %float -%float_3 = OpConstant %float 3 -%float_1_78900003 = OpConstant %float 1.78900003 -%v4float = OpTypeVector %float 4 -%uint = OpTypeInt 32 0 -%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 -%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex -%_ = OpVariable %_ptr_Output_gl_PerVertex Output -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%21 = OpTypeImage %float 1D 0 0 0 1 Unknown -%22 = OpTypeSampledImage %21 -%uint_128 = OpConstant %uint 128 -%_arr_22_uint_128 = OpTypeArray %22 %uint_128 -%_ptr_UniformConstant__arr_22_uint_128 = OpTypePointer UniformConstant %_arr_22_uint_128 -%texSampler1D = OpVariable %_ptr_UniformConstant__arr_22_uint_128 UniformConstant -%foo = OpTypeStruct %int -%_ptr_Uniform_foo = OpTypePointer Uniform %foo -%__0 = OpVariable %_ptr_Uniform_foo Uniform -%_ptr_Uniform_int = OpTypePointer Uniform %int -%_ptr_UniformConstant_22 = OpTypePointer UniformConstant %22 -%_ptr_Output_v4float = OpTypePointer Output %v4float -%v2float = OpTypeVector %float 2 -%_ptr_Input_v2float = OpTypePointer Input %v2float -%coords2D = OpVariable %_ptr_Input_v2float 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_v4float:%\w+]] = OpConstantNull %v4float -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%lod = OpVariable %_ptr_Function_float Function -%coords1D = OpVariable %_ptr_Function_float Function -OpStore %lod %float_3 -OpStore %coords1D %float_1_78900003 -%31 = OpAccessChain %_ptr_Uniform_int %__0 %int_0 -%32 = OpLoad %int %31 -%34 = OpAccessChain %_ptr_UniformConstant_22 %texSampler1D %32 -%35 = OpLoad %22 %34 -%36 = OpLoad %float %coords1D -%37 = OpLoad %float %lod -%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 %)" + 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 -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, InstrumentTeseSimple) { - // This test verifies that the pass will correctly instrument tessellation - // evaluation shader doing bindless buffer load. - // - // clang-format off - // - // #version 450 - // #extension GL_EXT_nonuniform_qualifier : enable - // - // layout(std140, set = 9, binding = 1) uniform ufoo { uint index; } uniform_index_buffer; - // - // layout(set = 9, binding = 2) buffer bfoo { vec4 val; } adds[11]; - // - // layout(triangles, equal_spacing, cw) in; - // - // void main() { - // gl_Position = adds[uniform_index_buffer.index].val; - // } - // - - 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 -OpExecutionMode %main Triangles -OpExecutionMode %main SpacingEqual -OpExecutionMode %main VertexOrderCw -OpSource GLSL 450 -OpSourceExtension "GL_EXT_nonuniform_qualifier" -OpName %main "main" -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 %_ "" -OpName %bfoo "bfoo" -OpMemberName %bfoo 0 "val" -OpName %adds "adds" -OpName %ufoo "ufoo" -OpMemberName %ufoo 0 "index" -OpName %uniform_index_buffer "uniform_index_buffer" -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 %bfoo 0 Offset 0 -OpDecorate %bfoo Block -OpDecorate %adds DescriptorSet 9 -OpDecorate %adds Binding 1 -OpMemberDecorate %ufoo 0 Offset 0 -OpDecorate %ufoo Block -OpDecorate %uniform_index_buffer DescriptorSet 9 -OpDecorate %uniform_index_buffer Binding 2 -)" + kImportDeco + R"( -;CHECK: OpDecorate %gl_PrimitiveID BuiltIn PrimitiveId -;CHECK: OpDecorate %gl_TessCoord BuiltIn TessCoord -%void = OpTypeVoid -%3 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v4float = OpTypeVector %float 4 -%uint = OpTypeInt 32 0 -%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 -%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex -%_ = OpVariable %_ptr_Output_gl_PerVertex Output -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%bfoo = OpTypeStruct %v4float -%uint_11 = OpConstant %uint 11 -%_arr_bfoo_uint_11 = OpTypeArray %bfoo %uint_11 -%_ptr_StorageBuffer__arr_bfoo_uint_11 = OpTypePointer StorageBuffer %_arr_bfoo_uint_11 -%adds = OpVariable %_ptr_StorageBuffer__arr_bfoo_uint_11 StorageBuffer -%ufoo = OpTypeStruct %uint -%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo -%uniform_index_buffer = OpVariable %_ptr_Uniform_ufoo Uniform -%_ptr_Uniform_uint = OpTypePointer Uniform %uint -%_ptr_StorageBuffer_v4float = OpTypePointer StorageBuffer %v4float -%_ptr_Output_v4float = OpTypePointer Output %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 -)"; - - 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 %)" + 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 %)" + 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 -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, InstrumentTesc) { - // This test verifies that the pass will correctly instrument tessellation - // control shader - // - // clang-format off - // - // #version 450 - // layout(vertices = 3) out; - // layout(set = 0, binding = 0) uniform texture1D _77; - // layout(set = 0, binding = 1) uniform sampler _78; - - // layout(location = 1) flat in int _3[]; - // layout(location = 0) out vec4 _5[3]; - - // void main() - // { - // float param; - // if (_3[gl_InvocationID] == 0) - // { - // param = 0.0234375; - // } - // else - // { - // param = 1.0156199932098388671875; - // } - // _5[gl_InvocationID] = textureLod(sampler1D(_77, _78), param, 0.0); - // vec4 _203; - // if (gl_InvocationID == 0) - // { - // _203 = gl_in[0].gl_Position; - // } - // else - // { - // _203 = gl_in[2].gl_Position; - // } - // gl_out[gl_InvocationID].gl_Position = _203; - // gl_TessLevelInner[0] = 2.7999999523162841796875; - // gl_TessLevelInner[1] = 2.7999999523162841796875; - // gl_TessLevelOuter[0] = 2.7999999523162841796875; - // gl_TessLevelOuter[1] = 2.7999999523162841796875; - // gl_TessLevelOuter[2] = 2.7999999523162841796875; - // gl_TessLevelOuter[3] = 2.7999999523162841796875; - // } - // - // clang-format on - // - // - - // clang-format off - const std::string defs = R"( -OpCapability Tessellation -OpCapability Sampled1D -;CHECK: OpCapability Linkage -;CHECK: OpExtension "SPV_KHR_storage_buffer_storage_class" -;CHECK: OpExtension "SPV_KHR_physical_storage_buffer" -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -;CHECK: OpMemoryModel PhysicalStorageBuffer64 GLSL450 -OpEntryPoint TessellationControl %main "main" %_3 %gl_InvocationID %_5 %gl_in %gl_out %gl_TessLevelInner %gl_TessLevelOuter -;CHECK: OpEntryPoint TessellationControl %main "main" %_3 %gl_InvocationID %_5 %gl_in %gl_out %gl_TessLevelInner %gl_TessLevelOuter %gl_PrimitiveID -OpExecutionMode %main OutputVertices 3 -OpSource GLSL 450 -OpName %main "main" -OpName %_3 "_3" -OpName %gl_InvocationID "gl_InvocationID" -OpName %param "param" -OpName %_5 "_5" -OpName %_77 "_77" -OpName %_78 "_78" -OpName %_203 "_203" -OpName %gl_PerVertex "gl_PerVertex" -OpMemberName %gl_PerVertex 0 "gl_Position" -OpMemberName %gl_PerVertex 1 "gl_PointSize" -OpMemberName %gl_PerVertex 2 "gl_ClipDistance" -OpMemberName %gl_PerVertex 3 "gl_CullDistance" -OpName %gl_in "gl_in" -OpName %gl_PerVertex_0 "gl_PerVertex" -OpMemberName %gl_PerVertex_0 0 "gl_Position" -OpMemberName %gl_PerVertex_0 1 "gl_PointSize" -OpMemberName %gl_PerVertex_0 2 "gl_ClipDistance" -OpMemberName %gl_PerVertex_0 3 "gl_CullDistance" -OpName %gl_out "gl_out" -OpName %gl_TessLevelInner "gl_TessLevelInner" -OpName %gl_TessLevelOuter "gl_TessLevelOuter" -OpDecorate %_3 Flat -OpDecorate %_3 Location 1 -OpDecorate %gl_InvocationID BuiltIn InvocationId -OpDecorate %_5 Location 0 -OpDecorate %_77 DescriptorSet 0 -OpDecorate %_77 Binding 0 -OpDecorate %_78 DescriptorSet 0 -OpDecorate %_78 Binding 1 -OpMemberDecorate %gl_PerVertex 0 BuiltIn Position -OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize -OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance -OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance -OpDecorate %gl_PerVertex Block -OpMemberDecorate %gl_PerVertex_0 0 BuiltIn Position -OpMemberDecorate %gl_PerVertex_0 1 BuiltIn PointSize -OpMemberDecorate %gl_PerVertex_0 2 BuiltIn ClipDistance -OpMemberDecorate %gl_PerVertex_0 3 BuiltIn CullDistance -OpDecorate %gl_PerVertex_0 Block -OpDecorate %gl_TessLevelInner Patch -OpDecorate %gl_TessLevelInner BuiltIn TessLevelInner -OpDecorate %gl_TessLevelOuter Patch -OpDecorate %gl_TessLevelOuter BuiltIn TessLevelOuter -%void = OpTypeVoid -%3 = OpTypeFunction %void -%int = OpTypeInt 32 1 -%uint = OpTypeInt 32 0 -%uint_32 = OpConstant %uint 32 -%_arr_int_uint_32 = OpTypeArray %int %uint_32 -%_ptr_Input__arr_int_uint_32 = OpTypePointer Input %_arr_int_uint_32 -%_3 = OpVariable %_ptr_Input__arr_int_uint_32 Input -%_ptr_Input_int = OpTypePointer Input %int -%gl_InvocationID = OpVariable %_ptr_Input_int Input -%int_0 = OpConstant %int 0 -%bool = OpTypeBool -%float = OpTypeFloat 32 -%_ptr_Function_float = OpTypePointer Function %float -%float_0_0234375 = OpConstant %float 0.0234375 -%float_1_01561999 = OpConstant %float 1.01561999 -%v4float = OpTypeVector %float 4 -%uint_3 = OpConstant %uint 3 -%_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3 -%_ptr_Output__arr_v4float_uint_3 = OpTypePointer Output %_arr_v4float_uint_3 -%_5 = OpVariable %_ptr_Output__arr_v4float_uint_3 Output -%34 = OpTypeImage %float 1D 0 0 0 1 Unknown -%_ptr_UniformConstant_34 = OpTypePointer UniformConstant %34 -%_77 = OpVariable %_ptr_UniformConstant_34 UniformConstant -%38 = OpTypeSampler -%_ptr_UniformConstant_38 = OpTypePointer UniformConstant %38 -%_78 = OpVariable %_ptr_UniformConstant_38 UniformConstant -%42 = OpTypeSampledImage %34 -%float_0 = OpConstant %float 0 -%_ptr_Output_v4float = OpTypePointer Output %v4float -%_ptr_Function_v4float = OpTypePointer Function %v4float -%uint_1 = OpConstant %uint 1 -%_arr_float_uint_1 = OpTypeArray %float %uint_1 -%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1 -%_arr_gl_PerVertex_uint_32 = OpTypeArray %gl_PerVertex %uint_32 -%_ptr_Input__arr_gl_PerVertex_uint_32 = OpTypePointer Input %_arr_gl_PerVertex_uint_32 -%gl_in = OpVariable %_ptr_Input__arr_gl_PerVertex_uint_32 Input -%_ptr_Input_v4float = OpTypePointer Input %v4float -%int_2 = OpConstant %int 2 -%gl_PerVertex_0 = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1 -%_arr_gl_PerVertex_0_uint_3 = OpTypeArray %gl_PerVertex_0 %uint_3 -%_ptr_Output__arr_gl_PerVertex_0_uint_3 = OpTypePointer Output %_arr_gl_PerVertex_0_uint_3 -%gl_out = OpVariable %_ptr_Output__arr_gl_PerVertex_0_uint_3 Output -%uint_2 = OpConstant %uint 2 -%_arr_float_uint_2 = OpTypeArray %float %uint_2 -%_ptr_Output__arr_float_uint_2 = OpTypePointer Output %_arr_float_uint_2 -%gl_TessLevelInner = OpVariable %_ptr_Output__arr_float_uint_2 Output -%float_2_79999995 = OpConstant %float 2.79999995 -%_ptr_Output_float = OpTypePointer Output %float -%int_1 = OpConstant %int 1 -%uint_4 = OpConstant %uint 4 -%_arr_float_uint_4 = OpTypeArray %float %uint_4 -%_ptr_Output__arr_float_uint_4 = OpTypePointer Output %_arr_float_uint_4 -%gl_TessLevelOuter = OpVariable %_ptr_Output__arr_float_uint_4 Output -%int_3 = OpConstant %int 3 -)"; - - const std::string main_func = - R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%param = OpVariable %_ptr_Function_float Function -%_203 = OpVariable %_ptr_Function_v4float Function -%14 = OpLoad %int %gl_InvocationID -%15 = OpAccessChain %_ptr_Input_int %_3 %14 -%16 = OpLoad %int %15 -%19 = OpIEqual %bool %16 %int_0 -OpSelectionMerge %21 None -OpBranchConditional %19 %20 %26 -%20 = OpLabel -;CHECK-NOT: %15 = OpAccessChain %_ptr_Input_int %_3 %14 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpLoad %int %gl_InvocationID -;CHECK: {{%\w+}} = OpAccessChain %_ptr_Input_int %_3 {{%\w+}} -;CHECK: {{%\w+}} = OpLoad %int {{%\w+}} -;CHECK: {{%\w+}} = OpIEqual %bool {{%\w+}} %int_0 -;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -OpStore %param %float_0_0234375 -OpBranch %21 -%26 = OpLabel -OpStore %param %float_1_01561999 -OpBranch %21 -%21 = OpLabel -%33 = OpLoad %int %gl_InvocationID -%37 = OpLoad %34 %_77 -%41 = OpLoad %38 %_78 -%43 = OpSampledImage %42 %37 %41 -%44 = OpLoad %float %param -;CHECK: {{%\w+}} = OpLoad %int %gl_InvocationID -;CHECK: {{%\w+}} = OpBitcast %uint {{%\w+}} -;CHECK: {{%\w+}} = OpLoad %uint %gl_PrimitiveID -;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_1 {{%\w+}} {{%\w+}} %uint_0 -;CHECK: {{%\w+}} = OpFunctionCall %bool %inst_bindless_check_desc %uint_23 %uint_129 {{%\w+}} %uint_0 %uint_0 %uint_0 %uint_0 -;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -%46 = OpImageSampleExplicitLod %v4float %43 %44 Lod %float_0 -%48 = OpAccessChain %_ptr_Output_v4float %_5 %33 -OpStore %48 %46 -;CHECK-NOT: %48 = OpAccessChain %_ptr_Output_v4float %_5 %33 -;CHECK-NOT: OpStore %48 %46 -;CHECK: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: [[access_chain:%\w+]] = OpAccessChain %_ptr_Output_v4float %_5 {{%\w+}} -;CHECK: OpStore [[access_chain]] [[phi_result]] -%49 = OpLoad %int %gl_InvocationID -%50 = OpIEqual %bool %49 %int_0 -OpSelectionMerge %52 None -OpBranchConditional %50 %51 %64 -%51 = OpLabel -%62 = OpAccessChain %_ptr_Input_v4float %gl_in %int_0 %int_0 -%63 = OpLoad %v4float %62 -OpStore %_203 %63 -OpBranch %52 -%64 = OpLabel -%66 = OpAccessChain %_ptr_Input_v4float %gl_in %int_2 %int_0 -%67 = OpLoad %v4float %66 -OpStore %_203 %67 -OpBranch %52 -%52 = OpLabel -%72 = OpLoad %int %gl_InvocationID -%73 = OpLoad %v4float %_203 -%74 = OpAccessChain %_ptr_Output_v4float %gl_out %72 %int_0 -OpStore %74 %73 -%81 = OpAccessChain %_ptr_Output_float %gl_TessLevelInner %int_0 -OpStore %81 %float_2_79999995 -%83 = OpAccessChain %_ptr_Output_float %gl_TessLevelInner %int_1 -OpStore %83 %float_2_79999995 -%88 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_0 -OpStore %88 %float_2_79999995 -%89 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_1 -OpStore %89 %float_2_79999995 -%90 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_2 -OpStore %90 %float_2_79999995 -%92 = OpAccessChain %_ptr_Output_float %gl_TessLevelOuter %int_3 -OpStore %92 %float_2_79999995 -OpReturn -OpFunctionEnd -)"; - // clang-format on - - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, MultipleDebugFunctions) { - // 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. - - // clang-format off - const std::string defs = R"( -OpCapability Shader -;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 -OpExecutionMode %MainPs OriginUpperLeft -%1 = OpString "foo5.frag" -OpSource HLSL 500 %1 -OpName %MainPs "MainPs" -OpName %PS_INPUT "PS_INPUT" -OpMemberName %PS_INPUT 0 "vTextureCoords" -OpName %PS_OUTPUT "PS_OUTPUT" -OpMemberName %PS_OUTPUT 0 "vColor" -OpName %_MainPs_struct_PS_INPUT_vf21_ "@MainPs(struct-PS_INPUT-vf21;" -OpName %i "i" -OpName %ps_output "ps_output" -OpName %g_tColor "g_tColor" -OpName %PerViewConstantBuffer_t "PerViewConstantBuffer_t" -OpMemberName %PerViewConstantBuffer_t 0 "g_nDataIdx" -OpName %_ "" -OpName %g_sAniso "g_sAniso" -OpName %i_0 "i" -OpName %i_vTextureCoords "i.vTextureCoords" -OpName %_entryPointOutput_vColor "@entryPointOutput.vColor" -OpName %param "param" -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 3 -OpDecorate %i_vTextureCoords Location 0 -OpDecorate %_entryPointOutput_vColor Location 0 -)" + kImportDeco + R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -%void = OpTypeVoid -%4 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v2float = OpTypeVector %float 2 -%PS_INPUT = OpTypeStruct %v2float -%_ptr_Function_PS_INPUT = OpTypePointer Function %PS_INPUT -%v4float = OpTypeVector %float 4 -%PS_OUTPUT = OpTypeStruct %v4float -%13 = OpTypeFunction %PS_OUTPUT %_ptr_Function_PS_INPUT -%_ptr_Function_PS_OUTPUT = OpTypePointer Function %PS_OUTPUT -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%21 = OpTypeImage %float 2D 0 0 0 1 Unknown -%uint = OpTypeInt 32 0 -%uint_128 = OpConstant %uint 128 -%_arr_21_uint_128 = OpTypeArray %21 %uint_128 -%_ptr_UniformConstant__arr_21_uint_128 = OpTypePointer UniformConstant %_arr_21_uint_128 -%g_tColor = OpVariable %_ptr_UniformConstant__arr_21_uint_128 UniformConstant -%PerViewConstantBuffer_t = OpTypeStruct %uint -%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t -%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant -%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint -%_ptr_UniformConstant_21 = OpTypePointer UniformConstant %21 -%36 = OpTypeSampler -%_ptr_UniformConstant_36 = OpTypePointer UniformConstant %36 -%g_sAniso = OpVariable %_ptr_UniformConstant_36 UniformConstant -%40 = OpTypeSampledImage %21 -%_ptr_Function_v2float = OpTypePointer Function %v2float -%_ptr_Function_v4float = OpTypePointer Function %v4float -%_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 -;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -)"; - - const std::string func1 = R"( -%MainPs = OpFunction %void None %4 -%6 = OpLabel -%i_0 = OpVariable %_ptr_Function_PS_INPUT Function -%param = OpVariable %_ptr_Function_PS_INPUT Function -OpLine %1 21 0 -%54 = OpLoad %v2float %i_vTextureCoords -%55 = OpAccessChain %_ptr_Function_v2float %i_0 %int_0 -OpStore %55 %54 -%59 = OpLoad %PS_INPUT %i_0 -OpStore %param %59 -%60 = OpFunctionCall %PS_OUTPUT %_MainPs_struct_PS_INPUT_vf21_ %param -%61 = OpCompositeExtract %v4float %60 0 -OpStore %_entryPointOutput_vColor %61 -OpReturn -OpFunctionEnd -)"; - - const std::string func2 = R"( -%_MainPs_struct_PS_INPUT_vf21_ = OpFunction %PS_OUTPUT None %13 -%i = OpFunctionParameter %_ptr_Function_PS_INPUT -%16 = OpLabel -%ps_output = OpVariable %_ptr_Function_PS_OUTPUT Function -OpLine %1 24 0 -%31 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 -%32 = OpLoad %uint %31 -%34 = OpAccessChain %_ptr_UniformConstant_21 %g_tColor %32 -%35 = OpLoad %21 %34 -%39 = OpLoad %36 %g_sAniso -%41 = OpSampledImage %40 %35 %39 -%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 %)" + 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]] -OpLine %1 25 0 -%48 = OpLoad %PS_OUTPUT %ps_output -OpReturnValue %48 -OpFunctionEnd -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch( - defs + kImportStub + func1 + func2, true, 23u); -} - -TEST_F(InstBindlessTest, RuntimeArray) { - // This test verifies that the pass will correctly instrument shader - // with runtime descriptor array. This test was created by editing the - // SPIR-V from the Simple test. - - // clang-format off - const std::string defs = R"( -OpCapability Shader -OpCapability RuntimeDescriptorArray -;CHECK: OpCapability Linkage -OpExtension "SPV_EXT_descriptor_indexing" -%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 -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 3 -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 -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%20 = OpTypeImage %float 2D 0 0 0 1 Unknown -%uint = OpTypeInt 32 0 -%uint_1 = OpConstant %uint 1 -%_rarr_20 = OpTypeRuntimeArray %20 -%_ptr_UniformConstant__arr_20 = OpTypePointer UniformConstant %_rarr_20 -%g_tColor = OpVariable %_ptr_UniformConstant__arr_20 UniformConstant -%PerViewConstantBuffer_t = OpTypeStruct %uint -%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t -%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant -%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint -%_ptr_UniformConstant_20 = OpTypePointer UniformConstant %20 -%35 = OpTypeSampler -%_ptr_UniformConstant_35 = OpTypePointer UniformConstant %35 -%g_sAniso = OpVariable %_ptr_UniformConstant_35 UniformConstant -%39 = OpTypeSampledImage %20 -%_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 -;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -)"; - - const std::string main_func = R"( -%MainPs = OpFunction %void None %3 -%5 = OpLabel -%53 = OpLoad %v2float %i_vTextureCoords -%63 = OpAccessChain %_ptr_PushConstant_uint %_ %int_0 -%64 = OpLoad %uint %63 -%65 = OpAccessChain %_ptr_UniformConstant_20 %g_tColor %64 -%66 = OpLoad %20 %65 -%67 = OpLoad %35 %g_sAniso -%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 %)" + 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 -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, InstrumentInitCheckOnScalarDescriptor) { - // This test verifies that the pass will correctly instrument vanilla - // texture sample on a scalar descriptor with an initialization check if the - // input_init_enable argument is set to true. This can happen when the - // descriptor indexing extension is enabled in the API but the SPIR-V - // does not have the extension enabled because it does not contain a - // runtime array. This is the same shader as NoInstrumentNonBindless. - - // clang-format off - const std::string defs = R"( -OpCapability Shader -;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 -OpExecutionMode %MainPs OriginUpperLeft -OpSource HLSL 500 -OpName %MainPs "MainPs" -OpName %g_tColor "g_tColor" -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 -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 -%8 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v2float = OpTypeVector %float 2 -%v4float = OpTypeVector %float 4 -%12 = OpTypeImage %float 2D 0 0 0 1 Unknown -%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12 -%g_tColor = OpVariable %_ptr_UniformConstant_12 UniformConstant -%14 = OpTypeSampler -%_ptr_UniformConstant_14 = OpTypePointer UniformConstant %14 -%g_sAniso = OpVariable %_ptr_UniformConstant_14 UniformConstant -%16 = OpTypeSampledImage %12 -%_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 -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -)"; - - const std::string main_func = R"( -%MainPs = OpFunction %void None %8 -%19 = OpLabel -%20 = OpLoad %v2float %i_vTextureCoords -%21 = OpLoad %12 %g_tColor -%22 = OpLoad %14 %g_sAniso -%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 %)" + 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 -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, SPV14AddToEntryPoint) { - const std::string text = R"( -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 -OpDecorate %sampler_var DescriptorSet 4 -OpDecorate %sampler_var Binding 2 -OpDecorate %gid DescriptorSet 0 -OpDecorate %gid Binding 2 -OpDecorate %struct Block -OpMemberDecorate %struct 0 Offset 0 -%void = OpTypeVoid -%int = OpTypeInt 32 0 -%int_0 = OpConstant %int 0 -%v3int = OpTypeVector %int 3 -%float = OpTypeFloat 32 -%v3float = OpTypeVector %float 3 -%v4float = OpTypeVector %float 4 -%struct = OpTypeStruct %v3int -%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct -%ptr_ssbo_v3int = OpTypePointer StorageBuffer %v3int -%gid = OpVariable %ptr_ssbo_struct StorageBuffer -%image = OpTypeImage %float 3D 0 0 0 1 Unknown -%ptr_uc_image = OpTypePointer UniformConstant %image -%sampler = OpTypeSampler -%ptr_uc_sampler = OpTypePointer UniformConstant %sampler -%image_var = OpVariable %ptr_uc_image UniformConstant -%sampler_var = OpVariable %ptr_uc_sampler UniformConstant -%sampled = OpTypeSampledImage %image -%void_fn = OpTypeFunction %void -%foo = OpFunction %void None %void_fn -%entry = OpLabel -%ld_image = OpLoad %image %image_var -%ld_sampler = OpLoad %sampler %sampler_var -%gep = OpAccessChain %ptr_ssbo_v3int %gid %int_0 -%ld_gid = OpLoad %v3int %gep -%convert = OpConvertUToF %v3float %ld_gid -%sampled_image = OpSampledImage %sampled %ld_image %ld_sampler -%sample = OpImageSampleImplicitLod %v4float %sampled_image %convert -OpReturn -OpFunctionEnd -)"; - - SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4); - SinglePassRunAndMatch(text, true, 23u); -} - -TEST_F(InstBindlessTest, SPV14AddToEntryPoints) { - const std::string text = R"( -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 -OpDecorate %sampler_var DescriptorSet 3 -OpDecorate %sampler_var Binding 3 -OpDecorate %gid DescriptorSet 3 -OpDecorate %gid Binding 4 -OpDecorate %struct Block -OpMemberDecorate %struct 0 Offset 0 -%void = OpTypeVoid -%int = OpTypeInt 32 0 -%int_0 = OpConstant %int 0 -%v3int = OpTypeVector %int 3 -%float = OpTypeFloat 32 -%v3float = OpTypeVector %float 3 -%v4float = OpTypeVector %float 4 -%struct = OpTypeStruct %v3int -%ptr_ssbo_struct = OpTypePointer StorageBuffer %struct -%ptr_ssbo_v3int = OpTypePointer StorageBuffer %v3int -%gid = OpVariable %ptr_ssbo_struct StorageBuffer -%image = OpTypeImage %float 3D 0 0 0 1 Unknown -%ptr_uc_image = OpTypePointer UniformConstant %image -%sampler = OpTypeSampler -%ptr_uc_sampler = OpTypePointer UniformConstant %sampler -%image_var = OpVariable %ptr_uc_image UniformConstant -%sampler_var = OpVariable %ptr_uc_sampler UniformConstant -%sampled = OpTypeSampledImage %image -%void_fn = OpTypeFunction %void -%foo = OpFunction %void None %void_fn -%entry = OpLabel -%ld_image = OpLoad %image %image_var -%ld_sampler = OpLoad %sampler %sampler_var -%gep = OpAccessChain %ptr_ssbo_v3int %gid %int_0 -%ld_gid = OpLoad %v3int %gep -%convert = OpConvertUToF %v3float %ld_gid -%sampled_image = OpSampledImage %sampled %ld_image %ld_sampler -%sample = OpImageSampleImplicitLod %v4float %sampled_image %convert -OpReturn -OpFunctionEnd -)"; - - SetTargetEnv(SPV_ENV_VULKAN_1_1_SPIRV_1_4); - SinglePassRunAndMatch(text, true, 23u); -} - -TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedUBOArray) { - // #version 450 - // #extension GL_EXT_nonuniform_qualifier : enable - // - // layout(location=0) in nonuniformEXT flat int nu_ii; - // layout(location=0) out float b; - // - // layout(set = 6, binding=3) uniform uname { float a; } uniformBuffer[]; - // - // void main() - // { - // b = uniformBuffer[nu_ii].a; - // } - - // clang-format off - const std::string defs = R"( -OpCapability Shader -OpCapability ShaderNonUniform -OpCapability RuntimeDescriptorArray -OpCapability UniformBufferArrayNonUniformIndexing -;CHECK: OpCapability Linkage -OpExtension "SPV_EXT_descriptor_indexing" -%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 -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 450 -OpSourceExtension "GL_EXT_nonuniform_qualifier" -OpName %main "main" -OpName %b "b" -OpName %uname "uname" -OpMemberName %uname 0 "a" -OpName %uniformBuffer "uniformBuffer" -OpName %nu_ii "nu_ii" -OpDecorate %b Location 0 -OpMemberDecorate %uname 0 Offset 0 -OpDecorate %uname Block -OpDecorate %uniformBuffer DescriptorSet 6 -OpDecorate %uniformBuffer Binding 3 -OpDecorate %nu_ii Flat -OpDecorate %nu_ii Location 0 -OpDecorate %nu_ii NonUniform -OpDecorate %16 NonUniform -OpDecorate %20 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 -%_ptr_Output_float = OpTypePointer Output %float -%b = OpVariable %_ptr_Output_float Output -%uname = OpTypeStruct %float -%_runtimearr_uname = OpTypeRuntimeArray %uname -%_ptr_Uniform__runtimearr_uname = OpTypePointer Uniform %_runtimearr_uname -%uniformBuffer = OpVariable %_ptr_Uniform__runtimearr_uname Uniform -%int = OpTypeInt 32 1 -%_ptr_Input_int = OpTypePointer Input %int -%nu_ii = OpVariable %_ptr_Input_int Input -%int_0 = OpConstant %int 0 -%_ptr_Uniform_float = OpTypePointer Uniform %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 -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%16 = OpLoad %int %nu_ii -%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 %)" + 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 -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArrayDeprecated) { - // #version 450 - // #extension GL_EXT_nonuniform_qualifier : enable - // - // layout(location=0) in nonuniformEXT flat int nu_ii; - // layout(location=0) out float b; - // - // layout(set = 7, binding=3) buffer bname { float b; } storageBuffer[]; - // - // void main() - // { - // b = storageBuffer[nu_ii].b; - // } - - // clang-format off - const std::string defs = R"( -OpCapability Shader -OpCapability ShaderNonUniform -OpCapability RuntimeDescriptorArray -OpCapability StorageBufferArrayNonUniformIndexing -;CHECK: OpCapability Linkage -OpExtension "SPV_EXT_descriptor_indexing" -%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 -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 450 -OpSourceExtension "GL_EXT_nonuniform_qualifier" -OpName %main "main" -OpName %b "b" -OpName %bname "bname" -OpMemberName %bname 0 "a" -OpName %storageBuffer "storageBuffer" -OpName %nu_ii "nu_ii" -OpDecorate %b Location 0 -OpMemberDecorate %bname 0 Offset 0 -OpDecorate %bname Block -OpDecorate %storageBuffer DescriptorSet 7 -OpDecorate %storageBuffer Binding 3 -OpDecorate %nu_ii Flat -OpDecorate %nu_ii Location 0 -OpDecorate %nu_ii NonUniform -OpDecorate %16 NonUniform -OpDecorate %20 NonUniform -)" + kImportDeco + R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -%void = OpTypeVoid -%3 = OpTypeFunction %void -%float = OpTypeFloat 32 -%_ptr_Output_float = OpTypePointer Output %float -%b = OpVariable %_ptr_Output_float Output -%bname = OpTypeStruct %float -%_runtimearr_bname = OpTypeRuntimeArray %bname -%_ptr_StorageBuffer__runtimearr_bname = OpTypePointer StorageBuffer %_runtimearr_bname -%storageBuffer = OpVariable %_ptr_StorageBuffer__runtimearr_bname StorageBuffer -%int = OpTypeInt 32 1 -%_ptr_Input_int = OpTypePointer Input %int -%nu_ii = OpVariable %_ptr_Input_int Input -%int_0 = OpConstant %int 0 -%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %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 -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%16 = OpLoad %int %nu_ii -%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 %)" + 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 -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, InstBoundsAndInitLoadUnsizedSSBOArray) { - // Same as Deprecated but declaring as StorageBuffer Block - - // clang-format off - const std::string defs = R"( -OpCapability Shader -OpCapability ShaderNonUniform -OpCapability RuntimeDescriptorArray -OpCapability StorageBufferArrayNonUniformIndexing -;CHECK: OpCapability Linkage -OpExtension "SPV_EXT_descriptor_indexing" -%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 -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 450 -OpSourceExtension "GL_EXT_nonuniform_qualifier" -OpName %main "main" -OpName %b "b" -OpName %bname "bname" -OpMemberName %bname 0 "a" -OpName %storageBuffer "storageBuffer" -OpName %nu_ii "nu_ii" -OpDecorate %b Location 0 -OpMemberDecorate %bname 0 Offset 0 -OpDecorate %bname Block -OpDecorate %storageBuffer DescriptorSet 0 -OpDecorate %storageBuffer Binding 3 -OpDecorate %nu_ii Flat -OpDecorate %nu_ii Location 0 -OpDecorate %nu_ii NonUniform -OpDecorate %16 NonUniform -OpDecorate %20 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 -%_ptr_Output_float = OpTypePointer Output %float -%b = OpVariable %_ptr_Output_float Output -%bname = OpTypeStruct %float -%_runtimearr_bname = OpTypeRuntimeArray %bname -%_ptr_StorageBuffer__runtimearr_bname = OpTypePointer StorageBuffer %_runtimearr_bname -%storageBuffer = OpVariable %_ptr_StorageBuffer__runtimearr_bname StorageBuffer -%int = OpTypeInt 32 1 -%_ptr_Input_int = OpTypePointer Input %int -%nu_ii = OpVariable %_ptr_Input_int Input -%int_0 = OpConstant %int 0 -%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %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 -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%16 = OpLoad %int %nu_ii -%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 %)" + 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 -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, InstInitLoadUBOScalar) { - // #version 450 - // #extension GL_EXT_nonuniform_qualifier : enable - // - // layout(location=0) out float b; - // layout(set=7, binding=3) uniform uname { float a; } uniformBuffer; - // - // void main() - // { - // b = uniformBuffer.a; - // } - - // clang-format off - const std::string defs = R"( -OpCapability Shader -;CHECK: OpCapability Linkage -OpExtension "SPV_EXT_descriptor_indexing" -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %b -;CHECK: OpEntryPoint Fragment %main "main" %b %gl_FragCoord -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 450 -OpSourceExtension "GL_EXT_nonuniform_qualifier" -OpName %main "main" -OpName %b "b" -OpName %uname "uname" -OpMemberName %uname 0 "a" -OpName %uniformBuffer "uniformBuffer" -OpDecorate %b Location 0 -OpMemberDecorate %uname 0 Offset 0 -OpDecorate %uname Block -OpDecorate %uniformBuffer DescriptorSet 7 -OpDecorate %uniformBuffer Binding 3 -)" + kImportDeco + R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -%void = OpTypeVoid -%3 = OpTypeFunction %void -%float = OpTypeFloat 32 -%_ptr_Output_float = OpTypePointer Output %float -%b = OpVariable %_ptr_Output_float Output -%uname = OpTypeStruct %float -%_ptr_Uniform_uname = OpTypePointer Uniform %uname -%uniformBuffer = OpVariable %_ptr_Uniform_uname Uniform -%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: %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 -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%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 %)" + 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 -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, InstBoundsInitStoreUnsizedSSBOArray) { - // #version 450 - // #extension GL_EXT_nonuniform_qualifier : enable - // - // layout(location=0) in nonuniformEXT flat int nu_ii; - // layout(location=1) in float b; - // - // layout(set=5, binding=4) buffer bname { float b; } storageBuffer[]; - // - // void main() - // { - // storageBuffer[nu_ii].b = b; - // } - - // clang-format off - const std::string defs = R"(OpCapability Shader -OpCapability ShaderNonUniform -OpCapability RuntimeDescriptorArray -OpCapability StorageBufferArrayNonUniformIndexing -;CHECK: OpCapability Linkage -OpExtension "SPV_EXT_descriptor_indexing" -%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 -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 450 -OpSourceExtension "GL_EXT_nonuniform_qualifier" -OpName %main "main" -OpName %bname "bname" -OpMemberName %bname 0 "b" -OpName %storageBuffer "storageBuffer" -OpName %nu_ii "nu_ii" -OpName %b "b" -OpMemberDecorate %bname 0 Offset 0 -OpDecorate %bname BufferBlock -OpDecorate %storageBuffer DescriptorSet 5 -OpDecorate %storageBuffer Binding 4 -OpDecorate %nu_ii Flat -OpDecorate %nu_ii Location 0 -OpDecorate %nu_ii NonUniform -OpDecorate %14 NonUniform -OpDecorate %b Location 1 -)" + kImportDeco + R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -%void = OpTypeVoid -%3 = OpTypeFunction %void -%float = OpTypeFloat 32 -%bname = OpTypeStruct %float -%_runtimearr_bname = OpTypeRuntimeArray %bname -%_ptr_Uniform__runtimearr_bname = OpTypePointer Uniform %_runtimearr_bname -%storageBuffer = OpVariable %_ptr_Uniform__runtimearr_bname Uniform -%int = OpTypeInt 32 1 -%_ptr_Input_int = OpTypePointer Input %int -%nu_ii = OpVariable %_ptr_Input_int Input -%int_0 = OpConstant %int 0 -%_ptr_Input_float = OpTypePointer Input %float -%b = OpVariable %_ptr_Input_float Input -%_ptr_Uniform_float = OpTypePointer Uniform %float -;CHECK: %v4uint = OpTypeVector %uint 4 -;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%14 = OpLoad %int %nu_ii -%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 %)" + 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 -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, InstBoundsInitLoadSizedUBOArray) { - // #version 450 - // #extension GL_EXT_nonuniform_qualifier : enable - // - // layout(location=0) in nonuniformEXT flat int nu_ii; - // layout(location=0) out float b; - // - // layout(set=1, binding=3) uniform uname { float a; } uniformBuffer[128]; - // - // void main() - // { - // b = uniformBuffer[nu_ii].a; - // } - - // clang-format off - const std::string defs = R"( -OpCapability Shader -OpCapability ShaderNonUniform -OpCapability UniformBufferArrayNonUniformIndexing -;CHECK: OpCapability Linkage -OpExtension "SPV_EXT_descriptor_indexing" -%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 -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 450 -OpSourceExtension "GL_EXT_nonuniform_qualifier" -OpName %main "main" -OpName %b "b" -OpName %uname "uname" -OpMemberName %uname 0 "a" -OpName %uniformBuffer "uniformBuffer" -OpName %nu_ii "nu_ii" -OpDecorate %b Location 0 -OpMemberDecorate %uname 0 Offset 0 -OpDecorate %uname Block -OpDecorate %uniformBuffer DescriptorSet 1 -OpDecorate %uniformBuffer Binding 3 -OpDecorate %nu_ii Flat -OpDecorate %nu_ii Location 0 -OpDecorate %nu_ii NonUniform -OpDecorate %18 NonUniform -OpDecorate %22 NonUniform -)" + kImportDeco + R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -;CHECK: OpDecorate [[load_result:%\w+]] NonUniform -%void = OpTypeVoid -%3 = OpTypeFunction %void -%float = OpTypeFloat 32 -%_ptr_Output_float = OpTypePointer Output %float -%b = OpVariable %_ptr_Output_float Output -%uname = OpTypeStruct %float -%uint = OpTypeInt 32 0 -%uint_128 = OpConstant %uint 128 -%_arr_uname_uint_128 = OpTypeArray %uname %uint_128 -%_ptr_Uniform__arr_uname_uint_128 = OpTypePointer Uniform %_arr_uname_uint_128 -%uniformBuffer = OpVariable %_ptr_Uniform__arr_uname_uint_128 Uniform -%int = OpTypeInt 32 1 -%_ptr_Input_int = OpTypePointer Input %int -%nu_ii = OpVariable %_ptr_Input_int Input -%int_0 = OpConstant %int 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -;CHECK: %_ptr_Input_v4float = OpTypePointer Input %v4float -;CHECK: %gl_FragCoord = OpVariable %_ptr_Input_v4float Input -;CHECK: [[null_float:%\w+]] = OpConstantNull %float -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%18 = OpLoad %int %nu_ii -%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 %)" + 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 -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, - InstBoundsComputeShaderInitLoadVariableSizedSampledImagesArray) { - // #version 450 - // #extension GL_EXT_nonuniform_qualifier : enable - // - // layout (local_size_x = 1, local_size_y = 1) in; - // - // layout(set = 2, binding = 0, std140) buffer Input { - // uint index; - // float red; - // } sbo; - // - // layout(set = 2, binding = 1, rgba32f) readonly uniform image2D images[]; - // - // void main() - // { - // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; - // } - - // clang-format off - const std::string defs = R"( -OpCapability Shader -OpCapability RuntimeDescriptorArray -;CHECK: OpCapability Linkage -OpExtension "SPV_EXT_descriptor_indexing" -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint GLCompute %main "main" -;CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID -OpExecutionMode %main LocalSize 1 1 1 -OpSource GLSL 450 -OpSourceExtension "GL_EXT_nonuniform_qualifier" -OpName %main "main" -OpName %Input "Input" -OpMemberName %Input 0 "index" -OpMemberName %Input 1 "red" -OpName %sbo "sbo" -OpName %images "images" -OpMemberDecorate %Input 0 Offset 0 -OpMemberDecorate %Input 1 Offset 4 -OpDecorate %Input BufferBlock -OpDecorate %sbo DescriptorSet 2 -OpDecorate %sbo Binding 0 -OpDecorate %images DescriptorSet 2 -OpDecorate %images Binding 1 -OpDecorate %images NonWritable -)" + kImportDeco + R"( -;CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId -%void = OpTypeVoid -%3 = OpTypeFunction %void -%uint = OpTypeInt 32 0 -%float = OpTypeFloat 32 -%Input = OpTypeStruct %uint %float -%_ptr_Uniform_Input = OpTypePointer Uniform %Input -%sbo = OpVariable %_ptr_Uniform_Input Uniform -%int = OpTypeInt 32 1 -%int_1 = OpConstant %int 1 -%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f -%_runtimearr_13 = OpTypeRuntimeArray %13 -%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 -%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant -%int_0 = OpConstant %int 0 -%_ptr_Uniform_uint = OpTypePointer Uniform %uint -%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 -%v2int = OpTypeVector %int 2 -%25 = OpConstantComposite %v2int %int_0 %int_0 -%v4float = OpTypeVector %float 4 -%uint_0 = OpConstant %uint 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -;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 -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 -%20 = OpLoad %uint %19 -%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 -%23 = OpLoad %13 %22 -%27 = OpImageRead %v4float %23 %25 -%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 %)" + 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 -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, - InstBoundsRayGenerationInitLoadVariableSizedSampledImagesArray) { - // #version 460 - // #extension GL_EXT_nonuniform_qualifier : require - // #extension GL_NV_ray_tracing : require - // - // layout(set = 3, binding = 1, std140) buffer StorageBuffer { - // uint index; - // float red; - // } sbo; - // - // layout(set = 3, binding = 5, rgba32f) readonly uniform image2D images[]; - // - // void main() - // { - // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; - // } - - // clang-format off - const std::string defs = R"( -OpCapability RuntimeDescriptorArray -OpCapability RayTracingNV -;CHECK: OpCapability Linkage -OpExtension "SPV_EXT_descriptor_indexing" -OpExtension "SPV_NV_ray_tracing" -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint RayGenerationNV %main "main" -;CHECK: OpEntryPoint RayGenerationNV %main "main" [[launch_id:%\w+]] -OpSource GLSL 460 -OpSourceExtension "GL_EXT_nonuniform_qualifier" -OpSourceExtension "GL_NV_ray_tracing" -OpName %main "main" -OpName %StorageBuffer "StorageBuffer" -OpMemberName %StorageBuffer 0 "index" -OpMemberName %StorageBuffer 1 "red" -OpName %sbo "sbo" -OpName %images "images" -OpMemberDecorate %StorageBuffer 0 Offset 0 -OpMemberDecorate %StorageBuffer 1 Offset 4 -OpDecorate %StorageBuffer BufferBlock -OpDecorate %sbo DescriptorSet 3 -OpDecorate %sbo Binding 1 -OpDecorate %images DescriptorSet 3 -OpDecorate %images Binding 5 -OpDecorate %images NonWritable -)" + kImportDeco + R"( -;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV -%void = OpTypeVoid -%3 = OpTypeFunction %void -%uint = OpTypeInt 32 0 -%float = OpTypeFloat 32 -%StorageBuffer = OpTypeStruct %uint %float -%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer -%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform -%int = OpTypeInt 32 1 -%int_1 = OpConstant %int 1 -%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f -%_runtimearr_13 = OpTypeRuntimeArray %13 -%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 -%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant -%int_0 = OpConstant %int 0 -%_ptr_Uniform_uint = OpTypePointer Uniform %uint -%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 -%v2int = OpTypeVector %int 2 -%25 = OpConstantComposite %v2int %int_0 %int_0 -%v4float = OpTypeVector %float 4 -%uint_0 = OpConstant %uint 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 -%20 = OpLoad %uint %19 -%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 -%23 = OpLoad %13 %22 -%27 = OpImageRead %v4float %23 %25 -%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 %)" + 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 -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, - InstBoundsIntersectionInitLoadVariableSizedSampledImagesArray) { - // #version 460 - // #extension GL_EXT_nonuniform_qualifier : require - // #extension GL_NV_ray_tracing : require - // - // layout(set = 5, binding = 1, std140) buffer StorageBuffer { - // uint index; - // float red; - // } sbo; - // - // layout(set = 5, binding = 3, rgba32f) readonly uniform image2D images[]; - // - // void main() - // { - // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; - // } - - // clang-format off - const std::string defs = R"( -OpCapability RuntimeDescriptorArray -OpCapability RayTracingNV -;CHECK: OpCapability Linkage -OpExtension "SPV_EXT_descriptor_indexing" -OpExtension "SPV_NV_ray_tracing" -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint IntersectionNV %main "main" -;CHECK: OpEntryPoint IntersectionNV %main "main" [[launch_id:%\w+]] -OpSource GLSL 460 -OpSourceExtension "GL_EXT_nonuniform_qualifier" -OpSourceExtension "GL_NV_ray_tracing" -OpName %main "main" -OpName %StorageBuffer "StorageBuffer" -OpMemberName %StorageBuffer 0 "index" -OpMemberName %StorageBuffer 1 "red" -OpName %sbo "sbo" -OpName %images "images" -OpMemberDecorate %StorageBuffer 0 Offset 0 -OpMemberDecorate %StorageBuffer 1 Offset 4 -OpDecorate %StorageBuffer BufferBlock -OpDecorate %sbo DescriptorSet 5 -OpDecorate %sbo Binding 1 -OpDecorate %images DescriptorSet 5 -OpDecorate %images Binding 3 -OpDecorate %images NonWritable -)" + kImportDeco + R"( -;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV -%void = OpTypeVoid -%3 = OpTypeFunction %void -%uint = OpTypeInt 32 0 -%float = OpTypeFloat 32 -%StorageBuffer = OpTypeStruct %uint %float -%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer -%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform -%int = OpTypeInt 32 1 -%int_1 = OpConstant %int 1 -%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f -%_runtimearr_13 = OpTypeRuntimeArray %13 -%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 -%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant -%int_0 = OpConstant %int 0 -%_ptr_Uniform_uint = OpTypePointer Uniform %uint -%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 -%v2int = OpTypeVector %int 2 -%25 = OpConstantComposite %v2int %int_0 %int_0 -%v4float = OpTypeVector %float 4 -%uint_0 = OpConstant %uint 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -;CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input -;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 -%20 = OpLoad %uint %19 -%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 -%23 = OpLoad %13 %22 -%27 = OpImageRead %v4float %23 %25 -%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 %)" + 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 -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, - InstBoundsAnyHitInitLoadVariableSizedSampledImagesArray) { - // #version 460 - // #extension GL_EXT_nonuniform_qualifier : require - // #extension GL_NV_ray_tracing : require - // - // layout(set = 2, binding = 1, std140) buffer StorageBuffer { - // uint index; - // float red; - // } sbo; - // - // layout(set = 2, binding = 3, rgba32f) readonly uniform image2D images[]; - // - // void main() - // { - // sbo.red = imageLoad(images[sbo.index], ivec2(0, 0)).r; - // } - - // clang-format off - const std::string defs = R"( -OpCapability RuntimeDescriptorArray -OpCapability RayTracingNV -;CHECK: OpCapability Linkage -OpExtension "SPV_EXT_descriptor_indexing" -OpExtension "SPV_NV_ray_tracing" -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint AnyHitNV %main "main" -;CHECK: OpEntryPoint AnyHitNV %main "main" [[launch_id:%\w+]] -OpSource GLSL 460 -OpSourceExtension "GL_EXT_nonuniform_qualifier" -OpSourceExtension "GL_NV_ray_tracing" -OpName %main "main" -OpName %StorageBuffer "StorageBuffer" -OpMemberName %StorageBuffer 0 "index" -OpMemberName %StorageBuffer 1 "red" -OpName %sbo "sbo" -OpName %images "images" -OpMemberDecorate %StorageBuffer 0 Offset 0 -OpMemberDecorate %StorageBuffer 1 Offset 4 -OpDecorate %StorageBuffer BufferBlock -OpDecorate %sbo DescriptorSet 2 -OpDecorate %sbo Binding 1 -OpDecorate %images DescriptorSet 2 -OpDecorate %images Binding 3 -OpDecorate %images NonWritable -)" + kImportDeco + R"( -;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV -%void = OpTypeVoid -%3 = OpTypeFunction %void -%uint = OpTypeInt 32 0 -%float = OpTypeFloat 32 -%StorageBuffer = OpTypeStruct %uint %float -%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer -%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform -%int = OpTypeInt 32 1 -%int_1 = OpConstant %int 1 -%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f -%_runtimearr_13 = OpTypeRuntimeArray %13 -%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 -%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant -%int_0 = OpConstant %int 0 -%_ptr_Uniform_uint = OpTypePointer Uniform %uint -%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 -%v2int = OpTypeVector %int 2 -%25 = OpConstantComposite %v2int %int_0 %int_0 -%v4float = OpTypeVector %float 4 -%uint_0 = OpConstant %uint 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -;CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input -;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 -%20 = OpLoad %uint %19 -%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 -%23 = OpLoad %13 %22 -%27 = OpImageRead %v4float %23 %25 -%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 %)" + kFuncName + R"( %uint_23 %uint_49 {{%\w+}} %uint_2 %uint_1 %uint_0 {{%\w+}} -;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpLoad %uint %25 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: [[phi_result:%\w+]] = OpPhi %uint {{%\w+}} {{%\w+}} [[null_uint]] {{%\w+}} -;CHECK: %27 = OpAccessChain %_ptr_UniformConstant_13 %images [[phi_result]] -;CHECK: %28 = OpLoad %13 %27 -;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5315 {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_52 {{%\w+}} %uint_2 %uint_3 {{%\w+}} %uint_0 -;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpLoad %13 %27 -;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %20 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -;CHECK: %30 = OpCompositeExtract %float {{%\w+}} 0 -;CHECK: %31 = OpAccessChain %_ptr_Uniform_float %sbo %int_1 -;CHECK: {{%\w+}} = OpLoad %v3uint {{%\w+}} -;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 0 -;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 1 -;CHECK: {{%\w+}} = OpCompositeExtract %uint {{%\w+}} 2 -;CHECK: {{%\w+}} = OpCompositeConstruct %v4uint %uint_5315 {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpFunctionCall %bool %)" + kFuncName + R"( %uint_23 %uint_55 {{%\w+}} %uint_2 %uint_1 %uint_0 {{%\w+}} -;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: OpStore %31 %30 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -OpReturn -OpFunctionEnd -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, - InstBoundsClosestHitInitLoadVariableSizedSampledImagesArray) { - // #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; - // } - - // clang-format off - const std::string defs = R"( -OpCapability RuntimeDescriptorArray -OpCapability RayTracingNV -;CHECK: OpCapability Linkage -OpExtension "SPV_EXT_descriptor_indexing" -OpExtension "SPV_NV_ray_tracing" -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint ClosestHitNV %main "main" -;CHECK: OpEntryPoint ClosestHitNV %main "main" [[launch_id:%\w+]] -OpSource GLSL 460 -OpSourceExtension "GL_EXT_nonuniform_qualifier" -OpSourceExtension "GL_NV_ray_tracing" -OpName %main "main" -OpName %StorageBuffer "StorageBuffer" -OpMemberName %StorageBuffer 0 "index" -OpMemberName %StorageBuffer 1 "red" -OpName %sbo "sbo" -OpName %images "images" -OpMemberDecorate %StorageBuffer 0 Offset 0 -OpMemberDecorate %StorageBuffer 1 Offset 4 -OpDecorate %StorageBuffer BufferBlock -OpDecorate %sbo DescriptorSet 1 -OpDecorate %sbo Binding 2 -OpDecorate %images DescriptorSet 1 -OpDecorate %images Binding 3 -OpDecorate %images NonWritable -)" + kImportDeco + R"( -;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV -%void = OpTypeVoid -%3 = OpTypeFunction %void -%uint = OpTypeInt 32 0 -%float = OpTypeFloat 32 -%StorageBuffer = OpTypeStruct %uint %float -%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer -%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform -%int = OpTypeInt 32 1 -%int_1 = OpConstant %int 1 -%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f -%_runtimearr_13 = OpTypeRuntimeArray %13 -%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 -%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant -%int_0 = OpConstant %int 0 -%_ptr_Uniform_uint = OpTypePointer Uniform %uint -%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 -%v2int = OpTypeVector %int 2 -%25 = OpConstantComposite %v2int %int_0 %int_0 -%v4float = OpTypeVector %float 4 -%uint_0 = OpConstant %uint 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -;CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input -;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 -%20 = OpLoad %uint %19 -%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 -%23 = OpLoad %13 %22 -%27 = OpImageRead %v4float %23 %25 -%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 %)" + 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 -)"; - // clang-format on - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, - InstBoundsMissInitLoadVariableSizedSampledImagesArray) { - // #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; - // } - - // clang-format off - const std::string defs = R"( -OpCapability RuntimeDescriptorArray -OpCapability RayTracingNV -;CHECK: OpCapability Linkage -OpExtension "SPV_EXT_descriptor_indexing" -OpExtension "SPV_NV_ray_tracing" -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint MissNV %main "main" -;CHECK: OpEntryPoint MissNV %main "main" [[launch_id:%\w+]] -OpSource GLSL 460 -OpSourceExtension "GL_EXT_nonuniform_qualifier" -OpSourceExtension "GL_NV_ray_tracing" -OpName %main "main" -OpName %StorageBuffer "StorageBuffer" -OpMemberName %StorageBuffer 0 "index" -OpMemberName %StorageBuffer 1 "red" -OpName %sbo "sbo" -OpName %images "images" -OpMemberDecorate %StorageBuffer 0 Offset 0 -OpMemberDecorate %StorageBuffer 1 Offset 4 -OpDecorate %StorageBuffer BufferBlock -OpDecorate %sbo DescriptorSet 1 -OpDecorate %sbo Binding 2 -OpDecorate %images DescriptorSet 1 -OpDecorate %images Binding 3 -OpDecorate %images NonWritable -)" + kImportDeco + R"( -;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV -%void = OpTypeVoid -%3 = OpTypeFunction %void -%uint = OpTypeInt 32 0 -%float = OpTypeFloat 32 -%StorageBuffer = OpTypeStruct %uint %float -%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer -%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform -%int = OpTypeInt 32 1 -%int_1 = OpConstant %int 1 -%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f -%_runtimearr_13 = OpTypeRuntimeArray %13 -%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 -%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant -%int_0 = OpConstant %int 0 -%_ptr_Uniform_uint = OpTypePointer Uniform %uint -%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 -%v2int = OpTypeVector %int 2 -%25 = OpConstantComposite %v2int %int_0 %int_0 -%v4float = OpTypeVector %float 4 -%uint_0 = OpConstant %uint 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -;CHECK: [[launch_id]] = OpVariable %_ptr_Input_v3uint Input -;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 -%20 = OpLoad %uint %19 -%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 -%23 = OpLoad %13 %22 -%27 = OpImageRead %v4float %23 %25 -%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 %)" + 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; - // } - - // clang-format off - const std::string defs = R"( -OpCapability RuntimeDescriptorArray -OpCapability RayTracingNV -;CHECK: OpCapability Linkage -OpExtension "SPV_EXT_descriptor_indexing" -OpExtension "SPV_NV_ray_tracing" -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint CallableNV %main "main" -;CHECK: OpEntryPoint CallableNV %main "main" [[launch_id:%\w+]] -OpSource GLSL 460 -OpSourceExtension "GL_EXT_nonuniform_qualifier" -OpSourceExtension "GL_NV_ray_tracing" -OpName %main "main" -OpName %StorageBuffer "StorageBuffer" -OpMemberName %StorageBuffer 0 "index" -OpMemberName %StorageBuffer 1 "red" -OpName %sbo "sbo" -OpName %images "images" -OpMemberDecorate %StorageBuffer 0 Offset 0 -OpMemberDecorate %StorageBuffer 1 Offset 4 -OpDecorate %StorageBuffer BufferBlock -OpDecorate %sbo DescriptorSet 1 -OpDecorate %sbo Binding 2 -OpDecorate %images DescriptorSet 1 -OpDecorate %images Binding 3 -OpDecorate %images NonWritable -)" + kImportDeco + R"( -;CHECK: OpDecorate [[launch_id]] BuiltIn LaunchIdNV -%void = OpTypeVoid -%3 = OpTypeFunction %void -%uint = OpTypeInt 32 0 -%float = OpTypeFloat 32 -%StorageBuffer = OpTypeStruct %uint %float -%_ptr_Uniform_StorageBuffer = OpTypePointer Uniform %StorageBuffer -%sbo = OpVariable %_ptr_Uniform_StorageBuffer Uniform -%int = OpTypeInt 32 1 -%int_1 = OpConstant %int 1 -%13 = OpTypeImage %float 2D 0 0 0 2 Rgba32f -%_runtimearr_13 = OpTypeRuntimeArray %13 -%_ptr_UniformConstant__runtimearr_13 = OpTypePointer UniformConstant %_runtimearr_13 -%images = OpVariable %_ptr_UniformConstant__runtimearr_13 UniformConstant -%int_0 = OpConstant %int 0 -%_ptr_Uniform_uint = OpTypePointer Uniform %uint -%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 -%v2int = OpTypeVector %int 2 -%25 = OpConstantComposite %v2int %int_0 %int_0 -%v4float = OpTypeVector %float 4 -%uint_0 = OpConstant %uint 0 -%_ptr_Uniform_float = OpTypePointer Uniform %float -;CHECK: [[null_uint:%\w+]] = OpConstantNull %uint -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%19 = OpAccessChain %_ptr_Uniform_uint %sbo %int_0 -%20 = OpLoad %uint %19 -%22 = OpAccessChain %_ptr_UniformConstant_13 %images %20 -%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 %)" + 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 %)" + 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, InstBoundsInitSameBlockOpReplication) { - // Test that same block ops like OpSampledImage are replicated properly - // where needed. - // - // clang-format off - // - // #version 450 core - // #extension GL_EXT_nonuniform_qualifier : enable - // - // layout(location = 0) in vec2 inTexcoord; - // layout(location = 0) out vec4 outColor; - // - // layout(set = 1, binding = 0) uniform Uniforms { - // vec2 var0; - // } uniforms; - // - // layout(set = 1, binding = 1) uniform sampler uniformSampler; - // layout(set = 1, binding = 2) uniform texture2D uniformTex; - // layout(set = 1, binding = 3) uniform texture2D uniformTexArr[8]; - // - // void main() { - // int index = 0; - // float x = texture(sampler2D(uniformTexArr[nonuniformEXT(index)], uniformSampler), inTexcoord.xy).x; - // float y = texture(sampler2D(uniformTex, uniformSampler), inTexcoord.xy * uniforms.var0.xy).x; - // outColor = vec4(x, y, 0.0, 0.0); - // } - // - - const std::string defs = R"( -OpCapability Shader -OpCapability ShaderNonUniformEXT -OpCapability SampledImageArrayNonUniformIndexingEXT -;CHECK: OpCapability Linkage -OpExtension "SPV_EXT_descriptor_indexing" -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Fragment %main "main" %inTexcoord %outColor -;CHECK: OpEntryPoint Fragment %main "main" %inTexcoord %outColor %gl_FragCoord -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 450 -OpSourceExtension "GL_EXT_nonuniform_qualifier" -OpName %main "main" -OpName %index "index" -OpName %x "x" -OpName %uniformTexArr "uniformTexArr" -OpName %uniformSampler "uniformSampler" -OpName %inTexcoord "inTexcoord" -OpName %y "y" -OpName %uniformTex "uniformTex" -OpName %Uniforms "Uniforms" -OpMemberName %Uniforms 0 "var0" -OpName %uniforms "uniforms" -OpName %outColor "outColor" -OpDecorate %uniformTexArr DescriptorSet 1 -OpDecorate %uniformTexArr Binding 3 -OpDecorate %19 NonUniformEXT -OpDecorate %22 NonUniformEXT -OpDecorate %uniformSampler DescriptorSet 1 -OpDecorate %uniformSampler Binding 1 -OpDecorate %inTexcoord Location 0 -OpDecorate %uniformTex DescriptorSet 1 -OpDecorate %uniformTex Binding 2 -OpMemberDecorate %Uniforms 0 Offset 0 -OpDecorate %Uniforms Block -OpDecorate %uniforms DescriptorSet 1 -OpDecorate %uniforms Binding 0 -OpDecorate %outColor Location 0 -;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 -%_ptr_Function_int = OpTypePointer Function %int -%int_0 = OpConstant %int 0 -%float = OpTypeFloat 32 -%_ptr_Function_float = OpTypePointer Function %float -%13 = OpTypeImage %float 2D 0 0 0 1 Unknown -%uint = OpTypeInt 32 0 -%uint_8 = OpConstant %uint 8 -%_arr_13_uint_8 = OpTypeArray %13 %uint_8 -%_ptr_UniformConstant__arr_13_uint_8 = OpTypePointer UniformConstant %_arr_13_uint_8 -%uniformTexArr = OpVariable %_ptr_UniformConstant__arr_13_uint_8 UniformConstant -%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 -%23 = OpTypeSampler -%_ptr_UniformConstant_23 = OpTypePointer UniformConstant %23 -%uniformSampler = OpVariable %_ptr_UniformConstant_23 UniformConstant -%27 = OpTypeSampledImage %13 -%v2float = OpTypeVector %float 2 -%_ptr_Input_v2float = OpTypePointer Input %v2float -%inTexcoord = OpVariable %_ptr_Input_v2float Input -%v4float = OpTypeVector %float 4 -%uint_0 = OpConstant %uint 0 -%uniformTex = OpVariable %_ptr_UniformConstant_13 UniformConstant -%Uniforms = OpTypeStruct %v2float -%_ptr_Uniform_Uniforms = OpTypePointer Uniform %Uniforms -%uniforms = OpVariable %_ptr_Uniform_Uniforms Uniform -%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float -%_ptr_Output_v4float = OpTypePointer Output %v4float -%outColor = OpVariable %_ptr_Output_v4float Output -%float_0 = OpConstant %float 0 -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -;CHECK: [[null_v2float:%\w+]] = OpConstantNull %v2float -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%index = OpVariable %_ptr_Function_int Function -%x = OpVariable %_ptr_Function_float Function -%y = OpVariable %_ptr_Function_float Function -OpStore %index %int_0 -%19 = OpLoad %int %index -%21 = OpAccessChain %_ptr_UniformConstant_13 %uniformTexArr %19 -%22 = OpLoad %13 %21 -%26 = OpLoad %23 %uniformSampler -%28 = OpSampledImage %27 %22 %26 -%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 %)" + 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 -%41 = OpSampledImage %27 %39 %40 -%42 = OpLoad %v2float %inTexcoord -%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 %)" + 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 %)" + 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 -%57 = OpCompositeConstruct %v4float %54 %55 %float_0 %float_0 -OpStore %outColor %57 -OpReturn -OpFunctionEnd -)"; - // clang-format on - - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(defs + kImportStub + main_func, - true, 23u); -} - -TEST_F(InstBindlessTest, MultipleUniformNonAggregateRefsNoDescInit) { - // Check that uniform refs do not go out-of-bounds. All checks use same input - // buffer read function call result at top of function for uniform buffer - // length. Because descriptor indexing is not being checked, we can avoid one - // buffer load. - // - // Texture2D g_tColor; - // SamplerState g_sAniso; - // - // layout(push_constant) cbuffer PerViewPushConst_t { bool g_B; }; - // - // cbuffer PerViewConstantBuffer_t { - // float2 g_TexOff0; - // float2 g_TexOff1; - // }; - // - // struct PS_INPUT { - // float2 vTextureCoords : TEXCOORD2; - // }; - // - // struct PS_OUTPUT { - // float4 vColor : SV_Target0; - // }; - // - // PS_OUTPUT MainPs(PS_INPUT i) { - // PS_OUTPUT ps_output; - // float2 off; - // float2 vtc; - // if (g_B) - // off = g_TexOff0; - // else - // off = g_TexOff1; - // vtc = i.vTextureCoords.xy + off; - // ps_output.vColor = g_tColor.Sample(g_sAniso, vtc); - // return ps_output; - // } - - // clang-format off - const std::string text = R"( -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 -%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint -%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 -%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float -%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 -%_ptr_UniformConstant_53 = OpTypePointer UniformConstant %53 -%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 -;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 -%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_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 23u); -} - -TEST_F(InstBindlessTest, UniformArrayRefNoDescInit) { - // Check that uniform array ref does not go out-of-bounds. - // - // Texture2D g_tColor; - // SamplerState g_sAniso; - // - // layout(push_constant) cbuffer PerViewPushConst_t { uint g_c; }; - // - // struct PerBatchEnvMapConstantBuffer_t { - // float4x3 g_matEnvMapWorldToLocal; - // float4 g_vEnvironmentMapBoxMins; - // float2 g_TexOff; - // }; - // - // cbuffer _BindlessFastEnvMapCB_PS_t { - // PerBatchEnvMapConstantBuffer_t g_envMapConstants[128]; - // }; - // - // struct PS_INPUT { - // float2 vTextureCoords : TEXCOORD2; - // }; - // - // struct PS_OUTPUT { - // float4 vColor : SV_Target0; - // }; - // - // PS_OUTPUT MainPs(PS_INPUT i) { - // PS_OUTPUT ps_output; - // float2 off; - // float2 vtc; - // off = g_envMapConstants[g_c].g_TexOff; - // vtc = i.vTextureCoords.xy + off; - // ps_output.vColor = g_tColor.Sample(g_sAniso, vtc); - // return ps_output; - // } - - // clang-format off - const std::string text = R"( -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 -%_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 -%PerViewPushConst_t = OpTypeStruct %uint -%_ptr_PushConstant_PerViewPushConst_t = OpTypePointer PushConstant %PerViewPushConst_t -%__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant -%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint -%int_2 = OpConstant %int 2 -%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float -%46 = OpTypeImage %float 2D 0 0 0 1 Unknown -%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46 -%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 -%_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 -;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 -;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %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_79 {{%\w+}} %uint_0 %uint_2 %uint_0 {{%\w+}} -;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpLoad %v2float %81 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;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 -)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 23u); -} - -TEST_F(InstBindlessTest, UniformArrayRefWithDescInit) { - // The buffer-oob and desc-init checks should use the same debug - // output buffer write function. - // - // Same source as UniformArrayRefNoDescInit - - // clang-format off - const std::string text = R"( -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 -%_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 -%PerViewPushConst_t = OpTypeStruct %uint -%_ptr_PushConstant_PerViewPushConst_t = OpTypePointer PushConstant %PerViewPushConst_t -%__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant -%_ptr_PushConstant_uint = OpTypePointer PushConstant %uint -%int_2 = OpConstant %int 2 -%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float -%46 = OpTypeImage %float 2D 0 0 0 1 Unknown -%_ptr_UniformConstant_46 = OpTypePointer UniformConstant %46 -%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 -%_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 -;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 -;CHECK: [[null_v4float:%\w+]] = OpConstantNull %v4float -)" + 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 -;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} -;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64 -;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %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_79 {{%\w+}} %uint_0 %uint_2 %uint_0 {{%\w+}} -;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpLoad %v2float %81 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: OpBranch {{%\w+}} -;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 -;CHECK-NOT: %91 = OpImageSampleImplicitLod %v4float %89 %86 -;CHECK-NOT: OpStore %_entryPointOutput_vColor %91 -;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_84 {{%\w+}} %uint_0 %uint_0 %uint_0 %uint_0 -;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpLoad %46 %g_tColor -;CHECK: {{%\w+}} = OpSampledImage %54 {{%\w+}} %88 -;CHECK: {{%\w+}} = OpImageSampleImplicitLod %v4float {{%\w+}} %86 -;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 -)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 23u); -} - -TEST_F(InstBindlessTest, Descriptor16BitIdxRef) { - // Check that descriptor indexed with 16bit index is inbounds and - // initialized - // - // Use Simple source with min16uint g_nDataIdx - - // clang-format off - const std::string text = R"( -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 -%PerViewConstantBuffer_t = OpTypeStruct %ushort -%_ptr_PushConstant_PerViewConstantBuffer_t = OpTypePointer PushConstant %PerViewConstantBuffer_t -%_ = OpVariable %_ptr_PushConstant_PerViewConstantBuffer_t PushConstant -%_ptr_PushConstant_ushort = OpTypePointer PushConstant %ushort -%_ptr_UniformConstant_16 = OpTypePointer UniformConstant %16 -%25 = OpTypeSampler -%_ptr_UniformConstant_25 = OpTypePointer UniformConstant %25 -%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 -;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 -;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 %)" + 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 -;CHECK: {{%\w+}} = OpLoad %16 %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: [[phi_result:%\w+]] = OpPhi %v4float {{%\w+}} {{%\w+}} [[null_v4float]] {{%\w+}} -;CHECK: OpStore %_entryPointOutput_vColor [[phi_result]] -OpReturn -OpFunctionEnd -)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 23u); -} - -TEST_F(InstBindlessTest, UniformArray16bitIdxRef) { - // Check that uniform array ref with 16bit index does not go out-of-bounds. - // - // Texture2D g_tColor; - // SamplerState g_sAniso; - // - // layout(push_constant) cbuffer PerViewPushConst_t { min16uint g_c; }; - // - // struct PerBatchEnvMapConstantBuffer_t { - // float4x3 g_matEnvMapWorldToLocal; - // float4 g_vEnvironmentMapBoxMins; - // float2 g_TexOff; - // }; - // - // cbuffer _BindlessFastEnvMapCB_PS_t { - // PerBatchEnvMapConstantBuffer_t g_envMapConstants[128]; - // }; - // - // struct PS_INPUT { - // float2 vTextureCoords : TEXCOORD2; - // }; - // - // struct PS_OUTPUT { - // float4 vColor : SV_Target0; - // }; - // - // PS_OUTPUT MainPs(PS_INPUT i) { - // PS_OUTPUT ps_output; - // float2 off; - // float2 vtc; - // off = g_envMapConstants[g_c].g_TexOff; - // vtc = i.vTextureCoords.xy + off; - // ps_output.vColor = g_tColor.Sample(g_sAniso, vtc); - // return ps_output; - // } - - // clang-format off - const std::string text = R"( -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 -%_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 -%PerViewPushConst_t = OpTypeStruct %ushort -%_ptr_PushConstant_PerViewPushConst_t = OpTypePointer PushConstant %PerViewPushConst_t -%__0 = OpVariable %_ptr_PushConstant_PerViewPushConst_t PushConstant -%_ptr_PushConstant_ushort = OpTypePointer PushConstant %ushort -%int_2 = OpConstant %int 2 -%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float -%30 = OpTypeImage %float 2D 0 0 0 1 Unknown -%_ptr_UniformConstant_30 = OpTypePointer UniformConstant %30 -%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 -%_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 -;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+}} -;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_64 -;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %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_82 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} -;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpLoad %v2float %41 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: OpBranch {{%\w+}} -;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 -)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 23u); -} - -TEST_F(InstBindlessTest, UniformMatrixRefRowMajor) { - // The buffer-oob row major matrix check - // - // #version 450 - // #extension GL_EXT_scalar_block_layout : enable - // - // layout(location = 0) in highp vec4 a_position; - // layout(location = 0) out mediump float v_vtxResult; - // - // layout(set = 0, binding = 0, std430, row_major) uniform Block - // { - // lowp mat4x2 var; - // }; - // - // void main (void) - // { - // v_vtxResult = var[2][1]; - // } - - // clang-format off - std::string text = R"( -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 -)" + 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 -%_ptr_Output_float = OpTypePointer Output %float -%v_vtxResult = OpVariable %_ptr_Output_float Output -%v2float = OpTypeVector %float 2 -%mat4v2float = OpTypeMatrix %v2float 4 -%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 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%v4float = OpTypeVector %float 4 -%_ptr_Input_v4float = OpTypePointer Input %v4float -%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 -;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 -;CHECK: {{%\w+}} = OpIMul %uint %uint_4 %int_2 -;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} -;CHECK: {{%\w+}} = OpIMul %uint %uint_16 %uint_1 -;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 -;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 %)" + 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 -;CHECK: [[load_result]] = OpLoad %float %20 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;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 -)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 23u); -} - -TEST_F(InstBindlessTest, UniformMatrixRefColumnMajor) { - // The buffer-oob column major matrix check - // - // #version 450 - // #extension GL_EXT_scalar_block_layout : enable - // - // layout(location = 0) in highp vec4 a_position; - // layout(location = 0) out mediump float v_vtxResult; - // - // layout(set = 0, binding = 0, std430, column_major) uniform Block - // { - // lowp mat4x2 var; - // }; - // - // void main (void) - // { - // v_vtxResult = var[2][1]; - // } - - // clang-format off - const std::string text = R"( -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 -)" + 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 -%_ptr_Output_float = OpTypePointer Output %float -%v_vtxResult = OpVariable %_ptr_Output_float Output -%v2float = OpTypeVector %float 2 -%mat4v2float = OpTypeMatrix %v2float 4 -%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 -%_ptr_Uniform_float = OpTypePointer Uniform %float -%v4float = OpTypeVector %float 4 -%_ptr_Input_v4float = OpTypePointer Input %v4float -%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 -;CHECK-NOT: %21 = OpLoad %float %20 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpIMul %uint %uint_8 %int_2 -;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 {{%\w+}} -;CHECK: {{%\w+}} = OpIMul %uint %uint_4 %uint_1 -;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_3 -;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 %)" + 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 -;CHECK:[[load_result]] = OpLoad %float %20 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;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 -)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - ValidatorOptions()->uniform_buffer_standard_layout = true; - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 23u); -} - -TEST_F(InstBindlessTest, UniformMatrixVecRefRowMajor) { - // The buffer-oob row major matrix vector ref check - // - // #version 450 - // #extension GL_EXT_scalar_block_layout : enable - // - // layout(location = 0) in highp vec4 a_position; - // layout(location = 0) out highp vec2 v_vtxResult; - // - // layout(set = 3, binding = 7, std430, row_major) uniform Block - // { - // lowp mat2 var[3][4]; - // }; - // - // void main (void) - // { - // v_vtxResult = var[2][3][1]; - // } - - // clang-format off - const std::string text = R"( -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 -)" + 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 -%_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 -%_arr_mat2v2float_uint_4 = OpTypeArray %mat2v2float %uint_4 -%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 -%_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 -%_ptr_Uniform_v2float = OpTypePointer Uniform %v2float -%v4float = OpTypeVector %float 4 -%_ptr_Input_v4float = OpTypePointer Input %v4float -%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 -)" + 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 -;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpIMul %uint %uint_4 %int_1 -;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpIAdd %uint {{%\w+}} %uint_19 -;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 %)" + 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: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional [[desc_state]] {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: [[load_result]] = OpLoad %v2float %25 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: [[phi_result]] = OpPhi %v2float [[load_result]] {{%\w+}} [[null_v2float]] {{%\w+}} -;CHECK: OpStore %v_vtxResult [[phi_result]] -OpReturn -OpFunctionEnd -)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 23u); -} - -TEST_F(InstBindlessTest, ImageBufferOOBRead) { - // Texel buffer (imagebuffer) oob check for ImageRead - // - // #version 450 - // layout(set=3, binding=7, r32f) uniform readonly imageBuffer s; - // layout(location=11) out vec4 x; - // layout(location=13) in flat int ii; - // - // void main(){ - // x = imageLoad(s, ii); - // } - - // clang-format off - const std::string text = R"( -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 -;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_34 {{%\w+}} %uint_3 %uint_7 %uint_0 %22 -;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpLoad %10 %s -;CHECK: {{%\w+}} = OpImageRead %v4float {{%\w+}} %17 -;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 %x [[phi_result]] -OpReturn -OpFunctionEnd -)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 23u); -} - -TEST_F(InstBindlessTest, ImageBufferOOBWrite) { - // Texel buffer (imagebuffer) oob check for ImageWrite - // - // #version 450 - // layout(set=3, binding=7, r32f) uniform readonly imageBuffer s; - // layout(location=11) out vec4 x; - // layout(location=13) in flat int ii; - // - // void main(){ - // imageStore(s, ii, x); - // } - - // clang-format off - const std::string text = R"( -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 -)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 23u); -} - -TEST_F(InstBindlessTest, TextureBufferOOBFetch) { - // Texel buffer (texturebuffer) oob check for ImageFetch - // - // #version 450 - // layout(set=3, binding=7) uniform textureBuffer s; - // layout(location=11) out vec4 x; - // layout(location=13) in flat int ii; - // - // void main(){ - // x = texelFetch(s, ii); - // } - - // clang-format off - const std::string text = R"( -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 -;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_33 {{%\w+}} %uint_3 %uint_7 %uint_0 {{%\w+}} -;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpLoad %10 %s -;CHECK: {{%\w+}} = OpImageFetch %v4float {{%\w+}} %17 -;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 %x [[phi_result]] -OpReturn -OpFunctionEnd -)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 23u); -} - -TEST_F(InstBindlessTest, SamplerBufferOOBFetch) { - // Texel buffer (samplerbuffer) oob check for ImageFetch - // - // #version 450 - // layout(set=3, binding=7) uniform samplerBuffer s; - // layout(location=11) out vec4 x; - // layout(location=13) in flat int ii; - // - // void main(){ - // x = texelFetch(s, ii); - // } - - // clang-format off - const std::string text = R"( -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 -)" + 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 %)" + 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 %11 %s -;CHECK: {{%\w+}} = OpImage %10 {{%\w+}} -;CHECK: {{%\w+}} = OpImageFetch %v4float {{%\w+}} {{%\w+}} -;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 %x [[phi_result]] -OpReturn -OpFunctionEnd -)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 23u); -} - -TEST_F(InstBindlessTest, SamplerBufferConstructorOOBFetch) { - // Texel buffer (samplerbuffer constructor) oob check for ImageFetch - // - // #version 450 - // layout(set=3, binding=7) uniform textureBuffer tBuf; - // layout(set=3, binding=8) uniform sampler s; - // layout(location=11) out vec4 x; - // layout(location=13) in flat int ii; - // - // void main(){ - // x = texelFetch(samplerBuffer(tBuf, s), ii); - // } - - // clang-format off - const std::string text = R"( -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 %)" + 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 -;CHECK: {{%\w+}} = OpLoad %10 %tBuf -;CHECK: {{%\w+}} = OpSampledImage %18 {{%\w+}} %17 -;CHECK: {{%\w+}} = OpImage %10 {{%\w+}} -;CHECK: {{%\w+}} = OpImageFetch %v4float {{%\w+}} %23 -;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 %x [[phi_result]] -OpReturn -OpFunctionEnd -)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 23u); -} - -TEST_F(InstBindlessTest, DeviceBufferAddressOOB) { - // #version 450 - // #extension GL_EXT_buffer_reference : enable - // layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct; - // layout(set = 0, binding = 0) uniform ufoo { - // bufStruct data; - // int nWrites; - // } u_info; - // layout(buffer_reference, std140) buffer bufStruct { - // int a[4]; - // }; - // void main() { - // for (int i=0; i < u_info.nWrites; ++i) { - // u_info.data.a[i] = 0xdeadca71; - // } - // } - - // clang-format off - 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 %gl_VertexIndex %gl_InstanceIndex -OpSource GLSL 450 -OpSourceExtension "GL_EXT_buffer_reference" -OpName %main "main" -OpName %i "i" -OpName %ufoo "ufoo" -OpMemberName %ufoo 0 "data" -OpMemberName %ufoo 1 "nWrites" -OpName %bufStruct "bufStruct" -OpMemberName %bufStruct 0 "a" -OpName %u_info "u_info" -OpMemberDecorate %ufoo 0 Offset 0 -OpMemberDecorate %ufoo 1 Offset 8 -OpDecorate %ufoo Block -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 -%void = OpTypeVoid -%3 = OpTypeFunction %void -%int = OpTypeInt 32 1 -%_ptr_Function_int = OpTypePointer Function %int -%int_0 = OpConstant %int 0 -OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer -%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %int -%uint = OpTypeInt 32 0 -%uint_4 = OpConstant %uint 4 -%_arr_int_uint_4 = OpTypeArray %int %uint_4 -%bufStruct = OpTypeStruct %_arr_int_uint_4 -%_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct -%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo -%u_info = OpVariable %_ptr_Uniform_ufoo Uniform -%int_1 = OpConstant %int 1 -%_ptr_Uniform_int = OpTypePointer Uniform %int -%bool = OpTypeBool -%_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct -%int_n559035791 = OpConstant %int -559035791 -%_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 -OpBranch %10 -%10 = OpLabel -OpLoopMerge %12 %13 None -OpBranch %14 -%14 = OpLabel -%15 = OpLoad %int %i -%26 = OpAccessChain %_ptr_Uniform_int %u_info %int_1 -;CHECK: {{%\w+}} = OpIAdd %uint %uint_8 %uint_3 -;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_56 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} -;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: [[load_result:%\w+]] = OpLoad %int %26 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: [[phi_result:%\w+]] = OpPhi %int [[load_result]] {{%\w+}} {{%\w+}} {{%\w+}} -%27 = OpLoad %int %26 -%29 = OpSLessThan %bool %15 %27 -;CHECK-NOT: %27 = OpLoad %int %26 -;CHECK-NOT: %29 = OpSLessThan %bool %15 %27 -;CHECK: %29 = OpSLessThan %bool %15 [[phi_result]] -OpBranchConditional %29 %11 %12 -%11 = OpLabel -%31 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 -%32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 -;CHECK-NOT: %32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 -;CHECK: {{%\w+}} = OpIAdd %uint %uint_0 %uint_7 -;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_61 {{%\w+}} %uint_0 %uint_0 %uint_0 {{%\w+}} -;CHECK: OpSelectionMerge {{%\w+}} None -;CHECK: OpBranchConditional {{%\w+}} {{%\w+}} {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: [[load_result_2:%\w+]] = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: {{%\w+}} = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_bufStruct {{%\w+}} -;CHECK: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -;CHECK: [[phi_result_2:%\w+]] = OpPhi %_ptr_PhysicalStorageBuffer_bufStruct [[load_result_2]] {{%\w+}} {{%\w+}} {{%\w+}} -%33 = OpLoad %int %i -%36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %32 %int_0 %33 -;CHECK-NOT: %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %32 %int_0 %33 -;CHECK: %36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int [[phi_result_2]] %int_0 %33 -OpStore %36 %int_n559035791 Aligned 16 -OpBranch %13 -%13 = OpLabel -%37 = OpLoad %int %i -%38 = OpIAdd %int %37 %int_1 -OpStore %i %38 -OpBranch %10 -%12 = OpLabel -OpReturn -OpFunctionEnd)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 23u); -} - -TEST_F(InstBindlessTest, VertexIndexOOB) { - // #version 450 - // layout(std140, binding = 0) uniform foo { uint tex_index[1]; } - // uniform_index_buffer; layout(location = 0) out flat uint index; vec2 - // vertices[3]; void main() { - // vertices[0] = vec2(-1.0, -1.0); - // vertices[1] = vec2( 1.0, -1.0); - // vertices[2] = vec2( 0.0, 1.0); - // gl_Position = vec4(vertices[gl_VertexIndex % 3], 0.0, 1.0); - // index = uniform_index_buffer.tex_index[0]; - // } - // clang-format off - const std::string text = R"( -OpCapability Shader -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel Logical GLSL450 -OpEntryPoint Vertex %main "main" %vertices %_ %gl_VertexIndex %index %uniform_index_buffer -OpSource GLSL 450 -OpName %main "main" -OpName %vertices "vertices" -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 %_ "" -OpName %gl_VertexIndex "gl_VertexIndex" -OpName %index "index" -OpName %foo "foo" -OpMemberName %foo 0 "tex_index" -OpName %uniform_index_buffer "uniform_index_buffer" -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 -OpDecorate %gl_VertexIndex BuiltIn VertexIndex -OpDecorate %index Flat -OpDecorate %index Location 0 -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 -%void = OpTypeVoid -%3 = OpTypeFunction %void -%float = OpTypeFloat 32 -%v2float = OpTypeVector %float 2 -%uint = OpTypeInt 32 0 -%uint_3 = OpConstant %uint 3 -%_arr_v2float_uint_3 = OpTypeArray %v2float %uint_3 -%_ptr_Private__arr_v2float_uint_3 = OpTypePointer Private %_arr_v2float_uint_3 -%vertices = OpVariable %_ptr_Private__arr_v2float_uint_3 Private -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%float_n1 = OpConstant %float -1 -%16 = OpConstantComposite %v2float %float_n1 %float_n1 -%_ptr_Private_v2float = OpTypePointer Private %v2float -%int_1 = OpConstant %int 1 -%float_1 = OpConstant %float 1 -%21 = OpConstantComposite %v2float %float_1 %float_n1 -%int_2 = OpConstant %int 2 -%float_0 = OpConstant %float 0 -%25 = OpConstantComposite %v2float %float_0 %float_1 -%v4float = OpTypeVector %float 4 -%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 -%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex -%_ = OpVariable %_ptr_Output_gl_PerVertex Output -%_ptr_Input_int = OpTypePointer Input %int -%gl_VertexIndex = OpVariable %_ptr_Input_int Input -%int_3 = OpConstant %int 3 -%_ptr_Output_v4float = OpTypePointer Output %v4float -%_ptr_Output_uint = OpTypePointer Output %uint -%index = OpVariable %_ptr_Output_uint Output -%_arr_uint_uint_1 = OpTypeArray %uint %uint_1 -%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 -)" + kImportStub + R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%18 = OpAccessChain %_ptr_Private_v2float %vertices %int_0 -OpStore %18 %16 -%22 = OpAccessChain %_ptr_Private_v2float %vertices %int_1 -OpStore %22 %21 -%26 = OpAccessChain %_ptr_Private_v2float %vertices %int_2 -OpStore %26 %25 -%35 = OpLoad %int %gl_VertexIndex -%37 = OpSMod %int %35 %int_3 -%38 = OpAccessChain %_ptr_Private_v2float %vertices %37 -%39 = OpLoad %v2float %38 -%40 = OpCompositeExtract %float %39 0 -%41 = OpCompositeExtract %float %39 1 -%42 = OpCompositeConstruct %v4float %40 %41 %float_0 %float_1 -%44 = OpAccessChain %_ptr_Output_v4float %_ %int_0 -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 %)" + 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 -OpReturn -;CHECK: OpReturn -OpFunctionEnd)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 23u); -} - -// TODO(greg-lunarg): Add tests to verify handling of these cases: -// -// Compute shader -// Geometry shader -// Tessellation control shader -// Tessellation eval shader -// OpImage -// SampledImage variable - -} // namespace -} // namespace opt -} // namespace spvtools diff --git a/test/opt/inst_buff_addr_check_test.cpp b/test/opt/inst_buff_addr_check_test.cpp deleted file mode 100644 index 72d343852a..0000000000 --- a/test/opt/inst_buff_addr_check_test.cpp +++ /dev/null @@ -1,772 +0,0 @@ -// Copyright (c) 2019-2022 Valve Corporation -// Copyright (c) 2019-2022 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 { - -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 kImportStub = R"( -;CHECK: %)" + kFuncName + R"( = OpFunction %bool None {{%\w+}} -;CHECK: OpFunctionEnd -)"; -// clang-format on - -using InstBuffAddrTest = PassTest<::testing::Test>; - -TEST_F(InstBuffAddrTest, InstPhysicalStorageBufferStore) { - // #version 450 - // #extension GL_EXT_buffer_reference : enable - // - // layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct; - // - // layout(set = 0, binding = 0) 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 defs = R"( -OpCapability Shader -OpCapability PhysicalStorageBufferAddresses -;CHECK: OpCapability Int64 -OpExtension "SPV_EXT_physical_storage_buffer" -;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 -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" -)"; - - // clang-format off - const std::string decorates = R"( -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 0 -OpDecorate %u_info Binding 0 -)" + kImportDeco + R"( -;CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId -)"; - - const std::string globals = R"( -%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 -;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 - - const std::string main_func = R"( -%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 -;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: OpBranch {{%\w+}} -;CHECK: {{%\w+}} = OpLabel -OpReturn -OpFunctionEnd -)"; - - // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch( - defs + decorates + globals + kImportStub + main_func, true, 23u); -} - -TEST_F(InstBuffAddrTest, InstPhysicalStorageBufferLoadAndStore) { - // #version 450 - // #extension GL_EXT_buffer_reference : enable - - // // forward reference - // layout(buffer_reference) buffer blockType; - - // layout(buffer_reference, std430, buffer_reference_align = 16) buffer - // blockType { - // int x; - // blockType next; - // }; - - // layout(std430) buffer rootBlock { - // blockType root; - // } r; - - // void main() - // { - // blockType b = r.root; - // b = b.next; - // b.x = 531; - // } - - const std::string defs = R"( -OpCapability Shader -OpCapability PhysicalStorageBufferAddresses -;CHECK: OpCapability Int64 -OpExtension "SPV_EXT_physical_storage_buffer" -OpExtension "SPV_KHR_storage_buffer_storage_class" -%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" -;CHECK: OpEntryPoint GLCompute %main "main" %gl_GlobalInvocationID -OpName %blockType "blockType" -OpMemberName %blockType 0 "x" -OpMemberName %blockType 1 "next" -OpName %rootBlock "rootBlock" -OpMemberName %rootBlock 0 "root" -OpName %r "r" -)"; - -// clang-format off - const std::string decorates = R"( -OpMemberDecorate %blockType 0 Offset 0 -OpMemberDecorate %blockType 1 Offset 8 -OpDecorate %blockType Block -OpMemberDecorate %rootBlock 0 Offset 0 -OpDecorate %rootBlock Block -OpDecorate %r DescriptorSet 0 -OpDecorate %r Binding 0 -)" + kImportDeco + R"( -;CHECK: OpDecorate %gl_GlobalInvocationID BuiltIn GlobalInvocationId -)"; - - const std::string globals = R"( -%void = OpTypeVoid -%3 = OpTypeFunction %void -OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_blockType PhysicalStorageBuffer -%int = OpTypeInt 32 1 -%blockType = OpTypeStruct %int %_ptr_PhysicalStorageBuffer_blockType -%_ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %blockType -%rootBlock = OpTypeStruct %_ptr_PhysicalStorageBuffer_blockType -%_ptr_StorageBuffer_rootBlock = OpTypePointer StorageBuffer %rootBlock -%r = OpVariable %_ptr_StorageBuffer_rootBlock StorageBuffer -%int_0 = OpConstant %int 0 -%_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer StorageBuffer %_ptr_PhysicalStorageBuffer_blockType -%int_1 = OpConstant %int 1 -%_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType = OpTypePointer PhysicalStorageBuffer %_ptr_PhysicalStorageBuffer_blockType -%int_531 = OpConstant %int 531 -%_ptr_PhysicalStorageBuffer_int = OpTypePointer PhysicalStorageBuffer %int -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%16 = OpAccessChain %_ptr_StorageBuffer__ptr_PhysicalStorageBuffer_blockType %r %int_0 -%17 = OpLoad %_ptr_PhysicalStorageBuffer_blockType %16 -%21 = OpAccessChain %_ptr_PhysicalStorageBuffer__ptr_PhysicalStorageBuffer_blockType %17 %int_1 -%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: {{%\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 -)"; - // clang-format on - - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch( - defs + decorates + globals + kImportStub + main_func, true, 23u); -} - -TEST_F(InstBuffAddrTest, StructLoad) { - // #version 450 - // #extension GL_EXT_buffer_reference : enable - // #extension GL_ARB_gpu_shader_int64 : enable - // struct Test { - // float a; - // }; - // - // layout(buffer_reference, std430, buffer_reference_align = 16) buffer - // TestBuffer { Test test; }; - // - // Test GetTest(uint64_t ptr) { - // return TestBuffer(ptr).test; - // } - // - // void main() { - // GetTest(0xe0000000); - // } - - const std::string defs = - R"( -OpCapability Shader -OpCapability Int64 -OpCapability PhysicalStorageBufferAddresses -;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" %gl_FragCoord -OpExecutionMode %main OriginUpperLeft -OpSource GLSL 450 -OpSourceExtension "GL_ARB_gpu_shader_int64" -OpSourceExtension "GL_EXT_buffer_reference" -OpName %main "main" -OpName %Test "Test" -OpMemberName %Test 0 "a" -OpName %Test_0 "Test" -OpMemberName %Test_0 0 "a" -OpName %TestBuffer "TestBuffer" -OpMemberName %TestBuffer 0 "test" -)"; - - // clang-format off - const std::string decorates = R"( -OpMemberDecorate %Test_0 0 Offset 0 -OpMemberDecorate %TestBuffer 0 Offset 0 -OpDecorate %TestBuffer Block -)" + kImportDeco + R"( -;CHECK: OpDecorate %gl_FragCoord BuiltIn FragCoord -)"; - - const std::string globals = R"( -%void = OpTypeVoid -%3 = OpTypeFunction %void -%ulong = OpTypeInt 64 0 -%float = OpTypeFloat 32 -%Test = OpTypeStruct %float -OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffer -%Test_0 = OpTypeStruct %float -%TestBuffer = OpTypeStruct %Test_0 -%_ptr_PhysicalStorageBuffer_TestBuffer = OpTypePointer PhysicalStorageBuffer %TestBuffer -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_PhysicalStorageBuffer_Test_0 = OpTypePointer PhysicalStorageBuffer %Test_0 -%ulong_18446744073172680704 = OpConstant %ulong 18446744073172680704 -;CHECK: {{%\w+}} = OpConstantNull %Test_0 -)"; - - 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+}} = 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]] -OpReturn -OpFunctionEnd -)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch( - defs + decorates + globals + kImportStub + main_func, true); -} - -TEST_F(InstBuffAddrTest, PaddedStructLoad) { - // #version 450 - // #extension GL_EXT_buffer_reference : enable - // #extension GL_ARB_gpu_shader_int64 : enable - // struct Test { - // uvec3 pad_1; // Offset 0 Size 12 - // double pad_2; // Offset 16 Size 8 (alignment requirement) - // float a; // Offset 24 Size 4 - // }; // Total Size 28 - // - // layout(buffer_reference, std430, buffer_reference_align = 16) buffer - // TestBuffer { Test test; }; - // - // Test GetTest(uint64_t ptr) { - // return TestBuffer(ptr).test; - // } - // - // void main() { - // GetTest(0xe0000000); - // } - - const std::string defs = - R"( -OpCapability Shader -OpCapability Float64 -OpCapability Int64 -OpCapability PhysicalStorageBufferAddresses -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel PhysicalStorageBuffer64 GLSL450 -OpEntryPoint Vertex %main "main" -OpSource GLSL 450 -OpSourceExtension "GL_ARB_gpu_shader_int64" -OpSourceExtension "GL_EXT_buffer_reference" -OpName %main "main" -OpName %Test "Test" -OpMemberName %Test 0 "pad_1" -OpMemberName %Test 1 "pad_2" -OpMemberName %Test 2 "a" -OpName %GetTest_u641_ "GetTest(u641;" -OpName %ptr "ptr" -OpName %Test_0 "Test" -OpMemberName %Test_0 0 "pad_1" -OpMemberName %Test_0 1 "pad_2" -OpMemberName %Test_0 2 "a" -OpName %TestBuffer "TestBuffer" -OpMemberName %TestBuffer 0 "test" -OpName %param "param" -)"; - - // clang-format off - const std::string decorates = R"( -OpDecorate %TestBuffer Block -OpMemberDecorate %Test_0 0 Offset 0 -OpMemberDecorate %Test_0 1 Offset 16 -OpMemberDecorate %Test_0 2 Offset 24 -OpMemberDecorate %TestBuffer 0 Offset 0 -)" + kImportDeco + R"( -;CHECK: OpDecorate %gl_VertexIndex BuiltIn VertexIndex -;CHECK: OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex -)"; - - const std::string globals = R"( -%void = OpTypeVoid -%3 = OpTypeFunction %void -%ulong = OpTypeInt 64 0 -%_ptr_Function_ulong = OpTypePointer Function %ulong -%uint = OpTypeInt 32 0 -%v3uint = OpTypeVector %uint 3 -%double = OpTypeFloat 64 -%float = OpTypeFloat 32 -%Test = OpTypeStruct %v3uint %double %float -%13 = OpTypeFunction %Test %_ptr_Function_ulong -OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_TestBuffer PhysicalStorageBuffer -%Test_0 = OpTypeStruct %v3uint %double %float -%TestBuffer = OpTypeStruct %Test_0 -%_ptr_PhysicalStorageBuffer_TestBuffer = OpTypePointer PhysicalStorageBuffer %TestBuffer -%int = OpTypeInt 32 1 -%int_0 = OpConstant %int 0 -%_ptr_PhysicalStorageBuffer_Test_0 = OpTypePointer PhysicalStorageBuffer %Test_0 -%_ptr_Function_Test = OpTypePointer Function %Test -%ulong_18446744073172680704 = OpConstant %ulong 18446744073172680704 -;CHECK: {{%\w+}} = OpConstantNull %Test_0 -)"; - - const std::string main_func = R"( -%main = OpFunction %void None %3 -%5 = OpLabel -%param = OpVariable %_ptr_Function_ulong Function -OpStore %param %ulong_18446744073172680704 -%35 = OpFunctionCall %Test %GetTest_u641_ %param -OpReturn -OpFunctionEnd -%GetTest_u641_ = OpFunction %Test None %13 -%ptr = OpFunctionParameter %_ptr_Function_ulong -%16 = OpLabel -%28 = OpVariable %_ptr_Function_Test Function -%17 = OpLoad %ulong %ptr -%21 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_TestBuffer %17 -%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+}} = 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 - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch( - defs + decorates + globals + kImportStub + main_func, true); -} - -TEST_F(InstBuffAddrTest, DeviceBufferAddressOOB) { - // #version 450 - // #extension GL_EXT_buffer_reference : enable - // layout(buffer_reference, buffer_reference_align = 16) buffer bufStruct; - // layout(set = 0, binding = 0) uniform ufoo { - // bufStruct data; - // int nWrites; - // } u_info; - // layout(buffer_reference, std140) buffer bufStruct { - // int a[4]; - // }; - // void main() { - // for (int i=0; i < u_info.nWrites; ++i) { - // u_info.data.a[i] = 0xdeadca71; - // } - // } - - // clang-format off - const std::string text = R"( -OpCapability Shader -OpCapability PhysicalStorageBufferAddresses -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel PhysicalStorageBuffer64 GLSL450 -OpEntryPoint Vertex %main "main" %u_info -;CHECK: OpEntryPoint Vertex %main "main" %u_info %gl_VertexIndex %gl_InstanceIndex -OpSource GLSL 450 -OpSourceExtension "GL_EXT_buffer_reference" -OpName %main "main" -OpName %i "i" -OpName %ufoo "ufoo" -OpMemberName %ufoo 0 "data" -OpMemberName %ufoo 1 "nWrites" -OpName %bufStruct "bufStruct" -OpMemberName %bufStruct 0 "a" -OpName %u_info "u_info" -OpMemberDecorate %ufoo 0 Offset 0 -OpMemberDecorate %ufoo 1 Offset 8 -OpDecorate %ufoo Block -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 -)" + kImportDeco + R"( -%void = OpTypeVoid -%3 = OpTypeFunction %void -%int = OpTypeInt 32 1 -%_ptr_Function_int = OpTypePointer Function %int -%int_0 = OpConstant %int 0 -OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_bufStruct PhysicalStorageBuffer -%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_bufStruct %int -%uint = OpTypeInt 32 0 -%uint_4 = OpConstant %uint 4 -%_arr_int_uint_4 = OpTypeArray %int %uint_4 -%bufStruct = OpTypeStruct %_arr_int_uint_4 -%_ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer PhysicalStorageBuffer %bufStruct -%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo -%u_info = OpVariable %_ptr_Uniform_ufoo Uniform -%int_1 = OpConstant %int 1 -%_ptr_Uniform_int = OpTypePointer Uniform %int -%bool = OpTypeBool -%_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_bufStruct -%int_n559035791 = OpConstant %int -559035791 -%_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 -OpBranch %10 -%10 = OpLabel -OpLoopMerge %12 %13 None -OpBranch %14 -%14 = OpLabel -%15 = OpLoad %int %i -%26 = OpAccessChain %_ptr_Uniform_int %u_info %int_1 -%27 = OpLoad %int %26 -%29 = OpSLessThan %bool %15 %27 -OpBranchConditional %29 %11 %12 -%11 = OpLabel -%31 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_bufStruct %u_info %int_0 -%32 = OpLoad %_ptr_PhysicalStorageBuffer_bufStruct %31 -%33 = OpLoad %int %i -%36 = OpAccessChain %_ptr_PhysicalStorageBuffer_int %32 %int_0 %33 -OpStore %36 %int_n559035791 Aligned 16 -;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 %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 -%13 = OpLabel -%37 = OpLoad %int %i -%38 = OpIAdd %int %37 %int_1 -OpStore %i %38 -OpBranch %10 -%12 = OpLabel -OpReturn -OpFunctionEnd)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - SinglePassRunAndMatch(text, true, 23); -} - -TEST_F(InstBuffAddrTest, UVec3ScalarAddressOOB) { - // clang-format off - // #version 450 - // #extension GL_EXT_buffer_reference : enable - // #extension GL_EXT_scalar_block_layout : enable - // layout(buffer_reference, std430, scalar) readonly buffer IndexBuffer - // { - // uvec3 indices[]; - // }; - // layout(set = 0, binding = 0) uniform ufoo { - // IndexBuffer data; - // int nReads; - // } u_info; - // void main() { - // uvec3 readvec; - // for (int i=0; i < u_info.nReads; ++i) { - // readvec = u_info.data.indices[i]; - // } - // } - const std::string text = R"( -OpCapability Shader -OpCapability PhysicalStorageBufferAddresses -%1 = OpExtInstImport "GLSL.std.450" -OpMemoryModel PhysicalStorageBuffer64 GLSL450 -OpEntryPoint Vertex %main "main" %u_info -OpSource GLSL 450 -OpSourceExtension "GL_EXT_buffer_reference" -OpSourceExtension "GL_EXT_scalar_block_layout" -OpName %main "main" -OpName %i "i" -OpName %ufoo "ufoo" -OpMemberName %ufoo 0 "data" -OpMemberName %ufoo 1 "nReads" -OpName %IndexBuffer "IndexBuffer" -OpMemberName %IndexBuffer 0 "indices" -OpName %u_info "u_info" -OpName %readvec "readvec" -OpMemberDecorate %ufoo 0 Offset 0 -OpMemberDecorate %ufoo 1 Offset 8 -OpDecorate %ufoo Block -OpDecorate %_runtimearr_v3uint ArrayStride 12 -OpMemberDecorate %IndexBuffer 0 NonWritable -OpMemberDecorate %IndexBuffer 0 Offset 0 -OpDecorate %IndexBuffer Block -OpDecorate %u_info DescriptorSet 0 -OpDecorate %u_info Binding 0 -)" + kImportDeco + R"( -%void = OpTypeVoid -%3 = OpTypeFunction %void -%int = OpTypeInt 32 1 -%_ptr_Function_int = OpTypePointer Function %int -%int_0 = OpConstant %int 0 -OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_IndexBuffer PhysicalStorageBuffer -%ufoo = OpTypeStruct %_ptr_PhysicalStorageBuffer_IndexBuffer %int -%uint = OpTypeInt 32 0 -%v3uint = OpTypeVector %uint 3 -%_runtimearr_v3uint = OpTypeRuntimeArray %v3uint -%IndexBuffer = OpTypeStruct %_runtimearr_v3uint -%_ptr_PhysicalStorageBuffer_IndexBuffer = OpTypePointer PhysicalStorageBuffer %IndexBuffer -%_ptr_Uniform_ufoo = OpTypePointer Uniform %ufoo -%u_info = OpVariable %_ptr_Uniform_ufoo Uniform -%int_1 = OpConstant %int 1 -%_ptr_Uniform_int = OpTypePointer Uniform %int -%bool = OpTypeBool -)" + kImportStub + R"( -%_ptr_Function_v3uint = OpTypePointer Function %v3uint -%_ptr_Uniform__ptr_PhysicalStorageBuffer_IndexBuffer = OpTypePointer Uniform %_ptr_PhysicalStorageBuffer_IndexBuffer -%_ptr_PhysicalStorageBuffer_v3uint = OpTypePointer PhysicalStorageBuffer %v3uint -%main = OpFunction %void None %3 -%5 = OpLabel -%i = OpVariable %_ptr_Function_int Function -%readvec = OpVariable %_ptr_Function_v3uint Function -OpStore %i %int_0 -OpBranch %10 -%10 = OpLabel -OpLoopMerge %12 %13 None -OpBranch %14 -%14 = OpLabel -%15 = OpLoad %int %i -%26 = OpAccessChain %_ptr_Uniform_int %u_info %int_1 -%27 = OpLoad %int %26 -%29 = OpSLessThan %bool %15 %27 -OpBranchConditional %29 %11 %12 -%11 = OpLabel -%33 = OpAccessChain %_ptr_Uniform__ptr_PhysicalStorageBuffer_IndexBuffer %u_info %int_0 -%34 = OpLoad %_ptr_PhysicalStorageBuffer_IndexBuffer %33 -%35 = OpLoad %int %i -%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: {{%\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 -%40 = OpIAdd %int %39 %int_1 -OpStore %i %40 -OpBranch %10 -%12 = OpLabel -OpReturn -OpFunctionEnd -)"; - // clang-format on - - SetTargetEnv(SPV_ENV_UNIVERSAL_1_4); - SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); - ValidatorOptions()->scalar_block_layout = true; - SinglePassRunAndMatch(text, true, 23); -} - -} // namespace -} // namespace opt -} // namespace spvtools From 199038f10cbe56bf7cbfeb5472eb0a25af2f09f5 Mon Sep 17 00:00:00 2001 From: Sven van Haastregt Date: Fri, 10 May 2024 21:49:10 +0200 Subject: [PATCH 433/523] spirv-val: Validate MemoryAccessMask of OpCooperativeMatrixStoreKHR (#5668) Reject `OpCooperativeMatrixStoreKHR` with a `MakePointerVisibleKHR` MemoryAccess operand, as `MakePointerVisibleKHR` is not supposed to be used with store operations. The `CoopMatKHRStoreMemoryAccessFail` test failed to catch this because it used the helper function `GenCoopMatLoadStoreShader` which generates `...NV` instead of `...KHR` instructions. Add a new helper function to generate similar shaders for the KHR extension, as the NV and KHR extensions have various subtle differences that makes parameterizing the original helper function non-trivial. Signed-off-by: Sven van Haastregt --- source/val/validate_memory.cpp | 3 +- test/val/val_memory_test.cpp | 208 +++++++++++++++++++++++++++++++-- 2 files changed, 201 insertions(+), 10 deletions(-) diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index 2d6715f423..ef6676fb7b 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -349,7 +349,8 @@ spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst, if (mask & uint32_t(spv::MemoryAccessMask::MakePointerVisibleKHR)) { if (inst->opcode() == spv::Op::OpStore || - inst->opcode() == spv::Op::OpCooperativeMatrixStoreNV) { + inst->opcode() == spv::Op::OpCooperativeMatrixStoreNV || + inst->opcode() == spv::Op::OpCooperativeMatrixStoreKHR) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "MakePointerVisibleKHR cannot be used with OpStore."; } diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp index 74a17e9846..dfddc98725 100644 --- a/test/val/val_memory_test.cpp +++ b/test/val/val_memory_test.cpp @@ -2348,19 +2348,209 @@ OpFunctionEnd)"; EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } +std::string GenCoopMatLoadStoreShaderKHR(const std::string& storeMemoryAccess, + const std::string& loadMemoryAccess) { + std::string s = R"( +OpCapability Shader +OpCapability GroupNonUniform +OpCapability VulkanMemoryModelKHR +OpCapability CooperativeMatrixKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpExtension "SPV_KHR_cooperative_matrix" +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical VulkanKHR +OpEntryPoint GLCompute %4 "main" %11 %21 +OpExecutionMode %4 LocalSize 1 1 1 +OpDecorate %11 BuiltIn SubgroupId +OpDecorate %21 BuiltIn WorkgroupId +OpDecorate %74 ArrayStride 4 +OpMemberDecorate %75 0 Offset 0 +OpDecorate %75 Block +OpDecorate %77 DescriptorSet 0 +OpDecorate %77 Binding 0 +OpDecorate %92 ArrayStride 4 +OpMemberDecorate %93 0 Offset 0 +OpDecorate %93 Block +OpDecorate %95 DescriptorSet 0 +OpDecorate %95 Binding 1 +OpDecorate %102 ArrayStride 4 +OpMemberDecorate %103 0 Offset 0 +OpDecorate %103 Block +OpDecorate %105 DescriptorSet 0 +OpDecorate %105 Binding 2 +OpDecorate %117 ArrayStride 4 +OpMemberDecorate %118 0 Offset 0 +OpDecorate %118 Block +OpDecorate %120 DescriptorSet 0 +OpDecorate %120 Binding 3 +OpDecorate %123 SpecId 2 +OpDecorate %124 SpecId 3 +OpDecorate %125 SpecId 4 +OpDecorate %126 SpecId 5 +OpDecorate %127 SpecId 0 +OpDecorate %128 SpecId 1 +OpDecorate %129 BuiltIn WorkgroupSize +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%6 = OpTypeInt 32 0 +%7 = OpTypeVector %6 2 +%8 = OpTypePointer Function %7 +%10 = OpTypePointer Input %6 +%11 = OpVariable %10 Input +%13 = OpConstant %6 2 +%19 = OpTypeVector %6 3 +%20 = OpTypePointer Input %19 +%21 = OpVariable %20 Input +%27 = OpConstantComposite %7 %13 %13 +%31 = OpTypePointer Function %6 +%33 = OpConstant %6 1024 +%34 = OpConstant %6 1 +%38 = OpConstant %6 8 +%39 = OpConstant %6 0 +%68 = OpTypeFloat 32 +%69 = OpConstant %6 16 +%70 = OpConstant %6 3 +%71 = OpTypeCooperativeMatrixKHR %68 %70 %69 %38 %39 +%72 = OpTypePointer Function %71 +%74 = OpTypeRuntimeArray %68 +%75 = OpTypeStruct %74 +%76 = OpTypePointer StorageBuffer %75 +%77 = OpVariable %76 StorageBuffer +%78 = OpTypeInt 32 1 +%79 = OpConstant %78 0 +%81 = OpConstant %6 5 +%82 = OpTypePointer StorageBuffer %68 +%84 = OpConstant %6 64 +%88 = OpTypePointer Private %71 +%89 = OpVariable %88 Private +%92 = OpTypeRuntimeArray %68 +%93 = OpTypeStruct %92 +%94 = OpTypePointer StorageBuffer %93 +%95 = OpVariable %94 StorageBuffer +%99 = OpVariable %88 Private +%102 = OpTypeRuntimeArray %68 +%103 = OpTypeStruct %102 +%104 = OpTypePointer StorageBuffer %103 +%105 = OpVariable %104 StorageBuffer +%109 = OpVariable %88 Private +%111 = OpVariable %88 Private +%112 = OpSpecConstantOp %6 CooperativeMatrixLengthKHR %71 +%113 = OpSpecConstantOp %78 IAdd %112 %79 +%117 = OpTypeRuntimeArray %68 +%118 = OpTypeStruct %117 +%119 = OpTypePointer StorageBuffer %118 +%120 = OpVariable %119 StorageBuffer +%123 = OpSpecConstant %78 1 +%124 = OpSpecConstant %78 1 +%125 = OpSpecConstant %78 1 +%126 = OpSpecConstant %78 1 +%127 = OpSpecConstant %6 1 +%128 = OpSpecConstant %6 1 +%129 = OpSpecConstantComposite %19 %127 %128 %34 +%4 = OpFunction %2 None %3 +%5 = OpLabel +%9 = OpVariable %8 Function +%18 = OpVariable %8 Function +%32 = OpVariable %31 Function +%44 = OpVariable %31 Function +%52 = OpVariable %31 Function +%60 = OpVariable %31 Function +%73 = OpVariable %72 Function +%91 = OpVariable %72 Function +%101 = OpVariable %72 Function +%12 = OpLoad %6 %11 +%14 = OpUMod %6 %12 %13 +%15 = OpLoad %6 %11 +%16 = OpUDiv %6 %15 %13 +%17 = OpCompositeConstruct %7 %14 %16 +OpStore %9 %17 +%22 = OpLoad %19 %21 +%23 = OpVectorShuffle %7 %22 %22 0 1 +%24 = OpCompositeExtract %6 %23 0 +%25 = OpCompositeExtract %6 %23 1 +%26 = OpCompositeConstruct %7 %24 %25 +%28 = OpIMul %7 %26 %27 +%29 = OpLoad %7 %9 +%30 = OpIAdd %7 %28 %29 +OpStore %18 %30 +%35 = OpAccessChain %31 %18 %34 +%36 = OpLoad %6 %35 +%37 = OpIMul %6 %33 %36 +%40 = OpAccessChain %31 %18 %39 +%41 = OpLoad %6 %40 +%42 = OpIMul %6 %38 %41 +%43 = OpIAdd %6 %37 %42 +OpStore %32 %43 +%45 = OpAccessChain %31 %18 %34 +%46 = OpLoad %6 %45 +%47 = OpIMul %6 %33 %46 +%48 = OpAccessChain %31 %18 %39 +%49 = OpLoad %6 %48 +%50 = OpIMul %6 %38 %49 +%51 = OpIAdd %6 %47 %50 +OpStore %44 %51 +%53 = OpAccessChain %31 %18 %34 +%54 = OpLoad %6 %53 +%55 = OpIMul %6 %33 %54 +%56 = OpAccessChain %31 %18 %39 +%57 = OpLoad %6 %56 +%58 = OpIMul %6 %38 %57 +%59 = OpIAdd %6 %55 %58 +OpStore %52 %59 +%61 = OpAccessChain %31 %18 %34 +%62 = OpLoad %6 %61 +%63 = OpIMul %6 %33 %62 +%64 = OpAccessChain %31 %18 %39 +%65 = OpLoad %6 %64 +%66 = OpIMul %6 %38 %65 +%67 = OpIAdd %6 %63 %66 +OpStore %60 %67 +%80 = OpLoad %6 %32 +%83 = OpAccessChain %82 %77 %79 %80 +%87 = OpCooperativeMatrixLoadKHR %71 %83 %39 %84 )" + + loadMemoryAccess + R"( %81 +OpStore %73 %87 +%90 = OpLoad %71 %73 +OpStore %89 %90 +%96 = OpLoad %6 %44 +%97 = OpAccessChain %82 %95 %79 %96 +%98 = OpCooperativeMatrixLoadKHR %71 %97 %39 %84 MakePointerVisibleKHR|NonPrivatePointerKHR %81 +OpStore %91 %98 +%100 = OpLoad %71 %91 +OpStore %99 %100 +%106 = OpLoad %6 %52 +%107 = OpAccessChain %82 %105 %79 %106 +%108 = OpCooperativeMatrixLoadKHR %71 %107 %39 %84 MakePointerVisibleKHR|NonPrivatePointerKHR %81 +OpStore %101 %108 +%110 = OpLoad %71 %101 +OpStore %109 %110 +%114 = OpConvertSToF %68 %113 +%115 = OpCompositeConstruct %71 %114 +OpStore %111 %115 +%116 = OpLoad %71 %111 +%121 = OpLoad %6 %60 +%122 = OpAccessChain %82 %120 %79 %121 +OpCooperativeMatrixStoreKHR %122 %116 %39 %84 )" + storeMemoryAccess + R"( %81 +OpReturn +OpFunctionEnd +)"; + + return s; +} + TEST_F(ValidateMemory, CoopMatKHRLoadStoreSuccess) { - std::string spirv = - GenCoopMatLoadStoreShader("MakePointerAvailableKHR|NonPrivatePointerKHR", - "MakePointerVisibleKHR|NonPrivatePointerKHR"); + std::string spirv = GenCoopMatLoadStoreShaderKHR( + "MakePointerAvailableKHR|NonPrivatePointerKHR", + "MakePointerVisibleKHR|NonPrivatePointerKHR"); CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); } TEST_F(ValidateMemory, CoopMatKHRStoreMemoryAccessFail) { - std::string spirv = - GenCoopMatLoadStoreShader("MakePointerVisibleKHR|NonPrivatePointerKHR", - "MakePointerVisibleKHR|NonPrivatePointerKHR"); + std::string spirv = GenCoopMatLoadStoreShaderKHR( + "MakePointerVisibleKHR|NonPrivatePointerKHR", + "MakePointerVisibleKHR|NonPrivatePointerKHR"); CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); @@ -2369,9 +2559,9 @@ TEST_F(ValidateMemory, CoopMatKHRStoreMemoryAccessFail) { } TEST_F(ValidateMemory, CoopMatKHRLoadMemoryAccessFail) { - std::string spirv = - GenCoopMatLoadStoreShader("MakePointerAvailableKHR|NonPrivatePointerKHR", - "MakePointerAvailableKHR|NonPrivatePointerKHR"); + std::string spirv = GenCoopMatLoadStoreShaderKHR( + "MakePointerAvailableKHR|NonPrivatePointerKHR", + "MakePointerAvailableKHR|NonPrivatePointerKHR"); CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); From ccf3e3c1035189bbb50793d1e249a2c0ba3388a3 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Tue, 14 May 2024 15:13:54 -0400 Subject: [PATCH 434/523] Improve matrix layout validation (#5662) * Check for matrix decorations on arrays of matrices * MatrixStide, RowMajor and ColMajor can be applied to matrix or arrays of matrix members * Check that matrix stride satisfies alignment in arrays --- source/val/validate_decorations.cpp | 19 ++- test/val/val_decoration_test.cpp | 226 ++++++++++++++++++++++++++++ 2 files changed, 244 insertions(+), 1 deletion(-) diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp index 0a7df65811..811c0e67c5 100644 --- a/source/val/validate_decorations.cpp +++ b/source/val/validate_decorations.cpp @@ -623,6 +623,14 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, seen[next_offset % 16] = true; } + } else if (spv::Op::OpTypeMatrix == element_inst->opcode()) { + // Matrix stride would be on the array element in the struct. + const auto stride = constraint.matrix_stride; + if (!IsAlignedTo(stride, alignment)) { + return fail(memberIdx) + << "is a matrix with stride " << stride + << " not satisfying alignment to " << alignment; + } } // Proceed to the element in case it is an array. @@ -675,7 +683,16 @@ bool checkForRequiredDecoration(uint32_t struct_id, spv::Op type, ValidationState_t& vstate) { const auto& members = getStructMembers(struct_id, vstate); for (size_t memberIdx = 0; memberIdx < members.size(); memberIdx++) { - const auto id = members[memberIdx]; + auto id = members[memberIdx]; + if (type == spv::Op::OpTypeMatrix) { + // Matrix decorations also apply to arrays of matrices. + auto memberInst = vstate.FindDef(id); + while (memberInst->opcode() == spv::Op::OpTypeArray || + memberInst->opcode() == spv::Op::OpTypeRuntimeArray) { + memberInst = vstate.FindDef(memberInst->GetOperandAs(1u)); + } + id = memberInst->id(); + } if (type != vstate.FindDef(id)->opcode()) continue; bool found = false; for (auto& dec : vstate.id_decorations(id)) { diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp index ba0e95976c..b525477cc6 100644 --- a/test/val/val_decoration_test.cpp +++ b/test/val/val_decoration_test.cpp @@ -9444,6 +9444,232 @@ OpFunctionEnd "contains an array with stride 0, but with an element size of 4")); } +TEST_F(ValidateDecorations, MatrixArrayMissingMajorness) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpMemberDecorate %block 0 MatrixStride 16 +OpDecorate %array ArrayStride 32 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%int_2 = OpConstant %int 2 +%vec = OpTypeVector %float 2 +%mat = OpTypeMatrix %vec 2 +%array = OpTypeArray %mat %int_2 +%block = OpTypeStruct %array +%ptr = OpTypePointer Uniform %block +%var = OpVariable %ptr Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "must be explicitly laid out with RowMajor or ColMajor decorations")); +} + +TEST_F(ValidateDecorations, MatrixArrayMissingStride) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpMemberDecorate %block 0 ColMajor +OpDecorate %array ArrayStride 32 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%int_2 = OpConstant %int 2 +%vec = OpTypeVector %float 2 +%mat = OpTypeMatrix %vec 2 +%array = OpTypeArray %mat %int_2 +%block = OpTypeStruct %array +%ptr = OpTypePointer Uniform %block +%var = OpVariable %ptr Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("must be explicitly laid out with MatrixStride decorations")); +} + +TEST_F(ValidateDecorations, MatrixArrayBadStride) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpMemberDecorate %block 0 ColMajor +OpMemberDecorate %block 0 MatrixStride 8 +OpDecorate %array ArrayStride 32 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%int_2 = OpConstant %int 2 +%vec = OpTypeVector %float 2 +%mat = OpTypeMatrix %vec 2 +%array = OpTypeArray %mat %int_2 +%block = OpTypeStruct %array +%ptr = OpTypePointer Uniform %block +%var = OpVariable %ptr Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("is a matrix with stride 8 not satisfying alignment to 16")); +} + +TEST_F(ValidateDecorations, MatrixArrayArrayMissingMajorness) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpMemberDecorate %block 0 MatrixStride 16 +OpDecorate %array ArrayStride 32 +OpDecorate %rta ArrayStride 64 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%int_2 = OpConstant %int 2 +%vec = OpTypeVector %float 2 +%mat = OpTypeMatrix %vec 2 +%array = OpTypeArray %mat %int_2 +%rta = OpTypeRuntimeArray %array +%block = OpTypeStruct %rta +%ptr = OpTypePointer StorageBuffer %block +%var = OpVariable %ptr StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "must be explicitly laid out with RowMajor or ColMajor decorations")); +} + +TEST_F(ValidateDecorations, MatrixArrayArrayMissingStride) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpMemberDecorate %block 0 ColMajor +OpDecorate %array ArrayStride 32 +OpDecorate %rta ArrayStride 64 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%int_2 = OpConstant %int 2 +%vec = OpTypeVector %float 2 +%mat = OpTypeMatrix %vec 2 +%array = OpTypeArray %mat %int_2 +%rta = OpTypeRuntimeArray %array +%block = OpTypeStruct %rta +%ptr = OpTypePointer StorageBuffer %block +%var = OpVariable %ptr StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("must be explicitly laid out with MatrixStride decorations")); +} + +TEST_F(ValidateDecorations, MatrixArrayArrayBadStride) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpMemberDecorate %block 0 ColMajor +OpMemberDecorate %block 0 MatrixStride 8 +OpDecorate %array ArrayStride 32 +OpDecorate %a ArrayStride 64 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%int = OpTypeInt 32 0 +%int_2 = OpConstant %int 2 +%vec = OpTypeVector %float 2 +%mat = OpTypeMatrix %vec 2 +%array = OpTypeArray %mat %int_2 +%a = OpTypeArray %array %int_2 +%block = OpTypeStruct %a +%ptr = OpTypePointer Uniform %block +%var = OpVariable %ptr Uniform +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("is a matrix with stride 8 not satisfying alignment to 16")); +} + } // namespace } // namespace val } // namespace spvtools From 14fe558c07e3f3e99e1647b6d250bda73f3f8c62 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 May 2024 10:09:12 -0400 Subject: [PATCH 435/523] --- (#5679) updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: lukka/get-cmake dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - 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/autoroll.yml | 2 +- .github/workflows/bazel.yml | 2 +- .github/workflows/ios.yml | 4 ++-- .github/workflows/release.yml | 2 +- .github/workflows/scorecard.yml | 6 +++--- .github/workflows/wasm.yml | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/autoroll.yml b/.github/workflows/autoroll.yml index 3954928d99..c5be7f1147 100644 --- a/.github/workflows/autoroll.yml +++ b/.github/workflows/autoroll.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 # 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 ee8a9d531e..b83d3324fd 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -18,7 +18,7 @@ jobs: runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: fetch-depth: '0' - name: Download dependencies diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 87ccd2d169..cfd6c16de1 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -11,8 +11,8 @@ jobs: matrix: os: [ macos-12, macos-13 ] steps: - - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - - uses: lukka/get-cmake@4931ab1fc1604964c055eb330edb3f6b26ba0cfa # v3.29.2 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: lukka/get-cmake@c57ffe818cee3ee5f08fc1cc78c8bbede1cbbe59 # v3.29.3 - name: Download dependencies run: python3 utils/git-sync-deps # NOTE: The MacOS SDK ships universal binaries. CI should reflect this. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 22cf61e963..36fdf11eb9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: prepare-release-job: runs-on: ubuntu-latest steps: - - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - 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 efda65dbbc..62561addb8 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -23,12 +23,12 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 + uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3 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@d39d31e687223d841ef683f52467bd88e9b21c14 # v3.25.3 + uses: github/codeql-action/upload-sarif@9fdb3e49720b44c48891d036bb502feb25684276 # v3.25.6 with: sarif_file: results.sarif diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 5eeec6109d..5f0818ca3d 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: fetch-depth: '0' - name: Build web From e4b1a48aab4df0b549568f24053b9a383616c4ef Mon Sep 17 00:00:00 2001 From: Zheng Shaokun Date: Tue, 21 May 2024 23:34:06 +0800 Subject: [PATCH 436/523] Use raw string to avoid unintended escapes in regex (#5676) --- utils/git-sync-deps | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/git-sync-deps b/utils/git-sync-deps index 6549afb1e6..21bf2bc743 100755 --- a/utils/git-sync-deps +++ b/utils/git-sync-deps @@ -78,7 +78,7 @@ def git_executable(): minor=None try: version_info = subprocess.check_output([git, '--version']).decode('utf-8') - match = re.search("^git version (\d+)\.(\d+)",version_info) + match = re.search(r"^git version (\d+)\.(\d+)",version_info) print("Using {}".format(version_info)) if match: major = int(match.group(1)) From e2646f5e9562e738daed967d48aae1e65225c955 Mon Sep 17 00:00:00 2001 From: Sven van Haastregt Date: Tue, 21 May 2024 19:02:17 +0200 Subject: [PATCH 437/523] spirv-val: Consider target env for OpReadClockKHR scope (#5681) The Scope operand of `OpReadClockKHR` was always validated using the Vulkan environment rules, which only allow `Subgroup` or `Device`. For the OpenCL environment, `Workgroup` is also a valid Scope, so `Workgroup` should not be rejected in the universal environment. Guard the existing Scope check behind `spvIsVulkanEnv` and add a new Scope check for the OpenCL environment. Signed-off-by: Sven van Haastregt --- source/val/validate_misc.cpp | 20 ++++++++++--- test/val/val_misc_test.cpp | 55 +++++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 5 deletions(-) diff --git a/source/val/validate_misc.cpp b/source/val/validate_misc.cpp index d71fd2d261..a404134b6e 100644 --- a/source/val/validate_misc.cpp +++ b/source/val/validate_misc.cpp @@ -50,10 +50,22 @@ spv_result_t ValidateShaderClock(ValidationState_t& _, bool is_int32 = false, is_const_int32 = false; uint32_t value = 0; std::tie(is_int32, is_const_int32, value) = _.EvalInt32IfConst(scope); - if (is_const_int32 && spv::Scope(value) != spv::Scope::Subgroup && - spv::Scope(value) != spv::Scope::Device) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << _.VkErrorID(4652) << "Scope must be Subgroup or Device"; + if (is_const_int32) { + spv::Scope scope_val{value}; + if (spvIsVulkanEnv(_.context()->target_env)) { + if (scope_val != spv::Scope::Subgroup && + scope_val != spv::Scope::Device) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << _.VkErrorID(4652) << "Scope must be Subgroup or Device"; + } + } else if (spvIsOpenCLEnv(_.context()->target_env)) { + if (scope_val != spv::Scope::Workgroup && + scope_val != spv::Scope::Subgroup && + scope_val != spv::Scope::Device) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Scope must be Subgroup, Workgroup, or Device"; + } + } } // Result Type must be a 64 - bit unsigned integer type or diff --git a/test/val/val_misc_test.cpp b/test/val/val_misc_test.cpp index b0e46bf95c..8c1f11dfe6 100644 --- a/test/val/val_misc_test.cpp +++ b/test/val/val_misc_test.cpp @@ -222,7 +222,7 @@ OpReturn OpFunctionEnd)"; CompileSuccessfully(spirv); - EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0)); EXPECT_THAT(getDiagnosticString(), HasSubstr("Scope must be Subgroup or Device")); } @@ -251,6 +251,59 @@ OpFunctionEnd)"; HasSubstr("Scope must be Subgroup or Device")); } +std::string GenKernelClockSpirv(const std::string& scope) { + const std::string s = R"( +OpCapability Kernel +OpCapability Addresses +OpCapability Int64 +OpCapability ShaderClockKHR +OpExtension "SPV_KHR_shader_clock" +OpMemoryModel Physical32 OpenCL +OpEntryPoint Kernel %main "main" +OpExecutionMode %main ContractionOff +OpSource OpenCL_C 200000 +OpName %main "main" +OpName %time1 "time1" +%void = OpTypeVoid +%3 = OpTypeFunction %void +%ulong = OpTypeInt 64 0 +%uint = OpTypeInt 32 0 +%_ptr_Function_ulong = OpTypePointer Function %ulong +%scope = OpConstant %uint )" + + scope + R"( +%main = OpFunction %void None %3 +%5 = OpLabel +%time1 = OpVariable %_ptr_Function_ulong Function +%11 = OpReadClockKHR %ulong %scope +OpStore %time1 %11 +OpReturn +OpFunctionEnd +)"; + return s; +} + +TEST_F(ValidateMisc, KernelClockScopeDevice) { + CompileSuccessfully(GenKernelClockSpirv("1"), SPV_ENV_OPENCL_1_2); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2)); +} + +TEST_F(ValidateMisc, KernelClockScopeWorkgroup) { + CompileSuccessfully(GenKernelClockSpirv("2"), SPV_ENV_OPENCL_1_2); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2)); +} + +TEST_F(ValidateMisc, KernelClockScopeSubgroup) { + CompileSuccessfully(GenKernelClockSpirv("3"), SPV_ENV_OPENCL_1_2); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_OPENCL_1_2)); +} + +TEST_F(ValidateMisc, KernelClockScopeInvalid) { + CompileSuccessfully(GenKernelClockSpirv("0"), SPV_ENV_OPENCL_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_OPENCL_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Scope must be Subgroup, Workgroup, or Device")); +} + TEST_F(ValidateMisc, UndefVoid) { const std::string spirv = R"( OpCapability Shader From ee749f50576b164afdf02e4b116a073661ecf8ff Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Tue, 21 May 2024 22:15:30 -0400 Subject: [PATCH 438/523] Add abseil to the autoroller (#5680) The autoroller does not update abseil, and that it stopping us from updating RE2. This change will update the auto roller, then the next time it runs, we should be able to update everything. --- utils/roll_deps.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/utils/roll_deps.sh b/utils/roll_deps.sh index d19ee000e5..a62ebe9bc5 100755 --- a/utils/roll_deps.sh +++ b/utils/roll_deps.sh @@ -29,13 +29,12 @@ function ExitIfIsInterestingError() { } -dependencies=("external/effcee/" - "external/googletest/" - "external/re2/" - "external/spirv-headers/") - - -branch="origin/main" +declare -A dependency_to_branch_map +dependency_to_branch_map["external/abseil_cpp"]="origin/master" +dependency_to_branch_map["external/effcee/"]="origin/main" +dependency_to_branch_map["external/googletest/"]="origin/main" +dependency_to_branch_map["external/re2/"]="origin/main" +dependency_to_branch_map["external/spirv-headers/"]="origin/main" # This script assumes it's parent directory is the repo root. repo_path=$(dirname "$0")/.. @@ -53,7 +52,8 @@ old_head=$(git rev-parse HEAD) set +e -for dep in ${dependencies[@]}; do +for dep in ${!dependency_to_branch_map[@]}; do + branch=${dependency_to_branch_map[$dep]} echo "Rolling $dep" roll-dep --ignore-dirty-tree --roll-to="${branch}" "${dep}" ExitIfIsInterestingError $? From 336b5710a5bec2d2da95cbdd7cf20a4c67e9b51d Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 22 May 2024 13:01:26 -0400 Subject: [PATCH 439/523] Do not fold mul and adds to generate fmas (#5682) This removes the folding rules added in #4783 and #4808. They lead to poor code generation on Adreno devices when 16-bit floating point values were used. Since this change is transformation is suppose to be neutral, there is no general reason to continue doing it. I have talked to the owners of SwiftShader, and they do not mind if the transform is removed. They were the ones the requested the change in the first place. Fixes #5658 --- source/opt/folding_rules.cpp | 128 --------------------------------- test/opt/fold_test.cpp | 132 +++++------------------------------ 2 files changed, 18 insertions(+), 242 deletions(-) diff --git a/source/opt/folding_rules.cpp b/source/opt/folding_rules.cpp index 5c68e291cd..5f83669940 100644 --- a/source/opt/folding_rules.cpp +++ b/source/opt/folding_rules.cpp @@ -1459,132 +1459,6 @@ FoldingRule FactorAddMuls() { }; } -// Replaces |inst| inplace with an FMA instruction |(x*y)+a|. -void ReplaceWithFma(Instruction* inst, uint32_t x, uint32_t y, uint32_t a) { - uint32_t ext = - inst->context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); - - if (ext == 0) { - inst->context()->AddExtInstImport("GLSL.std.450"); - ext = inst->context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); - assert(ext != 0 && - "Could not add the GLSL.std.450 extended instruction set"); - } - - std::vector operands; - operands.push_back({SPV_OPERAND_TYPE_ID, {ext}}); - operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {GLSLstd450Fma}}); - operands.push_back({SPV_OPERAND_TYPE_ID, {x}}); - operands.push_back({SPV_OPERAND_TYPE_ID, {y}}); - operands.push_back({SPV_OPERAND_TYPE_ID, {a}}); - - inst->SetOpcode(spv::Op::OpExtInst); - inst->SetInOperands(std::move(operands)); -} - -// Folds a multiple and add into an Fma. -// -// Cases: -// (x * y) + a = Fma x y a -// a + (x * y) = Fma x y a -bool MergeMulAddArithmetic(IRContext* context, Instruction* inst, - const std::vector&) { - assert(inst->opcode() == spv::Op::OpFAdd); - - if (!inst->IsFloatingPointFoldingAllowed()) { - return false; - } - - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - for (int i = 0; i < 2; i++) { - uint32_t op_id = inst->GetSingleWordInOperand(i); - Instruction* op_inst = def_use_mgr->GetDef(op_id); - - if (op_inst->opcode() != spv::Op::OpFMul) { - continue; - } - - if (!op_inst->IsFloatingPointFoldingAllowed()) { - continue; - } - - uint32_t x = op_inst->GetSingleWordInOperand(0); - uint32_t y = op_inst->GetSingleWordInOperand(1); - uint32_t a = inst->GetSingleWordInOperand((i + 1) % 2); - ReplaceWithFma(inst, x, y, a); - return true; - } - return false; -} - -// Replaces |sub| inplace with an FMA instruction |(x*y)+a| where |a| first gets -// negated if |negate_addition| is true, otherwise |x| gets negated. -void ReplaceWithFmaAndNegate(Instruction* sub, uint32_t x, uint32_t y, - uint32_t a, bool negate_addition) { - uint32_t ext = - sub->context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); - - if (ext == 0) { - sub->context()->AddExtInstImport("GLSL.std.450"); - ext = sub->context()->get_feature_mgr()->GetExtInstImportId_GLSLstd450(); - assert(ext != 0 && - "Could not add the GLSL.std.450 extended instruction set"); - } - - InstructionBuilder ir_builder( - sub->context(), sub, - IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); - - Instruction* neg = ir_builder.AddUnaryOp(sub->type_id(), spv::Op::OpFNegate, - negate_addition ? a : x); - uint32_t neg_op = neg->result_id(); // -a : -x - - std::vector operands; - operands.push_back({SPV_OPERAND_TYPE_ID, {ext}}); - operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {GLSLstd450Fma}}); - operands.push_back({SPV_OPERAND_TYPE_ID, {negate_addition ? x : neg_op}}); - operands.push_back({SPV_OPERAND_TYPE_ID, {y}}); - operands.push_back({SPV_OPERAND_TYPE_ID, {negate_addition ? neg_op : a}}); - - sub->SetOpcode(spv::Op::OpExtInst); - sub->SetInOperands(std::move(operands)); -} - -// Folds a multiply and subtract into an Fma and negation. -// -// Cases: -// (x * y) - a = Fma x y -a -// a - (x * y) = Fma -x y a -bool MergeMulSubArithmetic(IRContext* context, Instruction* sub, - const std::vector&) { - assert(sub->opcode() == spv::Op::OpFSub); - - if (!sub->IsFloatingPointFoldingAllowed()) { - return false; - } - - analysis::DefUseManager* def_use_mgr = context->get_def_use_mgr(); - for (int i = 0; i < 2; i++) { - uint32_t op_id = sub->GetSingleWordInOperand(i); - Instruction* mul = def_use_mgr->GetDef(op_id); - - if (mul->opcode() != spv::Op::OpFMul) { - continue; - } - - if (!mul->IsFloatingPointFoldingAllowed()) { - continue; - } - - uint32_t x = mul->GetSingleWordInOperand(0); - uint32_t y = mul->GetSingleWordInOperand(1); - uint32_t a = sub->GetSingleWordInOperand((i + 1) % 2); - ReplaceWithFmaAndNegate(sub, x, y, a, i == 0); - return true; - } - return false; -} - FoldingRule IntMultipleBy1() { return [](IRContext*, Instruction* inst, const std::vector& constants) { @@ -2941,7 +2815,6 @@ void FoldingRules::AddFoldingRules() { rules_[spv::Op::OpFAdd].push_back(MergeAddSubArithmetic()); rules_[spv::Op::OpFAdd].push_back(MergeGenericAddSubArithmetic()); rules_[spv::Op::OpFAdd].push_back(FactorAddMuls()); - rules_[spv::Op::OpFAdd].push_back(MergeMulAddArithmetic); rules_[spv::Op::OpFDiv].push_back(RedundantFDiv()); rules_[spv::Op::OpFDiv].push_back(ReciprocalFDiv()); @@ -2962,7 +2835,6 @@ void FoldingRules::AddFoldingRules() { rules_[spv::Op::OpFSub].push_back(MergeSubNegateArithmetic()); rules_[spv::Op::OpFSub].push_back(MergeSubAddArithmetic()); rules_[spv::Op::OpFSub].push_back(MergeSubSubArithmetic()); - rules_[spv::Op::OpFSub].push_back(MergeMulSubArithmetic); rules_[spv::Op::OpIAdd].push_back(RedundantIAdd()); rules_[spv::Op::OpIAdd].push_back(MergeAddNegateArithmetic()); diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index a4e0447c10..255449dbbf 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -7933,21 +7933,15 @@ ::testing::Values( 3, true) )); +// Issue #5658: The Adreno compiler does not handle 16-bit FMA instructions well. +// We want to avoid this by not generating FMA. We decided to never generate +// FMAs because, from a SPIR-V perspective, it is neutral. The ICD can generate +// the FMA if it wants. The simplest code is no code. INSTANTIATE_TEST_SUITE_P(FmaGenerationMatchingTest, MatchingInstructionFoldingTest, ::testing::Values( - // Test case 0: (x * y) + a = Fma(x, y, a) + // Test case 0: Don't fold (x * y) + a InstructionFoldingCase( Header() + - "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" + - "; CHECK: OpFunction\n" + - "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" + - "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" + - "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" + - "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" + - "; CHECK: OpStore {{%\\w+}} [[fma]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + @@ -7961,20 +7955,10 @@ ::testing::Values( "OpStore %a %3\n" + "OpReturn\n" + "OpFunctionEnd", - 3, true), - // Test case 1: a + (x * y) = Fma(x, y, a) + 3, false), + // Test case 1: Don't fold a + (x * y) InstructionFoldingCase( Header() + - "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" + - "; CHECK: OpFunction\n" + - "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" + - "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" + - "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" + - "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" + - "; CHECK: OpStore {{%\\w+}} [[fma]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + @@ -7988,20 +7972,10 @@ ::testing::Values( "OpStore %a %3\n" + "OpReturn\n" + "OpFunctionEnd", - 3, true), - // Test case 2: (x * y) + a = Fma(x, y, a) with vectors + 3, false), + // Test case 2: Don't fold (x * y) + a with vectors InstructionFoldingCase( Header() + - "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" + - "; CHECK: OpFunction\n" + - "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" + - "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" + - "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" + - "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" + - "; CHECK: OpStore {{%\\w+}} [[fma]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_v4float Function\n" + @@ -8015,20 +7989,10 @@ ::testing::Values( "OpStore %a %3\n" + "OpReturn\n" + "OpFunctionEnd", - 3, true), - // Test case 3: a + (x * y) = Fma(x, y, a) with vectors + 3,false), + // Test case 3: Don't fold a + (x * y) with vectors InstructionFoldingCase( Header() + - "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" + - "; CHECK: OpFunction\n" + - "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" + - "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" + - "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" + - "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" + - "; CHECK: OpStore {{%\\w+}} [[fma]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + @@ -8042,46 +8006,8 @@ ::testing::Values( "OpStore %a %3\n" + "OpReturn\n" + "OpFunctionEnd", - 3, true), - // Test 4: that the OpExtInstImport instruction is generated if it is missing. - InstructionFoldingCase( - std::string() + - "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" + - "; CHECK: OpFunction\n" + - "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" + - "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" + - "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" + - "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[la]]\n" + - "; CHECK: OpStore {{%\\w+}} [[fma]]\n" + - "OpCapability Shader\n" + - "OpMemoryModel Logical GLSL450\n" + - "OpEntryPoint Fragment %main \"main\"\n" + - "OpExecutionMode %main OriginUpperLeft\n" + - "OpSource GLSL 140\n" + - "OpName %main \"main\"\n" + - "%void = OpTypeVoid\n" + - "%void_func = OpTypeFunction %void\n" + - "%bool = OpTypeBool\n" + - "%float = OpTypeFloat 32\n" + - "%_ptr_float = OpTypePointer Function %float\n" + - "%main = OpFunction %void None %void_func\n" + - "%main_lab = OpLabel\n" + - "%x = OpVariable %_ptr_float Function\n" + - "%y = OpVariable %_ptr_float Function\n" + - "%a = OpVariable %_ptr_float Function\n" + - "%lx = OpLoad %float %x\n" + - "%ly = OpLoad %float %y\n" + - "%mul = OpFMul %float %lx %ly\n" + - "%la = OpLoad %float %a\n" + - "%3 = OpFAdd %float %mul %la\n" + - "OpStore %a %3\n" + - "OpReturn\n" + - "OpFunctionEnd", - 3, true), - // Test 5: Don't fold if the multiple is marked no contract. + 3, false), + // Test 4: Don't fold if the multiple is marked no contract. InstructionFoldingCase( std::string() + "OpCapability Shader\n" + @@ -8110,7 +8036,7 @@ ::testing::Values( "OpReturn\n" + "OpFunctionEnd", 3, false), - // Test 6: Don't fold if the add is marked no contract. + // Test 5: Don't fold if the add is marked no contract. InstructionFoldingCase( std::string() + "OpCapability Shader\n" + @@ -8139,20 +8065,9 @@ ::testing::Values( "OpReturn\n" + "OpFunctionEnd", 3, false), - // Test case 7: (x * y) - a = Fma(x, y, -a) + // Test case 6: Don't fold (x * y) - a InstructionFoldingCase( Header() + - "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" + - "; CHECK: OpFunction\n" + - "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" + - "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" + - "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" + - "; CHECK: [[na:%\\w+]] = OpFNegate {{%\\w+}} [[la]]\n" + - "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[lx]] [[ly]] [[na]]\n" + - "; CHECK: OpStore {{%\\w+}} [[fma]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + @@ -8166,21 +8081,10 @@ ::testing::Values( "OpStore %a %3\n" + "OpReturn\n" + "OpFunctionEnd", - 3, true), - // Test case 8: a - (x * y) = Fma(-x, y, a) + 3, false), + // Test case 7: Don't fold a - (x * y) InstructionFoldingCase( Header() + - "; CHECK: [[ext:%\\w+]] = OpExtInstImport \"GLSL.std.450\"\n" + - "; CHECK: OpFunction\n" + - "; CHECK: [[x:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[y:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[a:%\\w+]] = OpVariable {{%\\w+}} Function\n" + - "; CHECK: [[lx:%\\w+]] = OpLoad {{%\\w+}} [[x]]\n" + - "; CHECK: [[ly:%\\w+]] = OpLoad {{%\\w+}} [[y]]\n" + - "; CHECK: [[la:%\\w+]] = OpLoad {{%\\w+}} [[a]]\n" + - "; CHECK: [[nx:%\\w+]] = OpFNegate {{%\\w+}} [[lx]]\n" + - "; CHECK: [[fma:%\\w+]] = OpExtInst {{%\\w+}} [[ext]] Fma [[nx]] [[ly]] [[la]]\n" + - "; CHECK: OpStore {{%\\w+}} [[fma]]\n" + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + "%x = OpVariable %_ptr_float Function\n" + @@ -8194,7 +8098,7 @@ ::testing::Values( "OpStore %a %3\n" + "OpReturn\n" + "OpFunctionEnd", - 3, true) + 3, false) )); using MatchingInstructionWithNoResultFoldingTest = From 77c40bece1b8b441eee432fc9d74efbf985f777f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 23 May 2024 16:18:51 -0400 Subject: [PATCH 440/523] Roll deps * Roll external/googletest/ 5a37b517a..9b4993ca7 (8 commits) https://github.com/google/googletest/compare/5a37b517ad4a...9b4993ca7d12 Created with: roll-dep external/googletest * Roll external/abseil_cpp/ 79ca5d7aa..1a31b81c0 (602 commits) https://github.com/abseil/abseil-cpp/compare/79ca5d7aad63...1a31b81c0a46 Created with: roll-dep external/abseil_cpp * Roll external/spirv-headers/ 4f7b471f1..49a1fceb9 (3 commits) https://github.com/KhronosGroup/SPIRV-Headers/compare/4f7b471f1a66...49a1fceb9b1d Created with: roll-dep external/spirv-headers --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index 8413d1beb9..e6bf04c91d 100644 --- a/DEPS +++ b/DEPS @@ -3,17 +3,18 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': '79ca5d7aad63973c83a4962a66ab07cd623131ea', + 'abseil_revision': '1a31b81c0a467c1c8e229b9fc172a4eb0db5bd85', 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', - 'googletest_revision': '5a37b517ad4ab6738556f0284c256cae1466c5b4', + 'googletest_revision': '9b4993ca7d1279dec5c5d41ba327cb11a77bdc00', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', 're2_revision': '917047f3606d3ba9e2de0d383c3cd80c94ed732c', - 'spirv_headers_revision': '4f7b471f1a66b6d06462cd4ba57628cc0cd087d7', + + 'spirv_headers_revision': '49a1fceb9b1d087f3c25ad5ec077bb0e46231297', } deps = { From 3d24089292ed357658e3de81ddc2e72f11296e39 Mon Sep 17 00:00:00 2001 From: Spencer Fricke <115671160+spencer-lunarg@users.noreply.github.com> Date: Thu, 30 May 2024 03:38:37 +0900 Subject: [PATCH 441/523] spirv-val: Add Duplicate EntryPoint Builtin check (#5678) * spirv-val: Add Decoration::builtin() * spirv-val: Add Duplicate EntryPoint Builtin check * spirv-val: Handle Built-ins in/out of block * spirv-val: Remove extra CheckBuiltInVariable --- source/val/decoration.h | 10 + source/val/validate_builtins.cpp | 174 ++++++++-------- source/val/validate_decorations.cpp | 99 ++++++---- source/val/validation_state.cpp | 4 + test/val/val_decoration_test.cpp | 297 ++++++++++++++++++++++++++++ 5 files changed, 467 insertions(+), 117 deletions(-) diff --git a/source/val/decoration.h b/source/val/decoration.h index 384cc5755e..85755b3d04 100644 --- a/source/val/decoration.h +++ b/source/val/decoration.h @@ -55,6 +55,12 @@ namespace val { // params_ = vector { 2 } // struct_member_index_ = 2 // +// Example 4: Decoration for a Builtin: +// OpDecorate %var BuiltIn FragDepth +// dec_type_ = spv::Decoration::BuiltIn +// params_ = vector { FragDepth } +// struct_member_index_ = kInvalidMember +// class Decoration { public: enum { kInvalidMember = -1 }; @@ -68,6 +74,10 @@ class Decoration { spv::Decoration dec_type() const { return dec_type_; } std::vector& params() { return params_; } const std::vector& params() const { return params_; } + spv::BuiltIn builtin() const { + assert(dec_type_ == spv::Decoration::BuiltIn); + return spv::BuiltIn(params_[0]); + } inline bool operator<(const Decoration& rhs) const { // Note: Sort by struct_member_index_ first, then type, so look up can be diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp index a7e9942a0f..9e307fcb14 100644 --- a/source/val/validate_builtins.cpp +++ b/source/val/validate_builtins.cpp @@ -741,7 +741,7 @@ std::string BuiltInsValidator::GetReferenceDesc( ss << " which is decorated with BuiltIn "; ss << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]); + (uint32_t)decoration.builtin()); if (function_id_) { ss << " in function <" << function_id_ << ">"; if (execution_model != spv::ExecutionModel::Max) { @@ -1170,7 +1170,7 @@ spv_result_t BuiltInsValidator::ValidateNotCalledWithExecutionModel( const char* execution_model_str = _.grammar().lookupOperandName( SPV_OPERAND_TYPE_EXECUTION_MODEL, uint32_t(execution_model)); const char* built_in_str = _.grammar().lookupOperandName( - SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]); + SPV_OPERAND_TYPE_BUILT_IN, (uint32_t)decoration.builtin()); return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << (vuid < 0 ? std::string("") : _.VkErrorID(vuid)) << comment << " " << GetIdDesc(referenced_inst) << " depends on " @@ -1201,13 +1201,14 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - uint32_t operand = decoration.params()[0]; + uint32_t operand = (uint32_t)decoration.builtin(); if (spvIsVulkanEnv(_.context()->target_env)) { const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != spv::StorageClass::Max && storage_class != spv::StorageClass::Input && storage_class != spv::StorageClass::Output) { - uint32_t vuid = (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::ClipDistance) ? 4190 : 4199; + uint32_t vuid = + (decoration.builtin() == spv::BuiltIn::ClipDistance) ? 4190 : 4199; return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, @@ -1221,7 +1222,8 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( if (storage_class == spv::StorageClass::Input) { assert(function_id_ == 0); - uint32_t vuid = (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::ClipDistance) ? 4188 : 4197; + uint32_t vuid = + (decoration.builtin() == spv::BuiltIn::ClipDistance) ? 4188 : 4197; id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid, "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be " @@ -1247,7 +1249,8 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( if (storage_class == spv::StorageClass::Output) { assert(function_id_ == 0); - uint32_t vuid = (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::ClipDistance) ? 4189 : 4198; + uint32_t vuid = + (decoration.builtin() == spv::BuiltIn::ClipDistance) ? 4189 : 4198; id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid, "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be " @@ -1266,7 +1269,7 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( [this, &decoration, &referenced_from_inst]( const std::string& message) -> spv_result_t { uint32_t vuid = - (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::ClipDistance) + (decoration.builtin() == spv::BuiltIn::ClipDistance) ? 4191 : 4200; return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) @@ -1274,7 +1277,7 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( << "According to the Vulkan spec BuiltIn " << _.grammar().lookupOperandName( SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + (uint32_t)decoration.builtin()) << " variable needs to be a 32-bit float array. " << message; })) { @@ -1294,7 +1297,7 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( [this, &decoration, &referenced_from_inst]( const std::string& message) -> spv_result_t { uint32_t vuid = - (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::ClipDistance) + (decoration.builtin() == spv::BuiltIn::ClipDistance) ? 4191 : 4200; return _.diag(SPV_ERROR_INVALID_DATA, @@ -1303,7 +1306,7 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( << "According to the Vulkan spec BuiltIn " << _.grammar().lookupOperandName( SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + (uint32_t)decoration.builtin()) << " variable needs to be a 32-bit float array. " << message; })) { @@ -1315,7 +1318,7 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( [this, &decoration, &referenced_from_inst]( const std::string& message) -> spv_result_t { uint32_t vuid = - (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::ClipDistance) + (decoration.builtin() == spv::BuiltIn::ClipDistance) ? 4191 : 4200; return _.diag(SPV_ERROR_INVALID_DATA, @@ -1324,7 +1327,7 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( << "According to the Vulkan spec BuiltIn " << _.grammar().lookupOperandName( SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + (uint32_t)decoration.builtin()) << " variable needs to be a 32-bit float array. " << message; })) { @@ -1335,8 +1338,9 @@ spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference( } default: { - uint32_t vuid = - (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::ClipDistance) ? 4187 : 4196; + uint32_t vuid = (decoration.builtin() == spv::BuiltIn::ClipDistance) + ? 4187 + : 4196; return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, @@ -2542,7 +2546,7 @@ spv_result_t BuiltInsValidator::ValidateTessLevelAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - uint32_t operand = decoration.params()[0]; + uint32_t operand = (uint32_t)decoration.builtin(); if (spvIsVulkanEnv(_.context()->target_env)) { const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != spv::StorageClass::Max && @@ -2561,7 +2565,8 @@ spv_result_t BuiltInsValidator::ValidateTessLevelAtReference( if (storage_class == spv::StorageClass::Input) { assert(function_id_ == 0); - uint32_t vuid = (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::TessLevelOuter) ? 4391 : 4395; + uint32_t vuid = + (decoration.builtin() == spv::BuiltIn::TessLevelOuter) ? 4391 : 4395; id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid, "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be " @@ -2574,7 +2579,8 @@ spv_result_t BuiltInsValidator::ValidateTessLevelAtReference( if (storage_class == spv::StorageClass::Output) { assert(function_id_ == 0); - uint32_t vuid = (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::TessLevelOuter) ? 4392 : 4396; + uint32_t vuid = + (decoration.builtin() == spv::BuiltIn::TessLevelOuter) ? 4392 : 4396; id_to_at_reference_checks_[referenced_from_inst.id()].push_back(std::bind( &BuiltInsValidator::ValidateNotCalledWithExecutionModel, this, vuid, "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be " @@ -2724,12 +2730,13 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtDefinition( [this, &decoration, &inst](const std::string& message) -> spv_result_t { uint32_t vuid = - (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::Layer) ? 4276 : 4408; + (decoration.builtin() == spv::BuiltIn::Layer) ? 4276 : 4408; return _.diag(SPV_ERROR_INVALID_DATA, &inst) << _.VkErrorID(vuid) << "According to the Vulkan spec BuiltIn " << _.grammar().lookupOperandName( - SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) + SPV_OPERAND_TYPE_BUILT_IN, + (uint32_t)decoration.builtin()) << "variable needs to be a 32-bit int scalar. " << message; })) { @@ -2741,12 +2748,13 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtDefinition( [this, &decoration, &inst](const std::string& message) -> spv_result_t { uint32_t vuid = - (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::Layer) ? 4276 : 4408; + (decoration.builtin() == spv::BuiltIn::Layer) ? 4276 : 4408; return _.diag(SPV_ERROR_INVALID_DATA, &inst) << _.VkErrorID(vuid) << "According to the Vulkan spec BuiltIn " << _.grammar().lookupOperandName( - SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) + SPV_OPERAND_TYPE_BUILT_IN, + (uint32_t)decoration.builtin()) << "variable needs to be a 32-bit int scalar. " << message; })) { @@ -2763,7 +2771,7 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - uint32_t operand = decoration.params()[0]; + uint32_t operand = (uint32_t)decoration.builtin(); if (spvIsVulkanEnv(_.context()->target_env)) { const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != spv::StorageClass::Max && @@ -2877,7 +2885,7 @@ spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference( spv_result_t BuiltInsValidator::ValidateFragmentShaderF32Vec3InputAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); if (spv_result_t error = ValidateF32Vec( decoration, inst, 3, [this, &inst, builtin](const std::string& message) -> spv_result_t { @@ -2907,7 +2915,7 @@ spv_result_t BuiltInsValidator::ValidateFragmentShaderF32Vec3InputAtReference( const Instruction& referenced_from_inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != spv::StorageClass::Max && storage_class != spv::StorageClass::Input) { @@ -2951,7 +2959,7 @@ spv_result_t BuiltInsValidator::ValidateFragmentShaderF32Vec3InputAtReference( spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); if (spv_result_t error = ValidateI32Vec( decoration, inst, 3, [this, &inst, builtin](const std::string& message) -> spv_result_t { @@ -2980,7 +2988,7 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference( const Instruction& referenced_inst, const Instruction& referenced_from_inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != spv::StorageClass::Max && storage_class != spv::StorageClass::Input) { @@ -3031,7 +3039,7 @@ spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference( spv_result_t BuiltInsValidator::ValidateComputeI32InputAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); if (decoration.struct_member_index() != Decoration::kInvalidMember) { return _.diag(SPV_ERROR_INVALID_DATA, &inst) << "BuiltIn " @@ -3065,7 +3073,7 @@ spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference( const Instruction& referenced_inst, const Instruction& referenced_from_inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != spv::StorageClass::Max && storage_class != spv::StorageClass::Input) { @@ -3116,7 +3124,7 @@ spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference( spv_result_t BuiltInsValidator::ValidateI32InputAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); if (decoration.struct_member_index() != Decoration::kInvalidMember) { return _.diag(SPV_ERROR_INVALID_DATA, &inst) << "BuiltIn " @@ -3159,7 +3167,7 @@ spv_result_t BuiltInsValidator::ValidateI32InputAtDefinition( spv_result_t BuiltInsValidator::ValidateI32Vec4InputAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); if (decoration.struct_member_index() != Decoration::kInvalidMember) { return _.diag(SPV_ERROR_INVALID_DATA, &inst) << "BuiltIn " @@ -3247,7 +3255,7 @@ spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference( << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + (uint32_t)decoration.builtin()) << " to be used only with GLCompute, MeshNV, TaskNV, MeshEXT or " << "TaskEXT execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -3273,14 +3281,15 @@ spv_result_t BuiltInsValidator::ValidateBaseInstanceOrVertexAtDefinition( decoration, inst, [this, &inst, &decoration](const std::string& message) -> spv_result_t { - uint32_t vuid = (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::BaseInstance) - ? 4183 - : 4186; + uint32_t vuid = + (decoration.builtin() == spv::BuiltIn::BaseInstance) ? 4183 + : 4186; return _.diag(SPV_ERROR_INVALID_DATA, &inst) << _.VkErrorID(vuid) << "According to the Vulkan spec BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, + (uint32_t)decoration.builtin()) << " variable needs to be a 32-bit int scalar. " << message; })) { @@ -3295,7 +3304,7 @@ spv_result_t BuiltInsValidator::ValidateBaseInstanceOrVertexAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - uint32_t operand = decoration.params()[0]; + uint32_t operand = (uint32_t)decoration.builtin(); if (spvIsVulkanEnv(_.context()->target_env)) { const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != spv::StorageClass::Max && @@ -3346,8 +3355,9 @@ spv_result_t BuiltInsValidator::ValidateDrawIndexAtDefinition( return _.diag(SPV_ERROR_INVALID_DATA, &inst) << _.VkErrorID(4209) << "According to the Vulkan spec BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, + (uint32_t)decoration.builtin()) << " variable needs to be a 32-bit int scalar. " << message; })) { @@ -3362,7 +3372,7 @@ spv_result_t BuiltInsValidator::ValidateDrawIndexAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - uint32_t operand = decoration.params()[0]; + uint32_t operand = (uint32_t)decoration.builtin(); if (spvIsVulkanEnv(_.context()->target_env)) { const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != spv::StorageClass::Max && @@ -3416,8 +3426,9 @@ spv_result_t BuiltInsValidator::ValidateViewIndexAtDefinition( return _.diag(SPV_ERROR_INVALID_DATA, &inst) << _.VkErrorID(4403) << "According to the Vulkan spec BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, + (uint32_t)decoration.builtin()) << " variable needs to be a 32-bit int scalar. " << message; })) { @@ -3432,7 +3443,7 @@ spv_result_t BuiltInsValidator::ValidateViewIndexAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - uint32_t operand = decoration.params()[0]; + uint32_t operand = (uint32_t)decoration.builtin(); if (spvIsVulkanEnv(_.context()->target_env)) { const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != spv::StorageClass::Max && @@ -3480,8 +3491,9 @@ spv_result_t BuiltInsValidator::ValidateDeviceIndexAtDefinition( return _.diag(SPV_ERROR_INVALID_DATA, &inst) << _.VkErrorID(4206) << "According to the Vulkan spec BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, + (uint32_t)decoration.builtin()) << " variable needs to be a 32-bit int scalar. " << message; })) { @@ -3496,7 +3508,7 @@ spv_result_t BuiltInsValidator::ValidateDeviceIndexAtReference( const Decoration& decoration, const Instruction& built_in_inst, const Instruction& referenced_inst, const Instruction& referenced_from_inst) { - uint32_t operand = decoration.params()[0]; + uint32_t operand = (uint32_t)decoration.builtin(); if (spvIsVulkanEnv(_.context()->target_env)) { const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != spv::StorageClass::Max && @@ -3526,7 +3538,7 @@ spv_result_t BuiltInsValidator::ValidateFragInvocationCountAtDefinition(const De const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); if (spv_result_t error = ValidateI32( decoration, inst, [this, &inst, &builtin](const std::string& message) -> spv_result_t { @@ -3553,7 +3565,7 @@ spv_result_t BuiltInsValidator::ValidateFragInvocationCountAtReference( const Instruction& referenced_from_inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != spv::StorageClass::Max && storage_class != spv::StorageClass::Input) { @@ -3596,7 +3608,7 @@ spv_result_t BuiltInsValidator::ValidateFragInvocationCountAtReference( spv_result_t BuiltInsValidator::ValidateFragSizeAtDefinition(const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); if (spv_result_t error = ValidateI32Vec( decoration, inst, 2, [this, &inst, &builtin](const std::string& message) -> spv_result_t { @@ -3623,7 +3635,7 @@ spv_result_t BuiltInsValidator::ValidateFragSizeAtReference( const Instruction& referenced_from_inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != spv::StorageClass::Max && storage_class != spv::StorageClass::Input) { @@ -3666,7 +3678,7 @@ spv_result_t BuiltInsValidator::ValidateFragSizeAtReference( spv_result_t BuiltInsValidator::ValidateFragStencilRefAtDefinition(const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); if (spv_result_t error = ValidateI( decoration, inst, [this, &inst, &builtin](const std::string& message) -> spv_result_t { @@ -3693,7 +3705,7 @@ spv_result_t BuiltInsValidator::ValidateFragStencilRefAtReference( const Instruction& referenced_from_inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != spv::StorageClass::Max && storage_class != spv::StorageClass::Output) { @@ -3736,7 +3748,7 @@ spv_result_t BuiltInsValidator::ValidateFragStencilRefAtReference( spv_result_t BuiltInsValidator::ValidateFullyCoveredAtDefinition(const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); if (spv_result_t error = ValidateBool( decoration, inst, [this, &inst, &builtin](const std::string& message) -> spv_result_t { @@ -3763,7 +3775,7 @@ spv_result_t BuiltInsValidator::ValidateFullyCoveredAtReference( const Instruction& referenced_from_inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != spv::StorageClass::Max && storage_class != spv::StorageClass::Input) { @@ -3814,8 +3826,9 @@ spv_result_t BuiltInsValidator::ValidateNVSMOrARMCoreBuiltinsAtDefinition( << "According to the " << spvLogStringForEnv(_.context()->target_env) << " spec BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, + (uint32_t)decoration.builtin()) << " variable needs to be a 32-bit int scalar. " << message; })) { @@ -3839,7 +3852,7 @@ spv_result_t BuiltInsValidator::ValidateNVSMOrARMCoreBuiltinsAtReference( << spvLogStringForEnv(_.context()->target_env) << " spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + (uint32_t)decoration.builtin()) << " to be only used for " "variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -3868,8 +3881,9 @@ spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtDefinition( return _.diag(SPV_ERROR_INVALID_DATA, &inst) << _.VkErrorID(4486) << "According to the Vulkan spec BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, + (uint32_t)decoration.builtin()) << " variable needs to be a 32-bit int scalar. " << message; })) { @@ -3892,7 +3906,7 @@ spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtReference( return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << _.VkErrorID(4485) << "Vulkan spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + (uint32_t)decoration.builtin()) << " to be only used for variables with Output storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst) @@ -3909,8 +3923,9 @@ spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtReference( default: { return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << _.VkErrorID(4484) << "Vulkan spec allows BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, + (uint32_t)decoration.builtin()) << " to be used only with Vertex, Geometry, or MeshNV " "execution models. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, @@ -3941,8 +3956,9 @@ spv_result_t BuiltInsValidator::ValidateShadingRateAtDefinition( return _.diag(SPV_ERROR_INVALID_DATA, &inst) << _.VkErrorID(4492) << "According to the Vulkan spec BuiltIn " - << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + << _.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, + (uint32_t)decoration.builtin()) << " variable needs to be a 32-bit int scalar. " << message; })) { @@ -3965,7 +3981,7 @@ spv_result_t BuiltInsValidator::ValidateShadingRateAtReference( return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << _.VkErrorID(4491) << "Vulkan spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + (uint32_t)decoration.builtin()) << " to be only used for variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst) @@ -3977,7 +3993,7 @@ spv_result_t BuiltInsValidator::ValidateShadingRateAtReference( return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << _.VkErrorID(4490) << "Vulkan spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + (uint32_t)decoration.builtin()) << " to be used only with the Fragment execution model. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst, execution_model); @@ -3998,7 +4014,7 @@ spv_result_t BuiltInsValidator::ValidateShadingRateAtReference( spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); switch (builtin) { case spv::BuiltIn::HitTNV: case spv::BuiltIn::RayTminKHR: @@ -4121,7 +4137,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference( const Instruction& referenced_inst, const Instruction& referenced_from_inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != spv::StorageClass::Max && storage_class != spv::StorageClass::Input) { @@ -4129,7 +4145,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference( return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << _.VkErrorID(vuid) << "Vulkan spec allows BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + (uint32_t)decoration.builtin()) << " to be only used for variables with Input storage class. " << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst) @@ -4142,10 +4158,11 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference( return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst) << _.VkErrorID(vuid) << "Vulkan spec does not allow BuiltIn " << _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN, - decoration.params()[0]) + (uint32_t)decoration.builtin()) << " to be used with the execution model " << _.grammar().lookupOperandName( - SPV_OPERAND_TYPE_EXECUTION_MODEL, uint32_t(execution_model)) + SPV_OPERAND_TYPE_EXECUTION_MODEL, + uint32_t(execution_model)) << ".\n" << GetReferenceDesc(decoration, built_in_inst, referenced_inst, referenced_from_inst, execution_model); @@ -4167,7 +4184,7 @@ spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference( spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition( const Decoration& decoration, const Instruction& inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); uint32_t vuid = GetVUIDForBuiltin(builtin, VUIDErrorType); if (builtin == spv::BuiltIn::PrimitivePointIndicesEXT) { if (spv_result_t error = ValidateI32Arr( @@ -4179,7 +4196,8 @@ spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition( << spvLogStringForEnv(_.context()->target_env) << " spec BuiltIn " << _.grammar().lookupOperandName( - SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) + SPV_OPERAND_TYPE_BUILT_IN, + (uint32_t)decoration.builtin()) << " variable needs to be a 32-bit int array." << message; })) { @@ -4196,7 +4214,8 @@ spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition( << spvLogStringForEnv(_.context()->target_env) << " spec BuiltIn " << _.grammar().lookupOperandName( - SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) + SPV_OPERAND_TYPE_BUILT_IN, + (uint32_t)decoration.builtin()) << " variable needs to be a 2-component 32-bit int " "array." << message; @@ -4214,7 +4233,8 @@ spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtDefinition( << spvLogStringForEnv(_.context()->target_env) << " spec BuiltIn " << _.grammar().lookupOperandName( - SPV_OPERAND_TYPE_BUILT_IN, decoration.params()[0]) + SPV_OPERAND_TYPE_BUILT_IN, + (uint32_t)decoration.builtin()) << " variable needs to be a 3-component 32-bit int " "array." << message; @@ -4233,7 +4253,7 @@ spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference( const Instruction& referenced_inst, const Instruction& referenced_from_inst) { if (spvIsVulkanEnv(_.context()->target_env)) { - const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn builtin = decoration.builtin(); const spv::StorageClass storage_class = GetStorageClass(referenced_from_inst); if (storage_class != spv::StorageClass::Max && @@ -4279,7 +4299,7 @@ spv_result_t BuiltInsValidator::ValidateMeshShadingEXTBuiltinsAtReference( spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition( const Decoration& decoration, const Instruction& inst) { - const spv::BuiltIn label = spv::BuiltIn(decoration.params()[0]); + const spv::BuiltIn label = decoration.builtin(); if (!spvIsVulkanEnv(_.context()->target_env)) { // Early return. All currently implemented rules are based on Vulkan spec. diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp index 811c0e67c5..ebc153c987 100644 --- a/source/val/validate_decorations.cpp +++ b/source/val/validate_decorations.cpp @@ -71,26 +71,6 @@ uint32_t GetArrayStride(uint32_t array_id, ValidationState_t& vstate) { return 0; } -// Returns true if the given variable has a BuiltIn decoration. -bool isBuiltInVar(uint32_t var_id, ValidationState_t& vstate) { - const auto& decorations = vstate.id_decorations(var_id); - return std::any_of(decorations.begin(), decorations.end(), - [](const Decoration& d) { - return spv::Decoration::BuiltIn == d.dec_type(); - }); -} - -// Returns true if the given structure type has any members with BuiltIn -// decoration. -bool isBuiltInStruct(uint32_t struct_id, ValidationState_t& vstate) { - const auto& decorations = vstate.id_decorations(struct_id); - return std::any_of( - decorations.begin(), decorations.end(), [](const Decoration& d) { - return spv::Decoration::BuiltIn == d.dec_type() && - Decoration::kInvalidMember != d.struct_member_index(); - }); -} - // Returns true if the given structure type has a Block decoration. bool isBlock(uint32_t struct_id, ValidationState_t& vstate) { const auto& decorations = vstate.id_decorations(struct_id); @@ -786,6 +766,8 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { int num_workgroup_variables_with_aliased = 0; for (const auto& desc : descs) { std::unordered_set seen_vars; + std::unordered_set input_var_builtin; + std::unordered_set output_var_builtin; for (auto interface : desc.interfaces) { Instruction* var_instr = vstate.FindDef(interface); if (!var_instr || spv::Op::OpVariable != var_instr->opcode()) { @@ -829,33 +811,70 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { // to. const uint32_t type_id = ptr_instr->word(3); Instruction* type_instr = vstate.FindDef(type_id); - if (type_instr && spv::Op::OpTypeStruct == type_instr->opcode() && - isBuiltInStruct(type_id, vstate)) { - if (!isBlock(type_id, vstate)) { - return vstate.diag(SPV_ERROR_INVALID_DATA, vstate.FindDef(type_id)) - << vstate.VkErrorID(4919) - << "Interface struct has no Block decoration but has " - "BuiltIn members. " - "Location decorations must be used on each member of " - "OpVariable with a structure type that is a block not " - "decorated with Location."; + const bool is_struct = + type_instr && spv::Op::OpTypeStruct == type_instr->opcode(); + + // Search all Built-in (on the variable or the struct) + bool has_built_in = false; + for (auto& dec : + vstate.id_decorations(is_struct ? type_id : interface)) { + if (dec.dec_type() != spv::Decoration::BuiltIn) continue; + has_built_in = true; + + if (!spvIsVulkanEnv(vstate.context()->target_env)) continue; + + const spv::BuiltIn builtin = dec.builtin(); + if (storage_class == spv::StorageClass::Input) { + if (!input_var_builtin.insert(builtin).second) { + return vstate.diag(SPV_ERROR_INVALID_ID, var_instr) + << vstate.VkErrorID(9658) + << "OpEntryPoint contains duplicate input variables " + "with " + << vstate.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, (uint32_t)builtin) + << " builtin"; + } } - if (storage_class == spv::StorageClass::Input) - ++num_builtin_block_inputs; - if (storage_class == spv::StorageClass::Output) - ++num_builtin_block_outputs; - if (num_builtin_block_inputs > 1 || num_builtin_block_outputs > 1) - break; - if (auto error = CheckBuiltInVariable(interface, vstate)) - return error; - } else if (isBuiltInVar(interface, vstate)) { + if (storage_class == spv::StorageClass::Output) { + if (!output_var_builtin.insert(builtin).second) { + return vstate.diag(SPV_ERROR_INVALID_ID, var_instr) + << vstate.VkErrorID(9659) + << "OpEntryPoint contains duplicate output variables " + "with " + << vstate.grammar().lookupOperandName( + SPV_OPERAND_TYPE_BUILT_IN, (uint32_t)builtin) + << " builtin"; + } + } + } + + if (has_built_in) { if (auto error = CheckBuiltInVariable(interface, vstate)) return error; + + if (is_struct) { + if (!isBlock(type_id, vstate)) { + return vstate.diag(SPV_ERROR_INVALID_DATA, + vstate.FindDef(type_id)) + << vstate.VkErrorID(4919) + << "Interface struct has no Block decoration but has " + "BuiltIn members. " + "Location decorations must be used on each member of " + "OpVariable with a structure type that is a block not " + "decorated with Location."; + } + if (storage_class == spv::StorageClass::Input) + ++num_builtin_block_inputs; + if (storage_class == spv::StorageClass::Output) + ++num_builtin_block_outputs; + if (num_builtin_block_inputs > 1 || num_builtin_block_outputs > 1) + break; + } } if (storage_class == spv::StorageClass::Workgroup) { ++num_workgroup_variables; - if (type_instr && spv::Op::OpTypeStruct == type_instr->opcode()) { + if (is_struct) { if (hasDecoration(type_id, spv::Decoration::Block, vstate)) ++num_workgroup_variables_with_block; if (hasDecoration(var_instr->id(), spv::Decoration::Aliased, diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 87322d2b96..316972eaa2 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -2353,6 +2353,10 @@ std::string ValidationState_t::VkErrorID(uint32_t id, return VUID_WRAP(VUID-StandaloneSpirv-Pointer-08973); case 9638: return VUID_WRAP(VUID-StandaloneSpirv-OpTypeImage-09638); + case 9658: + return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-09658); + case 9659: + return VUID_WRAP(VUID-StandaloneSpirv-OpEntryPoint-09659); default: return ""; // unknown id } diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp index b525477cc6..5aff68787c 100644 --- a/test/val/val_decoration_test.cpp +++ b/test/val/val_decoration_test.cpp @@ -9670,6 +9670,303 @@ OpFunctionEnd HasSubstr("is a matrix with stride 8 not satisfying alignment to 16")); } +TEST_F(ValidateDecorations, MultipleBuiltinsInputVertex) { + const std::string body = R"( + OpCapability Shader + OpCapability DrawParameters + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %_ %gl_BaseInstance1 %gl_BaseInstance2 + 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 + OpDecorate %gl_BaseInstance1 BuiltIn BaseInstance + OpDecorate %gl_BaseInstance2 BuiltIn BaseInstance + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 + %uint = OpTypeInt 32 0 + %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 +%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex + %_ = OpVariable %_ptr_Output_gl_PerVertex Output + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float_0 = OpConstant %float 0 + %17 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 +%_ptr_Input_int = OpTypePointer Input %int +%gl_BaseInstance1 = OpVariable %_ptr_Input_int Input +%gl_BaseInstance2 = OpVariable %_ptr_Input_int Input +%_ptr_Output_v4float = OpTypePointer Output %v4float + %main = OpFunction %void None %3 + %5 = OpLabel + %20 = OpLoad %int %gl_BaseInstance1 + %21 = OpConvertSToF %float %20 + %22 = OpVectorTimesScalar %v4float %17 %21 + %24 = OpAccessChain %_ptr_Output_v4float %_ %int_0 + OpStore %24 %22 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpEntryPoint contains duplicate input variables with " + "BaseInstance builtin")); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-09658")); +} + +TEST_F(ValidateDecorations, MultipleBuiltinsInputMesh) { + const std::string body = R"( + OpCapability DrawParameters + OpCapability MeshShadingEXT + OpExtension "SPV_EXT_mesh_shader" + OpMemoryModel Logical GLSL450 + OpEntryPoint MeshEXT %main "main" %gl_DrawID_1 %gl_DrawID_2 + OpExecutionMode %main LocalSize 1 1 1 + OpExecutionMode %main OutputVertices 32 + OpExecutionMode %main OutputPrimitivesEXT 32 + OpExecutionMode %main OutputTrianglesEXT + OpDecorate %gl_DrawID_1 BuiltIn DrawIndex + OpDecorate %gl_DrawID_2 BuiltIn DrawIndex + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 +%_ptr_Input_int = OpTypePointer Input %int + %gl_DrawID_1 = OpVariable %_ptr_Input_int Input + %gl_DrawID_2 = OpVariable %_ptr_Input_int Input + %uint = OpTypeInt 32 0 + %main = OpFunction %void None %3 + %5 = OpLabel + %9 = OpLoad %int %gl_DrawID_1 + %11 = OpBitcast %uint %9 + %12 = OpLoad %int %gl_DrawID_2 + %13 = OpBitcast %uint %12 + OpSetMeshOutputsEXT %11 %13 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpEntryPoint contains duplicate input variables with " + "DrawIndex builtin")); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-09658")); +} + +TEST_F(ValidateDecorations, MultipleBuiltinsInputCompute) { + const std::string body = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" %_ %gl_WorkGroupID_1 %gl_WorkGroupID_2 + OpExecutionMode %main LocalSize 1 1 1 + OpMemberDecorate %Buffers 0 Offset 0 + OpDecorate %Buffers Block + OpDecorate %_ DescriptorSet 0 + OpDecorate %_ Binding 0 + OpDecorate %gl_WorkGroupID_1 BuiltIn WorkgroupId + OpDecorate %gl_WorkGroupID_2 BuiltIn WorkgroupId + %void = OpTypeVoid + %3 = OpTypeFunction %void + %uint = OpTypeInt 32 0 + %v3uint = OpTypeVector %uint 3 + %Buffers = OpTypeStruct %v3uint +%_ptr_StorageBuffer_Buffers = OpTypePointer StorageBuffer %Buffers + %_ = OpVariable %_ptr_StorageBuffer_Buffers StorageBuffer + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 +%_ptr_Input_v3uint = OpTypePointer Input %v3uint +%gl_WorkGroupID_1 = OpVariable %_ptr_Input_v3uint Input +%gl_WorkGroupID_2 = OpVariable %_ptr_Input_v3uint Input +%_ptr_StorageBuffer_v3uint = OpTypePointer StorageBuffer %v3uint + %main = OpFunction %void None %3 + %5 = OpLabel + %15 = OpLoad %v3uint %gl_WorkGroupID_1 + %16 = OpLoad %v3uint %gl_WorkGroupID_2 + %17 = OpIAdd %v3uint %15 %16 + %19 = OpAccessChain %_ptr_StorageBuffer_v3uint %_ %int_0 + OpStore %19 %17 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpEntryPoint contains duplicate input variables with " + "WorkgroupId builtin")); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-09658")); +} + +TEST_F(ValidateDecorations, MultipleBuiltinsOutputFragment) { + const std::string body = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %gl_FragDepth_1 %gl_FragDepth_2 + OpExecutionMode %main OriginUpperLeft + OpExecutionMode %main DepthReplacing + OpDecorate %gl_FragDepth_1 BuiltIn FragDepth + OpDecorate %gl_FragDepth_2 BuiltIn FragDepth + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 +%_ptr_Output_float = OpTypePointer Output %float +%gl_FragDepth_1 = OpVariable %_ptr_Output_float Output +%gl_FragDepth_2 = OpVariable %_ptr_Output_float Output + %float_1 = OpConstant %float 1 + %main = OpFunction %void None %3 + %5 = OpLabel + OpStore %gl_FragDepth_1 %float_1 + %10 = OpLoad %float %gl_FragDepth_1 + %11 = OpFAdd %float %10 %float_1 + OpStore %gl_FragDepth_2 %11 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpEntryPoint contains duplicate output variables with " + "FragDepth builtin")); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-09659")); +} + +TEST_F(ValidateDecorations, MultipleBuiltinsRayTmaxKHR) { + const std::string body = R"( + OpCapability RayTracingKHR + OpExtension "SPV_KHR_ray_tracing" + OpMemoryModel Logical GLSL450 + OpEntryPoint AnyHitKHR %main "main" %gl_RayTmaxEXT %gl_HitTEXT %incomingPayload + OpDecorate %gl_RayTmaxEXT BuiltIn RayTmaxKHR + OpDecorate %gl_HitTEXT BuiltIn RayTmaxKHR + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 +%_ptr_Function_float = OpTypePointer Function %float +%_ptr_Input_float = OpTypePointer Input %float +%gl_RayTmaxEXT = OpVariable %_ptr_Input_float Input + %gl_HitTEXT = OpVariable %_ptr_Input_float Input + %v4float = OpTypeVector %float 4 +%_ptr_IncomingRayPayloadKHR_v4float = OpTypePointer IncomingRayPayloadKHR %v4float +%incomingPayload = OpVariable %_ptr_IncomingRayPayloadKHR_v4float IncomingRayPayloadKHR + %main = OpFunction %void None %3 + %5 = OpLabel + %a = OpVariable %_ptr_Function_float Function + %b = OpVariable %_ptr_Function_float Function + %11 = OpLoad %float %gl_RayTmaxEXT + OpStore %a %11 + %14 = OpLoad %float %gl_HitTEXT + OpStore %b %14 + %18 = OpLoad %float %a + %19 = OpLoad %float %b + %22 = OpCompositeConstruct %v4float %18 %18 %19 %19 + OpStore %incomingPayload %22 + OpTerminateRayKHR + OpFunctionEnd + )"; + + CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_2); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpEntryPoint contains duplicate input variables with RayTmax")); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-09658")); +} + +TEST_F(ValidateDecorations, MultipleBuiltinsBlock) { + const std::string body = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %var + OpMemberDecorate %gl_PerVertex 0 BuiltIn Position + OpMemberDecorate %gl_PerVertex 1 BuiltIn Position + OpDecorate %gl_PerVertex Block + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%gl_PerVertex = OpTypeStruct %v4float %v4float +%_ptr_gl_PerVertex = OpTypePointer Output %gl_PerVertex + %var = OpVariable %_ptr_gl_PerVertex Output + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %float_0 = OpConstant %float 0 + %17 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 + %ptr_vec4 = OpTypePointer Output %v4float + %main = OpFunction %void None %3 + %5 = OpLabel + %19 = OpAccessChain %ptr_vec4 %var %int_0 + OpStore %19 %17 + %22 = OpAccessChain %ptr_vec4 %var %int_1 + OpStore %22 %17 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpEntryPoint contains duplicate output variables with Position")); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-09659")); +} + +TEST_F(ValidateDecorations, MultipleBuiltinsBlockMixed) { + const std::string body = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Vertex %main "main" %var %position + OpMemberDecorate %gl_PerVertex 0 BuiltIn Position + OpDecorate %gl_PerVertex Block + OpDecorate %position BuiltIn Position + %void = OpTypeVoid + %3 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v4float = OpTypeVector %float 4 +%gl_PerVertex = OpTypeStruct %v4float +%_ptr_gl_PerVertex = OpTypePointer Output %gl_PerVertex + %var = OpVariable %_ptr_gl_PerVertex Output + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %float_0 = OpConstant %float 0 + %17 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 + %ptr_vec4 = OpTypePointer Output %v4float + %position = OpVariable %ptr_vec4 Output + %main = OpFunction %void None %3 + %5 = OpLabel + %19 = OpAccessChain %ptr_vec4 %var %int_0 + OpStore %19 %17 + OpStore %position %17 + OpReturn + OpFunctionEnd + )"; + + CompileSuccessfully(body.c_str(), SPV_ENV_VULKAN_1_0); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpEntryPoint contains duplicate output variables with Position")); + EXPECT_THAT(getDiagnosticString(), + AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-09659")); +} + } // namespace } // namespace val } // namespace spvtools From 7e1a8cdc534093862cc369bb9f398f919c105684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Petit?= Date: Thu, 30 May 2024 15:58:44 +0100 Subject: [PATCH 442/523] Basic support for SPV_EXT_replicated_composites (#5690) * Basic support for SPV_EXT_replicated_composites Validation will follow as a separate PR (still need to write a test suite) Change-Id: Ic95fa6ce39d32f5ac2787bc38dba2748c9cc58f7 Signed-off-by: Kevin Petit * Update SPIRV-Headers Change-Id: I6c0df248d99c13b49d78528d035a4222027c0232 --------- Signed-off-by: Kevin Petit --- DEPS | 2 +- source/opcode.cpp | 3 +++ test/text_to_binary.extension_test.cpp | 26 ++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/DEPS b/DEPS index e6bf04c91d..af8ad4be12 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 're2_revision': '917047f3606d3ba9e2de0d383c3cd80c94ed732c', - 'spirv_headers_revision': '49a1fceb9b1d087f3c25ad5ec077bb0e46231297', + 'spirv_headers_revision': 'ea77f2a826bc820cb8f57f9b2a7c7eccb681c731', } deps = { diff --git a/source/opcode.cpp b/source/opcode.cpp index 787dbb3403..726a4e0f6b 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -225,6 +225,7 @@ int32_t spvOpcodeIsSpecConstant(const spv::Op opcode) { case spv::Op::OpSpecConstantFalse: case spv::Op::OpSpecConstant: case spv::Op::OpSpecConstantComposite: + case spv::Op::OpSpecConstantCompositeReplicateEXT: case spv::Op::OpSpecConstantOp: return true; default: @@ -238,6 +239,7 @@ int32_t spvOpcodeIsConstant(const spv::Op opcode) { case spv::Op::OpConstantFalse: case spv::Op::OpConstant: case spv::Op::OpConstantComposite: + case spv::Op::OpConstantCompositeReplicateEXT: case spv::Op::OpConstantSampler: case spv::Op::OpConstantNull: case spv::Op::OpConstantFunctionPointerINTEL: @@ -245,6 +247,7 @@ int32_t spvOpcodeIsConstant(const spv::Op opcode) { case spv::Op::OpSpecConstantFalse: case spv::Op::OpSpecConstant: case spv::Op::OpSpecConstantComposite: + case spv::Op::OpSpecConstantCompositeReplicateEXT: case spv::Op::OpSpecConstantOp: return true; default: diff --git a/test/text_to_binary.extension_test.cpp b/test/text_to_binary.extension_test.cpp index 8e78312e6e..1d58c02ba2 100644 --- a/test/text_to_binary.extension_test.cpp +++ b/test/text_to_binary.extension_test.cpp @@ -1300,5 +1300,31 @@ INSTANTIATE_TEST_SUITE_P( (uint32_t)spv::FPFastMathModeMask::AllowTransform})}, }))); +// SPV_EXT_replicated_composites + +INSTANTIATE_TEST_SUITE_P( + SPV_EXT_replicated_composites, ExtensionRoundTripTest, + Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_6, + SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2, + SPV_ENV_VULKAN_1_3, SPV_ENV_OPENCL_2_1), + ValuesIn(std::vector{ + {"OpExtension \"SPV_EXT_replicated_composites\"\n", + MakeInstruction(spv::Op::OpExtension, + MakeVector("SPV_EXT_replicated_composites"))}, + {"OpCapability ReplicatedCompositesEXT\n", + MakeInstruction( + spv::Op::OpCapability, + {(uint32_t)spv::Capability::ReplicatedCompositesEXT})}, + {"%2 = OpConstantCompositeReplicateEXT %1 %3\n", + MakeInstruction(spv::Op::OpConstantCompositeReplicateEXT, + {1, 2, 3})}, + {"%2 = OpSpecConstantCompositeReplicateEXT %1 %3\n", + MakeInstruction(spv::Op::OpSpecConstantCompositeReplicateEXT, + {1, 2, 3})}, + {"%2 = OpCompositeConstructReplicateEXT %1 %3\n", + MakeInstruction(spv::Op::OpCompositeConstructReplicateEXT, + {1, 2, 3})}, + }))); + } // namespace } // namespace spvtools From 142bf7de83b550b549b4049eb1f3dcb2ff007ec1 Mon Sep 17 00:00:00 2001 From: Sven van Haastregt Date: Thu, 30 May 2024 17:01:35 +0200 Subject: [PATCH 443/523] spirv-val: Fix indentation of --version output (#5686) The last three elements in the list of supported targets were misaligned: ``` Targets: SPIR-V 1.0 SPIR-V 1.1 ... SPIR-V 1.3 (under Vulkan 1.1 semantics) SPIR-V 1.4 (under Vulkan 1.1 semantics) SPIR-V 1.5 (under Vulkan 1.2 semantics) SPIR-V 1.6 (under Vulkan 1.3 semantics) ``` Signed-off-by: Sven van Haastregt --- tools/val/val.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/val/val.cpp b/tools/val/val.cpp index 880ce46b3a..33d1ddedfb 100644 --- a/tools/val/val.cpp +++ b/tools/val/val.cpp @@ -111,7 +111,7 @@ int main(int argc, char** argv) { printf("%s\n", spvSoftwareVersionDetailsString()); printf( "Targets:\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n " - "%s\n %s\n %s\n %s\n", + "%s\n %s\n %s\n %s\n", spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_0), spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_1), spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_2), From 148c97f6876e427efd76d2328122c3075eab4b8f Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Fri, 31 May 2024 08:13:20 -0400 Subject: [PATCH 444/523] Avoid use of type manager in extact->construct folding (#5684) * Avoid use of type manager in extact->construct folding When dealing with structs the type manager merge two different structs into a single entry if they have all of the same decorations and element types. This is because they hash to the same value in the hash table. This can cause problems if you need to get the id of a type from the type manager because you could get either one. In this case, it returns the wrong one. The fix avoids using the type manager in one place. I have not looked closely at other places the type manager is used to make sure it is used safely everywhere. Fixes #5624 * Remove use of TypeManager::GetId This removes a use of TypeManager::GetId by keeping the id around. This avoid a potential problem if the type manager gets confused. These types of bugs are hard to generate test cases for, so I do not have a test. However, existing tests make sure that do not regress. --- source/opt/folding_rules.cpp | 66 +++++++++++++++++------------------- test/opt/fold_test.cpp | 16 ++++++++- 2 files changed, 47 insertions(+), 35 deletions(-) diff --git a/source/opt/folding_rules.cpp b/source/opt/folding_rules.cpp index 5f83669940..24979671f2 100644 --- a/source/opt/folding_rules.cpp +++ b/source/opt/folding_rules.cpp @@ -1607,27 +1607,26 @@ bool CompositeConstructFeedingExtract( } // Walks the indexes chain from |start| to |end| of an OpCompositeInsert or -// OpCompositeExtract instruction, and returns the type of the final element -// being accessed. -const analysis::Type* GetElementType(uint32_t type_id, - Instruction::iterator start, - Instruction::iterator end, - const analysis::TypeManager* type_mgr) { - const analysis::Type* type = type_mgr->GetType(type_id); +// OpCompositeExtract instruction, and returns the type id of the final element +// being accessed. Returns 0 if a valid type could not be found. +uint32_t GetElementType(uint32_t type_id, Instruction::iterator start, + Instruction::iterator end, + const analysis::DefUseManager* def_use_manager) { for (auto index : make_range(std::move(start), std::move(end))) { + const Instruction* type_inst = def_use_manager->GetDef(type_id); assert(index.type == SPV_OPERAND_TYPE_LITERAL_INTEGER && index.words.size() == 1); - if (auto* array_type = type->AsArray()) { - type = array_type->element_type(); - } else if (auto* matrix_type = type->AsMatrix()) { - type = matrix_type->element_type(); - } else if (auto* struct_type = type->AsStruct()) { - type = struct_type->element_types()[index.words[0]]; + if (type_inst->opcode() == spv::Op::OpTypeArray) { + type_id = type_inst->GetSingleWordInOperand(0); + } else if (type_inst->opcode() == spv::Op::OpTypeMatrix) { + type_id = type_inst->GetSingleWordInOperand(0); + } else if (type_inst->opcode() == spv::Op::OpTypeStruct) { + type_id = type_inst->GetSingleWordInOperand(index.words[0]); } else { - type = nullptr; + return 0; } } - return type; + return type_id; } // Returns true of |inst_1| and |inst_2| have the same indexes that will be used @@ -1712,16 +1711,11 @@ bool CompositeExtractFeedingConstruct( // The last check it to see that the object being extracted from is the // correct type. Instruction* original_inst = def_use_mgr->GetDef(original_id); - analysis::TypeManager* type_mgr = context->get_type_mgr(); - const analysis::Type* original_type = + uint32_t original_type_id = GetElementType(original_inst->type_id(), first_element_inst->begin() + 3, - first_element_inst->end() - 1, type_mgr); - - if (original_type == nullptr) { - return false; - } + first_element_inst->end() - 1, def_use_mgr); - if (inst->type_id() != type_mgr->GetId(original_type)) { + if (inst->type_id() != original_type_id) { return false; } @@ -2011,13 +2005,15 @@ bool DoInsertedValuesCoverEntireObject( return true; } -// Returns the type of the element that immediately contains the element being -// inserted by the OpCompositeInsert instruction |inst|. -const analysis::Type* GetContainerType(Instruction* inst) { +// Returns id of the type of the element that immediately contains the element +// being inserted by the OpCompositeInsert instruction |inst|. Returns 0 if it +// could not be found. +uint32_t GetContainerTypeId(Instruction* inst) { assert(inst->opcode() == spv::Op::OpCompositeInsert); - analysis::TypeManager* type_mgr = inst->context()->get_type_mgr(); - return GetElementType(inst->type_id(), inst->begin() + 4, inst->end() - 1, - type_mgr); + analysis::DefUseManager* def_use_manager = inst->context()->get_def_use_mgr(); + uint32_t container_type_id = GetElementType( + inst->type_id(), inst->begin() + 4, inst->end() - 1, def_use_manager); + return container_type_id; } // Returns an OpCompositeConstruct instruction that build an object with @@ -2064,18 +2060,20 @@ bool CompositeInsertToCompositeConstruct( if (inst->NumInOperands() < 3) return false; std::map values_inserted = GetInsertedValues(inst); - const analysis::Type* container_type = GetContainerType(inst); - if (container_type == nullptr) { + uint32_t container_type_id = GetContainerTypeId(inst); + if (container_type_id == 0) { return false; } + analysis::TypeManager* type_mgr = context->get_type_mgr(); + const analysis::Type* container_type = type_mgr->GetType(container_type_id); + assert(container_type && "GetContainerTypeId returned a bad id."); if (!DoInsertedValuesCoverEntireObject(container_type, values_inserted)) { return false; } - analysis::TypeManager* type_mgr = context->get_type_mgr(); - Instruction* construct = BuildCompositeConstruct( - type_mgr->GetId(container_type), values_inserted, inst); + Instruction* construct = + BuildCompositeConstruct(container_type_id, values_inserted, inst); InsertConstructedObject(inst, construct); return true; } diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index 255449dbbf..35828ab22f 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -7827,7 +7827,21 @@ ::testing::Values( "%5 = OpCompositeInsert %int_arr_2 %int_1 %4 1\n" + "OpReturn\n" + "OpFunctionEnd", - 5, true) + 5, true), + // Test case 19: Don't fold for isomorphic structs + InstructionFoldingCase( + Header() + + "%structA = OpTypeStruct %ulong\n" + + "%structB = OpTypeStruct %ulong\n" + + "%structC = OpTypeStruct %structB\n" + + "%struct_a_undef = OpUndef %structA\n" + + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%3 = OpCompositeExtract %ulong %struct_a_undef 0\n" + + "%4 = OpCompositeConstruct %structB %3\n" + + "OpReturn\n" + + "OpFunctionEnd", + 4, false) )); INSTANTIATE_TEST_SUITE_P(DotProductMatchingTest, MatchingInstructionFoldingTest, From 95681dc42f92af0bd8d881f81f3bd3035cbb6497 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Mon, 3 Jun 2024 09:07:52 -0400 Subject: [PATCH 445/523] Remove implicit call to GetId in ConvertToSampledImagePass. (#5692) We replace getting the id of a poitner type with a specific funciton call to FindPointerToType. Also, FindPointerToType is updated to not indirectly call GetId. This leads to a linear search for an existing type in all cases, but it is necessary. Note that this function could have a similar problem. There could be two pointer types with the same pointee and storage class, and the first one will be returned. I have checked the ~20 uses, and they are all used in situations where the id is used to create something new, and it does not have to match an existing type. These will not cause problems. Part of #5691 --- source/opt/convert_to_sampled_image_pass.cpp | 6 ++---- source/opt/type_manager.cpp | 9 +++------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/source/opt/convert_to_sampled_image_pass.cpp b/source/opt/convert_to_sampled_image_pass.cpp index c82db41cec..d2da4d1e0b 100644 --- a/source/opt/convert_to_sampled_image_pass.cpp +++ b/source/opt/convert_to_sampled_image_pass.cpp @@ -329,12 +329,10 @@ bool ConvertToSampledImagePass::ConvertImageVariableToSampledImage( if (sampled_image_type == nullptr) return false; auto storage_class = GetStorageClass(*image_variable); if (storage_class == spv::StorageClass::Max) return false; - analysis::Pointer sampled_image_pointer(sampled_image_type, storage_class); - // Make sure |image_variable| is behind its type i.e., avoid the forward // reference. - uint32_t type_id = - context()->get_type_mgr()->GetTypeInstruction(&sampled_image_pointer); + uint32_t type_id = context()->get_type_mgr()->FindPointerToType( + sampled_image_type_id, storage_class); MoveInstructionNextToType(image_variable, type_id); return true; } diff --git a/source/opt/type_manager.cpp b/source/opt/type_manager.cpp index 7b609bc776..62f93698ff 100644 --- a/source/opt/type_manager.cpp +++ b/source/opt/type_manager.cpp @@ -454,12 +454,7 @@ uint32_t TypeManager::FindPointerToType(uint32_t type_id, spv::StorageClass storage_class) { Type* pointeeTy = GetType(type_id); Pointer pointerTy(pointeeTy, storage_class); - if (pointeeTy->IsUniqueType()) { - // Non-ambiguous type. Get the pointer type through the type manager. - return GetTypeInstruction(&pointerTy); - } - // Ambiguous type, do a linear search. Module::inst_iterator type_itr = context()->module()->types_values_begin(); for (; type_itr != context()->module()->types_values_end(); ++type_itr) { const Instruction* type_inst = &*type_itr; @@ -472,8 +467,10 @@ uint32_t TypeManager::FindPointerToType(uint32_t type_id, } // Must create the pointer type. - // TODO(1841): Handle id overflow. uint32_t resultId = context()->TakeNextId(); + if (resultId == 0) { + return 0; + } std::unique_ptr type_inst( new Instruction(context(), spv::Op::OpTypePointer, 0, resultId, {{spv_operand_type_t::SPV_OPERAND_TYPE_STORAGE_CLASS, From fd96922e9a1814d92df46df03277788c799a4fad Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Mon, 3 Jun 2024 09:21:14 -0400 Subject: [PATCH 446/523] Remove calls to GetId in liveness analysis (#5693) Part of #5691 --- .../opt/eliminate_dead_output_stores_pass.cpp | 13 ++- source/opt/liveness.cpp | 106 +++++++++++------- source/opt/liveness.h | 19 ++-- 3 files changed, 80 insertions(+), 58 deletions(-) diff --git a/source/opt/eliminate_dead_output_stores_pass.cpp b/source/opt/eliminate_dead_output_stores_pass.cpp index 99711a16e8..e71032d439 100644 --- a/source/opt/eliminate_dead_output_stores_pass.cpp +++ b/source/opt/eliminate_dead_output_stores_pass.cpp @@ -92,16 +92,19 @@ void EliminateDeadOutputStoresPass::KillAllDeadStoresOfLocRef( }); // Compute offset and final type of reference. If no location found // or any stored locations are live, return without removing stores. - auto ptr_type = type_mgr->GetType(var->type_id())->AsPointer(); + + Instruction* ptr_type = get_def_use_mgr()->GetDef(var->type_id()); assert(ptr_type && "unexpected var type"); - auto var_type = ptr_type->pointee_type(); + const uint32_t kPointerTypePointeeIdx = 1; + uint32_t var_type_id = + ptr_type->GetSingleWordInOperand(kPointerTypePointeeIdx); uint32_t ref_loc = start_loc; - auto curr_type = var_type; if (ref->opcode() == spv::Op::OpAccessChain || ref->opcode() == spv::Op::OpInBoundsAccessChain) { - live_mgr->AnalyzeAccessChainLoc(ref, &curr_type, &ref_loc, &no_loc, - is_patch, /* input */ false); + var_type_id = live_mgr->AnalyzeAccessChainLoc( + ref, var_type_id, &ref_loc, &no_loc, is_patch, /* input */ false); } + const analysis::Type* curr_type = type_mgr->GetType(var_type_id); if (no_loc || AnyLocsAreLive(ref_loc, live_mgr->GetLocSize(curr_type))) return; // Kill all stores based on this reference diff --git a/source/opt/liveness.cpp b/source/opt/liveness.cpp index 336f3ae526..dae705dc5b 100644 --- a/source/opt/liveness.cpp +++ b/source/opt/liveness.cpp @@ -123,21 +123,29 @@ uint32_t LivenessManager::GetLocSize(const analysis::Type* type) const { return 1; } -const analysis::Type* LivenessManager::GetComponentType( - uint32_t index, const analysis::Type* agg_type) const { - auto arr_type = agg_type->AsArray(); - if (arr_type) return arr_type->element_type(); - auto struct_type = agg_type->AsStruct(); - if (struct_type) return struct_type->element_types()[index]; - auto mat_type = agg_type->AsMatrix(); - if (mat_type) return mat_type->element_type(); - auto vec_type = agg_type->AsVector(); - assert(vec_type && "unexpected non-aggregate type"); - return vec_type->element_type(); +uint32_t LivenessManager::GetComponentType(uint32_t index, + uint32_t agg_type_id) const { + analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr(); + Instruction* agg_type_inst = def_use_mgr->GetDef(agg_type_id); + + const uint32_t kArrayElementInIdx = 0; + switch (agg_type_inst->opcode()) { + case spv::Op::OpTypeArray: + case spv::Op::OpTypeMatrix: + case spv::Op::OpTypeVector: + return agg_type_inst->GetSingleWordInOperand(kArrayElementInIdx); + case spv::Op::OpTypeStruct: + return agg_type_inst->GetSingleWordInOperand(index); + default: + assert(false && "unexpected aggregate type"); + return 0; + } } uint32_t LivenessManager::GetLocOffset(uint32_t index, - const analysis::Type* agg_type) const { + uint32_t agg_type_id) const { + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + const analysis::Type* agg_type = type_mgr->GetType(agg_type_id); auto arr_type = agg_type->AsArray(); if (arr_type) return index * GetLocSize(arr_type->element_type()); auto struct_type = agg_type->AsStruct(); @@ -161,12 +169,11 @@ uint32_t LivenessManager::GetLocOffset(uint32_t index, return 0; } -void LivenessManager::AnalyzeAccessChainLoc(const Instruction* ac, - const analysis::Type** curr_type, - uint32_t* offset, bool* no_loc, - bool is_patch, bool input) { +uint32_t LivenessManager::AnalyzeAccessChainLoc(const Instruction* ac, + uint32_t curr_type_id, + uint32_t* offset, bool* no_loc, + bool is_patch, bool input) { analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr(); - analysis::TypeManager* type_mgr = context()->get_type_mgr(); analysis::DecorationManager* deco_mgr = context()->get_decoration_mgr(); // For tesc, tese and geom input variables, and tesc output variables, // first array index does not contribute to offset. @@ -178,15 +185,18 @@ void LivenessManager::AnalyzeAccessChainLoc(const Instruction* ac, (!input && stage == spv::ExecutionModel::TessellationControl)) skip_first_index = !is_patch; uint32_t ocnt = 0; - ac->WhileEachInOperand([this, &ocnt, def_use_mgr, type_mgr, deco_mgr, - curr_type, offset, no_loc, + ac->WhileEachInOperand([this, &ocnt, def_use_mgr, deco_mgr, &curr_type_id, + offset, no_loc, skip_first_index](const uint32_t* opnd) { if (ocnt >= 1) { // Skip first index's contribution to offset if indicated + Instruction* curr_type_inst = def_use_mgr->GetDef(curr_type_id); if (ocnt == 1 && skip_first_index) { - auto arr_type = (*curr_type)->AsArray(); - assert(arr_type && "unexpected wrapper type"); - *curr_type = arr_type->element_type(); + assert(curr_type_inst->opcode() == spv::Op::OpTypeArray && + "unexpected wrapper type"); + const uint32_t kArrayElementTypeInIdx = 0; + curr_type_id = + curr_type_inst->GetSingleWordInOperand(kArrayElementTypeInIdx); ocnt++; return true; } @@ -196,12 +206,10 @@ void LivenessManager::AnalyzeAccessChainLoc(const Instruction* ac, // If current type is struct, look for location decoration on member and // reset offset if found. auto index = idx_inst->GetSingleWordInOperand(0); - auto str_type = (*curr_type)->AsStruct(); - if (str_type) { + if (curr_type_inst->opcode() == spv::Op::OpTypeStruct) { uint32_t loc = 0; - auto str_type_id = type_mgr->GetId(str_type); bool no_mem_loc = deco_mgr->WhileEachDecoration( - str_type_id, uint32_t(spv::Decoration::Location), + curr_type_id, uint32_t(spv::Decoration::Location), [&loc, index, no_loc](const Instruction& deco) { assert(deco.opcode() == spv::Op::OpMemberDecorate && "unexpected decoration"); @@ -216,19 +224,20 @@ void LivenessManager::AnalyzeAccessChainLoc(const Instruction* ac, }); if (!no_mem_loc) { *offset = loc; - *curr_type = GetComponentType(index, *curr_type); + curr_type_id = curr_type_inst->GetSingleWordInOperand(index); ocnt++; return true; } } // Update offset and current type based on constant index. - *offset += GetLocOffset(index, *curr_type); - *curr_type = GetComponentType(index, *curr_type); + *offset += GetLocOffset(index, curr_type_id); + curr_type_id = GetComponentType(index, curr_type_id); } ocnt++; return true; }); + return curr_type_id; } void LivenessManager::MarkRefLive(const Instruction* ref, Instruction* var) { @@ -268,8 +277,15 @@ void LivenessManager::MarkRefLive(const Instruction* ref, Instruction* var) { // through constant indices and mark those locs live. Assert if no location // found. uint32_t offset = loc; - auto curr_type = var_type; - AnalyzeAccessChainLoc(ref, &curr_type, &offset, &no_loc, is_patch); + Instruction* ptr_type_inst = + context()->get_def_use_mgr()->GetDef(var->type_id()); + assert(ptr_type && "unexpected var type"); + const uint32_t kPointerTypePointeeIdx = 1; + uint32_t var_type_id = + ptr_type_inst->GetSingleWordInOperand(kPointerTypePointeeIdx); + uint32_t curr_type_id = + AnalyzeAccessChainLoc(ref, var_type_id, &offset, &no_loc, is_patch); + auto curr_type = type_mgr->GetType(curr_type_id); assert(!no_loc && "missing input variable location"); MarkLocsLive(offset, GetLocSize(curr_type)); } @@ -277,15 +293,18 @@ void LivenessManager::MarkRefLive(const Instruction* ref, Instruction* var) { void LivenessManager::ComputeLiveness() { InitializeAnalysis(); analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr(); - analysis::TypeManager* type_mgr = context()->get_type_mgr(); // Process all input variables for (auto& var : context()->types_values()) { if (var.opcode() != spv::Op::OpVariable) { continue; } - analysis::Type* var_type = type_mgr->GetType(var.type_id()); - analysis::Pointer* ptr_type = var_type->AsPointer(); - if (ptr_type->storage_class() != spv::StorageClass::Input) { + Instruction* var_type_inst = def_use_mgr->GetDef(var.type_id()); + assert(var_type_inst->opcode() == spv::Op::OpTypePointer && + "Expected a pointer type"); + const uint32_t kPointerTypeStorageClassInIdx = 0; + spv::StorageClass sc = static_cast( + var_type_inst->GetSingleWordInOperand(kPointerTypeStorageClassInIdx)); + if (sc != spv::StorageClass::Input) { continue; } // If var is builtin, mark live if analyzed and continue to next variable @@ -295,14 +314,15 @@ void LivenessManager::ComputeLiveness() { // continue to next variable. Input interface blocks will only appear // in tesc, tese and geom shaders. Will need to strip off one level of // arrayness to get to block type. - auto pte_type = ptr_type->pointee_type(); - auto arr_type = pte_type->AsArray(); - if (arr_type) { - auto elt_type = arr_type->element_type(); - auto str_type = elt_type->AsStruct(); - if (str_type) { - auto str_type_id = type_mgr->GetId(str_type); - if (AnalyzeBuiltIn(str_type_id)) continue; + const uint32_t kPointerTypePointeeTypeInIdx = 1; + uint32_t pte_type_id = + var_type_inst->GetSingleWordInOperand(kPointerTypePointeeTypeInIdx); + Instruction* pte_type_inst = def_use_mgr->GetDef(pte_type_id); + if (pte_type_inst->opcode() == spv::Op::OpTypeArray) { + uint32_t array_elt_type_id = pte_type_inst->GetSingleWordInOperand(0); + Instruction* arr_elt_type = def_use_mgr->GetDef(array_elt_type_id); + if (arr_elt_type->opcode() == spv::Op::OpTypeStruct) { + if (AnalyzeBuiltIn(array_elt_type_id)) continue; } } // Mark all used locations of var live diff --git a/source/opt/liveness.h b/source/opt/liveness.h index 7d8a9fb408..ce25207714 100644 --- a/source/opt/liveness.h +++ b/source/opt/liveness.h @@ -41,13 +41,13 @@ class LivenessManager { // Return true if builtin |bi| is being analyzed. bool IsAnalyzedBuiltin(uint32_t bi); - // Determine starting loc |offset| and the type |cur_type| of - // access chain |ac|. Set |no_loc| to true if no loc found. - // |is_patch| indicates if patch variable. |input| is true - // if input variable, otherwise output variable. - void AnalyzeAccessChainLoc(const Instruction* ac, - const analysis::Type** curr_type, uint32_t* offset, - bool* no_loc, bool is_patch, bool input = true); + // Return the result type of |ac| when applied to |cur_type|. Set + // |no_loc| to true if no loc found. Set |is_patch| indicates if the variable + // is a patch variable. Set |input| if the variable is an input variable. + // Otherwise it is assumed that the variable is an output variable. + uint32_t AnalyzeAccessChainLoc(const Instruction* ac, uint32_t curr_type_id, + uint32_t* offset, bool* no_loc, bool is_patch, + bool input = true); // Return size of |type_id| in units of locations uint32_t GetLocSize(const analysis::Type* type) const; @@ -69,12 +69,11 @@ class LivenessManager { void MarkLocsLive(uint32_t start, uint32_t count); // Return type of component of aggregate type |agg_type| at |index| - const analysis::Type* GetComponentType(uint32_t index, - const analysis::Type* agg_type) const; + uint32_t GetComponentType(uint32_t index, uint32_t agg_type_id) const; // Return offset of |index| into aggregate type |agg_type| in units of // input locations - uint32_t GetLocOffset(uint32_t index, const analysis::Type* agg_type) const; + uint32_t GetLocOffset(uint32_t index, uint32_t agg_type_id) const; // Populate live_locs_ and live_builtins_ void ComputeLiveness(); From 70ad4dae7dc2c2d035c288b4e9ada0d7bcc26e9b Mon Sep 17 00:00:00 2001 From: alan-baker Date: Mon, 3 Jun 2024 10:43:26 -0400 Subject: [PATCH 447/523] OpSampledImage extra validation (#5695) * Validate that the type of Image operand matches the result type's Image operand --- source/val/validate_image.cpp | 8 ++++++- test/val/val_image_test.cpp | 42 +++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index a1a76ea274..9af97b79b7 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -1005,7 +1005,8 @@ bool IsAllowedSampledImageOperand(spv::Op opcode, ValidationState_t& _) { spv_result_t ValidateSampledImage(ValidationState_t& _, const Instruction* inst) { - if (_.GetIdOpcode(inst->type_id()) != spv::Op::OpTypeSampledImage) { + auto type_inst = _.FindDef(inst->type_id()); + if (type_inst->opcode() != spv::Op::OpTypeSampledImage) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Result Type to be OpTypeSampledImage."; } @@ -1016,6 +1017,11 @@ spv_result_t ValidateSampledImage(ValidationState_t& _, << "Expected Image to be of type OpTypeImage."; } + if (type_inst->GetOperandAs(1) != image_type) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Image to have the same type as Result Type Image"; + } + ImageTypeInfo info; if (!GetImageTypeInfo(_, image_type, &info)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index 77b042f04c..e39ee36f37 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -4451,7 +4451,7 @@ TEST_F(ValidateImage, QuerySizeNotImage) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler %res1 = OpImageQuerySize %u32vec2 %sampler )"; @@ -4465,7 +4465,7 @@ TEST_F(ValidateImage, QuerySizeSampledImageDirectly) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler %res1 = OpImageQuerySize %u32vec2 %simg )"; @@ -10647,6 +10647,44 @@ TEST_F(ValidateImage, ImageMSArray_ArrayedTypeDoesNotRequireCapability) { EXPECT_THAT(getDiagnosticString(), Eq("")); } +TEST_F(ValidateImage, SampledImageTypeMismatch) { + const std::string code = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %im_var DescriptorSet 0 +OpDecorate %im_var Binding 0 +OpDecorate %s_var DescriptorSet 1 +OpDecorate %s_var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%im1_ty = OpTypeImage %float 2D 0 0 0 1 Unknown +%im2_ty = OpTypeImage %float 2D 1 0 0 1 Unknown +%s_ty = OpTypeSampler +%s_im_ty = OpTypeSampledImage %im2_ty +%ptr_im = OpTypePointer UniformConstant %im1_ty +%ptr_s = OpTypePointer UniformConstant %s_ty +%im_var = OpVariable %ptr_im UniformConstant +%s_var = OpVariable %ptr_s UniformConstant +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%im_ld = OpLoad %im1_ty %im_var +%s_ld = OpLoad %s_ty %s_var +%sampled_image = OpSampledImage %s_im_ty %im_ld %s_ld +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("Expected Image to have the same type as Result Type Image")); +} + } // namespace } // namespace val } // namespace spvtools From 4a2e0c9b3663d1bacc91821ae5699965bff4e5e9 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Mon, 3 Jun 2024 12:05:04 -0400 Subject: [PATCH 448/523] Fix comments in liveness.h (#5699) Addressed comments from #5693 that were not fixed before merging. --- source/opt/liveness.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/opt/liveness.h b/source/opt/liveness.h index ce25207714..70500059a2 100644 --- a/source/opt/liveness.h +++ b/source/opt/liveness.h @@ -41,7 +41,7 @@ class LivenessManager { // Return true if builtin |bi| is being analyzed. bool IsAnalyzedBuiltin(uint32_t bi); - // Return the result type of |ac| when applied to |cur_type|. Set + // Return the result type of |ac| when applied to |cur_type_id|. Set // |no_loc| to true if no loc found. Set |is_patch| indicates if the variable // is a patch variable. Set |input| if the variable is an input variable. // Otherwise it is assumed that the variable is an output variable. @@ -68,11 +68,11 @@ class LivenessManager { // Mark |count| locations starting at location |start|. void MarkLocsLive(uint32_t start, uint32_t count); - // Return type of component of aggregate type |agg_type| at |index| + // Return type of the member |index| in the aggregate type |agg_type_id|. uint32_t GetComponentType(uint32_t index, uint32_t agg_type_id) const; - // Return offset of |index| into aggregate type |agg_type| in units of - // input locations + // Return offset of member |index| in the aggregate type |agg_type_id| in + // units of input locations. uint32_t GetLocOffset(uint32_t index, uint32_t agg_type_id) const; // Populate live_locs_ and live_builtins_ From 6a2bdeee75eb35e5349c6993d33c9afe30237d79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 4 Jun 2024 16:18:06 +0200 Subject: [PATCH 449/523] spirv-val, core: add support for OpExtInstWithForwardRefs (#5698) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * val, core: add support for OpExtInstWithForwardRefs This commit adds validation and support for OpExtInstWithForwardRefs. This new instruction will be used for non-semantic debug info, when forward references are required. For now, this commit only fixes the code to handle this new instruction, and adds validation rules. But it does not add the pass to generate/fix the OpExtInst instruction when forward references are in use. Such pass would be useful for DXC or other tools, but I wanted to land validation rules first. This commit also bumps SPIRV-Headers to get this new opcode. --------- Signed-off-by: Nathan Gauër --- DEPS | 2 +- source/binary.cpp | 4 +- source/opcode.cpp | 10 ++ source/opcode.h | 3 + source/operand.cpp | 8 +- source/operand.h | 2 +- source/opt/ir_context.h | 4 +- source/opt/ir_loader.cpp | 10 +- source/opt/strip_debug_info_pass.cpp | 2 +- source/opt/strip_nonsemantic_info_pass.cpp | 2 +- source/text.cpp | 3 +- source/val/instruction.h | 5 +- source/val/validate_adjacency.cpp | 1 + source/val/validate_decorations.cpp | 1 + source/val/validate_extensions.cpp | 10 +- source/val/validate_id.cpp | 29 +++++- source/val/validate_layout.cpp | 2 + source/val/validation_state.cpp | 1 + test/val/val_ext_inst_test.cpp | 75 +++++++++++++++ test/val/val_extensions_test.cpp | 40 +++++++- test/val/val_id_test.cpp | 107 +++++++++++++++++++++ 21 files changed, 293 insertions(+), 28 deletions(-) diff --git a/DEPS b/DEPS index af8ad4be12..4f0ff6e7ca 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 're2_revision': '917047f3606d3ba9e2de0d383c3cd80c94ed732c', - 'spirv_headers_revision': 'ea77f2a826bc820cb8f57f9b2a7c7eccb681c731', + 'spirv_headers_revision': 'ff2afc3afc48dff4eec2a10f0212402a80708e38', } deps = { diff --git a/source/binary.cpp b/source/binary.cpp index cf1f0b7b01..a39bcf06b3 100644 --- a/source/binary.cpp +++ b/source/binary.cpp @@ -473,7 +473,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset, if (!word) return diagnostic(SPV_ERROR_INVALID_ID) << "Id is 0"; parsed_operand.type = SPV_OPERAND_TYPE_ID; - if (opcode == spv::Op::OpExtInst && parsed_operand.offset == 3) { + if (spvIsExtendedInstruction(opcode) && parsed_operand.offset == 3) { // The current word is the extended instruction set Id. // Set the extended instruction set type for the current instruction. auto ext_inst_type_iter = _.import_id_to_ext_inst_type.find(word); @@ -494,7 +494,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset, break; case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: { - assert(spv::Op::OpExtInst == opcode); + assert(spvIsExtendedInstruction(opcode)); assert(inst->ext_inst_type != SPV_EXT_INST_TYPE_NONE); spv_ext_inst_desc ext_inst; if (grammar_.lookupExtInst(inst->ext_inst_type, word, &ext_inst) == diff --git a/source/opcode.cpp b/source/opcode.cpp index 726a4e0f6b..c28f26bf70 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -720,6 +720,16 @@ bool spvOpcodeIsImageSample(const spv::Op opcode) { } } +bool spvIsExtendedInstruction(const spv::Op opcode) { + switch (opcode) { + case spv::Op::OpExtInst: + case spv::Op::OpExtInstWithForwardRefs: + return true; + default: + return false; + } +} + std::vector spvOpcodeMemorySemanticsOperandIndices(spv::Op opcode) { switch (opcode) { case spv::Op::OpMemoryBarrier: diff --git a/source/opcode.h b/source/opcode.h index 217aeb2b6f..6578e80845 100644 --- a/source/opcode.h +++ b/source/opcode.h @@ -146,6 +146,9 @@ bool spvOpcodeIsLinearAlgebra(spv::Op opcode); // Returns true for opcodes that represent image sample instructions. bool spvOpcodeIsImageSample(spv::Op opcode); +// Returns true if the opcode is either OpExtInst or OpExtInstWithForwardRefs +bool spvIsExtendedInstruction(spv::Op opcode); + // Returns a vector containing the indices of the memory semantics // operands for |opcode|. std::vector spvOpcodeMemorySemanticsOperandIndices(spv::Op opcode); diff --git a/source/operand.cpp b/source/operand.cpp index 7848846745..dc80588219 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -582,11 +582,13 @@ std::function spvOperandCanBeForwardDeclaredFunction( } std::function spvDbgInfoExtOperandCanBeForwardDeclaredFunction( - spv_ext_inst_type_t ext_type, uint32_t key) { + spv::Op opcode, spv_ext_inst_type_t ext_type, uint32_t key) { // The Vulkan debug info extended instruction set is non-semantic so allows no - // forward references ever + // forward references except if used through OpExtInstWithForwardRefs. if (ext_type == SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) { - return [](unsigned) { return false; }; + return [opcode](unsigned) { + return opcode == spv::Op::OpExtInstWithForwardRefs; + }; } // TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/532): Forward diff --git a/source/operand.h b/source/operand.h index f74c93389e..3d42a0594d 100644 --- a/source/operand.h +++ b/source/operand.h @@ -140,6 +140,6 @@ std::function spvOperandCanBeForwardDeclaredFunction( // of the operand can be forward declared. This function will // used in the SSA validation stage of the pipeline std::function spvDbgInfoExtOperandCanBeForwardDeclaredFunction( - spv_ext_inst_type_t ext_type, uint32_t key); + spv::Op opcode, spv_ext_inst_type_t ext_type, uint32_t key); #endif // SOURCE_OPERAND_H_ diff --git a/source/opt/ir_context.h b/source/opt/ir_context.h index ef7c45806a..6e1713cdfb 100644 --- a/source/opt/ir_context.h +++ b/source/opt/ir_context.h @@ -202,8 +202,8 @@ class IRContext { inline IteratorRange debugs3() const; // Iterators for debug info instructions (excluding OpLine & OpNoLine) - // contained in this module. These are OpExtInst for DebugInfo extension - // placed between section 9 and 10. + // contained in this module. These are OpExtInst & OpExtInstWithForwardRefs + // for DebugInfo extension placed between section 9 and 10. inline Module::inst_iterator ext_inst_debuginfo_begin(); inline Module::inst_iterator ext_inst_debuginfo_end(); inline IteratorRange ext_inst_debuginfo(); diff --git a/source/opt/ir_loader.cpp b/source/opt/ir_loader.cpp index e9b7bbfc2b..a78504880f 100644 --- a/source/opt/ir_loader.cpp +++ b/source/opt/ir_loader.cpp @@ -42,7 +42,7 @@ IrLoader::IrLoader(const MessageConsumer& consumer, Module* m) bool IsLineInst(const spv_parsed_instruction_t* inst) { const auto opcode = static_cast(inst->opcode); if (IsOpLineInst(opcode)) return true; - if (opcode != spv::Op::OpExtInst) return false; + if (!spvIsExtendedInstruction(opcode)) return false; if (inst->ext_inst_type != SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) return false; const uint32_t ext_inst_index = inst->words[kExtInstSetIndex]; @@ -65,7 +65,7 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { // create a new instruction, but simply keep the information in // struct DebugScope. const auto opcode = static_cast(inst->opcode); - if (opcode == spv::Op::OpExtInst && + if (spvIsExtendedInstruction(opcode) && spvExtInstIsDebugInfo(inst->ext_inst_type)) { const uint32_t ext_inst_index = inst->words[kExtInstSetIndex]; if (inst->ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 || @@ -209,10 +209,10 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { } else if (IsConstantInst(opcode) || opcode == spv::Op::OpVariable || opcode == spv::Op::OpUndef) { module_->AddGlobalValue(std::move(spv_inst)); - } else if (opcode == spv::Op::OpExtInst && + } else if (spvIsExtendedInstruction(opcode) && spvExtInstIsDebugInfo(inst->ext_inst_type)) { module_->AddExtInstDebugInfo(std::move(spv_inst)); - } else if (opcode == spv::Op::OpExtInst && + } else if (spvIsExtendedInstruction(opcode) && spvExtInstIsNonSemantic(inst->ext_inst_type)) { // If there are no functions, add the non-semantic instructions to the // global values. Otherwise append it to the list of the last function. @@ -235,7 +235,7 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) { last_dbg_scope_ = DebugScope(kNoDebugScope, kNoInlinedAt); if (last_dbg_scope_.GetLexicalScope() != kNoDebugScope) spv_inst->SetDebugScope(last_dbg_scope_); - if (opcode == spv::Op::OpExtInst && + if (spvIsExtendedInstruction(opcode) && spvExtInstIsDebugInfo(inst->ext_inst_type)) { const uint32_t ext_inst_index = inst->words[kExtInstSetIndex]; if (inst->ext_inst_type == SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100) { diff --git a/source/opt/strip_debug_info_pass.cpp b/source/opt/strip_debug_info_pass.cpp index f81bced52c..118d84656b 100644 --- a/source/opt/strip_debug_info_pass.cpp +++ b/source/opt/strip_debug_info_pass.cpp @@ -43,7 +43,7 @@ Pass::Status StripDebugInfoPass::Process() { // see if this string is used anywhere by a non-semantic instruction bool no_nonsemantic_use = def_use->WhileEachUser(&inst, [def_use](Instruction* use) { - if (use->opcode() == spv::Op::OpExtInst) { + if (spvIsExtendedInstruction(use->opcode())) { auto ext_inst_set = def_use->GetDef(use->GetSingleWordInOperand(0u)); const std::string extension_name = diff --git a/source/opt/strip_nonsemantic_info_pass.cpp b/source/opt/strip_nonsemantic_info_pass.cpp index 3886835ad7..659849efd2 100644 --- a/source/opt/strip_nonsemantic_info_pass.cpp +++ b/source/opt/strip_nonsemantic_info_pass.cpp @@ -96,7 +96,7 @@ Pass::Status StripNonSemanticInfoPass::Process() { if (!non_semantic_sets.empty()) { context()->module()->ForEachInst( [&non_semantic_sets, &to_remove](Instruction* inst) { - if (inst->opcode() == spv::Op::OpExtInst) { + if (spvIsExtendedInstruction(inst->opcode())) { if (non_semantic_sets.find(inst->GetSingleWordInOperand(0)) != non_semantic_sets.end()) { to_remove.push_back(inst); diff --git a/source/text.cpp b/source/text.cpp index 263bacd7bc..fda46ec2ef 100644 --- a/source/text.cpp +++ b/source/text.cpp @@ -227,8 +227,7 @@ spv_result_t spvTextEncodeOperand(const spvtools::AssemblyGrammar& grammar, // Set the extended instruction type. // The import set id is the 3rd operand of OpExtInst. - if (spv::Op(pInst->opcode) == spv::Op::OpExtInst && - pInst->words.size() == 4) { + if (spvIsExtendedInstruction(pInst->opcode) && pInst->words.size() == 4) { auto ext_inst_type = context->getExtInstTypeForId(pInst->words[3]); if (ext_inst_type == SPV_EXT_INST_TYPE_NONE) { return context->diagnostic() diff --git a/source/val/instruction.h b/source/val/instruction.h index c524bd3750..59e8af13b1 100644 --- a/source/val/instruction.h +++ b/source/val/instruction.h @@ -22,6 +22,7 @@ #include #include "source/ext_inst.h" +#include "source/opcode.h" #include "source/table.h" #include "spirv-tools/libspirv.h" @@ -87,13 +88,13 @@ class Instruction { } bool IsNonSemantic() const { - return opcode() == spv::Op::OpExtInst && + return spvIsExtendedInstruction(opcode()) && spvExtInstIsNonSemantic(inst_.ext_inst_type); } /// True if this is an OpExtInst for debug info extension. bool IsDebugInfo() const { - return opcode() == spv::Op::OpExtInst && + return spvIsExtendedInstruction(opcode()) && spvExtInstIsDebugInfo(inst_.ext_inst_type); } diff --git a/source/val/validate_adjacency.cpp b/source/val/validate_adjacency.cpp index 7e371c2f9f..013c167f3b 100644 --- a/source/val/validate_adjacency.cpp +++ b/source/val/validate_adjacency.cpp @@ -52,6 +52,7 @@ spv_result_t ValidateAdjacency(ValidationState_t& _) { adjacency_status == IN_NEW_FUNCTION ? IN_ENTRY_BLOCK : PHI_VALID; break; case spv::Op::OpExtInst: + case spv::Op::OpExtInstWithForwardRefs: // If it is a debug info instruction, we do not change the status to // allow debug info instructions before OpVariable in a function. // TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/533): We need diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp index ebc153c987..13b2aa2bf4 100644 --- a/source/val/validate_decorations.cpp +++ b/source/val/validate_decorations.cpp @@ -1684,6 +1684,7 @@ spv_result_t CheckIntegerWrapDecoration(ValidationState_t& vstate, case spv::Op::OpSNegate: return SPV_SUCCESS; case spv::Op::OpExtInst: + case spv::Op::OpExtInstWithForwardRefs: // TODO(dneto): Only certain extended instructions allow these // decorations. For now allow anything. return SPV_SUCCESS; diff --git a/source/val/validate_extensions.cpp b/source/val/validate_extensions.cpp index 7b73c9c6e2..05f8ca8b99 100644 --- a/source/val/validate_extensions.cpp +++ b/source/val/validate_extensions.cpp @@ -147,7 +147,7 @@ bool DoesDebugInfoOperandMatchExpectation( const Instruction* inst, uint32_t word_index) { if (inst->words().size() <= word_index) return false; auto* debug_inst = _.FindDef(inst->word(word_index)); - if (debug_inst->opcode() != spv::Op::OpExtInst || + if (!spvIsExtendedInstruction(debug_inst->opcode()) || (debug_inst->ext_inst_type() != SPV_EXT_INST_TYPE_OPENCL_DEBUGINFO_100 && debug_inst->ext_inst_type() != SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) || @@ -165,7 +165,7 @@ bool DoesDebugInfoOperandMatchExpectation( const Instruction* inst, uint32_t word_index) { if (inst->words().size() <= word_index) return false; auto* debug_inst = _.FindDef(inst->word(word_index)); - if (debug_inst->opcode() != spv::Op::OpExtInst || + if (!spvIsExtendedInstruction(debug_inst->opcode()) || (debug_inst->ext_inst_type() != SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) || !expectation( @@ -409,7 +409,7 @@ spv_result_t ValidateClspvReflectionArgumentInfo(ValidationState_t& _, spv_result_t ValidateKernelDecl(ValidationState_t& _, const Instruction* inst) { const auto decl_id = inst->GetOperandAs(4); const auto decl = _.FindDef(decl_id); - if (!decl || decl->opcode() != spv::Op::OpExtInst) { + if (!decl || !spvIsExtendedInstruction(decl->opcode())) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Kernel must be a Kernel extended instruction"; } @@ -432,7 +432,7 @@ spv_result_t ValidateKernelDecl(ValidationState_t& _, const Instruction* inst) { spv_result_t ValidateArgInfo(ValidationState_t& _, const Instruction* inst, uint32_t info_index) { auto info = _.FindDef(inst->GetOperandAs(info_index)); - if (!info || info->opcode() != spv::Op::OpExtInst) { + if (!info || !spvIsExtendedInstruction(info->opcode())) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "ArgInfo must be an ArgumentInfo extended instruction"; } @@ -3706,7 +3706,7 @@ spv_result_t ExtensionPass(ValidationState_t& _, const Instruction* inst) { const spv::Op opcode = inst->opcode(); if (opcode == spv::Op::OpExtension) return ValidateExtension(_, inst); if (opcode == spv::Op::OpExtInstImport) return ValidateExtInstImport(_, inst); - if (opcode == spv::Op::OpExtInst) return ValidateExtInst(_, inst); + if (spvIsExtendedInstruction(opcode)) return ValidateExtInst(_, inst); return SPV_SUCCESS; } diff --git a/source/val/validate_id.cpp b/source/val/validate_id.cpp index bcfeb5915e..d7d3e8f4fc 100644 --- a/source/val/validate_id.cpp +++ b/source/val/validate_id.cpp @@ -120,15 +120,16 @@ spv_result_t CheckIdDefinitionDominateUse(ValidationState_t& _) { // instruction operand's ID can be forward referenced. spv_result_t IdPass(ValidationState_t& _, Instruction* inst) { auto can_have_forward_declared_ids = - inst->opcode() == spv::Op::OpExtInst && + spvIsExtendedInstruction(inst->opcode()) && spvExtInstIsDebugInfo(inst->ext_inst_type()) ? spvDbgInfoExtOperandCanBeForwardDeclaredFunction( - inst->ext_inst_type(), inst->word(4)) + inst->opcode(), inst->ext_inst_type(), inst->word(4)) : spvOperandCanBeForwardDeclaredFunction(inst->opcode()); // Keep track of a result id defined by this instruction. 0 means it // does not define an id. uint32_t result_id = 0; + bool has_forward_declared_ids = false; for (unsigned i = 0; i < inst->operands().size(); i++) { const spv_parsed_operand_t& operand = inst->operand(i); @@ -177,6 +178,7 @@ spv_result_t IdPass(ValidationState_t& _, Instruction* inst) { !inst->IsNonSemantic() && !spvOpcodeIsDecoration(opcode) && !spvOpcodeIsBranch(opcode) && opcode != spv::Op::OpPhi && opcode != spv::Op::OpExtInst && + opcode != spv::Op::OpExtInstWithForwardRefs && opcode != spv::Op::OpExtInstImport && opcode != spv::Op::OpSelectionMerge && opcode != spv::Op::OpLoopMerge && @@ -200,6 +202,7 @@ spv_result_t IdPass(ValidationState_t& _, Instruction* inst) { ret = SPV_SUCCESS; } } else if (can_have_forward_declared_ids(i)) { + has_forward_declared_ids = true; if (spvOpcodeGeneratesType(inst->opcode()) && !_.IsForwardPointer(operand_word)) { ret = _.diag(SPV_ERROR_INVALID_ID, inst) @@ -229,12 +232,34 @@ spv_result_t IdPass(ValidationState_t& _, Instruction* inst) { << " has not been defined"; } break; + case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: + // Ideally, this check would live in validate_extensions.cpp. But since + // forward references are only allowed on non-semantic instructions, and + // ID validation is done first, we would fail with a "ID had not been + // defined" error before we could give a more helpful message. For this + // reason, this test is done here, so we can be more helpful to the + // user. + if (inst->opcode() == spv::Op::OpExtInstWithForwardRefs && + !inst->IsNonSemantic()) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "OpExtInstWithForwardRefs is only allowed with " + "non-semantic instructions."; + ret = SPV_SUCCESS; + break; default: ret = SPV_SUCCESS; break; } if (SPV_SUCCESS != ret) return ret; } + const bool must_have_forward_declared_ids = + inst->opcode() == spv::Op::OpExtInstWithForwardRefs; + if (must_have_forward_declared_ids && !has_forward_declared_ids) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Opcode OpExtInstWithForwardRefs must have at least one forward " + "declared ID."; + } + if (result_id) _.RemoveIfForwardDeclared(result_id); return SPV_SUCCESS; diff --git a/source/val/validate_layout.cpp b/source/val/validate_layout.cpp index dbc1f1e5de..3efeea62fe 100644 --- a/source/val/validate_layout.cpp +++ b/source/val/validate_layout.cpp @@ -35,6 +35,7 @@ spv_result_t ModuleScopedInstructions(ValidationState_t& _, const Instruction* inst, spv::Op opcode) { switch (opcode) { case spv::Op::OpExtInst: + case spv::Op::OpExtInstWithForwardRefs: if (spvExtInstIsDebugInfo(inst->ext_inst_type())) { const uint32_t ext_inst_index = inst->word(4); bool local_debug_info = false; @@ -243,6 +244,7 @@ spv_result_t FunctionScopedInstructions(ValidationState_t& _, break; case spv::Op::OpExtInst: + case spv::Op::OpExtInstWithForwardRefs: if (spvExtInstIsDebugInfo(inst->ext_inst_type())) { const uint32_t ext_inst_index = inst->word(4); bool local_debug_info = false; diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 316972eaa2..e4c7014f79 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -76,6 +76,7 @@ ModuleLayoutSection InstructionLayoutSection( if (current_section == kLayoutTypes) return kLayoutTypes; return kLayoutFunctionDefinitions; case spv::Op::OpExtInst: + case spv::Op::OpExtInstWithForwardRefs: // spv::Op::OpExtInst is only allowed in types section for certain // extended instruction sets. This will be checked separately. if (current_section == kLayoutTypes) return kLayoutTypes; diff --git a/test/val/val_ext_inst_test.cpp b/test/val/val_ext_inst_test.cpp index 8f0bcce14b..30f25a5b67 100644 --- a/test/val/val_ext_inst_test.cpp +++ b/test/val/val_ext_inst_test.cpp @@ -7472,6 +7472,81 @@ OpFunctionEnd } } +TEST_F(ValidateExtInst, OpExtInstWithForwardNotAllowedSemantic) { + const std::string body = R"( + OpCapability Shader + OpExtension "SPV_KHR_non_semantic_info" + OpExtension "SPV_KHR_relaxed_extended_instruction" + %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + %extinst = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpExecutionMode %2 LocalSize 1 1 1 + %3 = OpString "sample" + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %f32 = OpTypeFloat 32 + %uint_0 = OpConstant %uint 0 + %f32_0 = OpConstant %f32 0 + %f32_1 = OpConstant %f32 1 + %7 = OpTypeFunction %void + %8 = OpExtInst %void %1 DebugSource %3 %3 + %9 = OpExtInst %void %1 DebugCompilationUnit %uint_0 %uint_0 %8 %uint_0 + %10 = OpExtInstWithForwardRefs %void %1 DebugTypeFunction %uint_0 %11 + %12 = OpExtInstWithForwardRefs %void %1 DebugFunction %3 %10 %8 %uint_0 %uint_0 %11 %3 %uint_0 %uint_0 + %11 = OpExtInst %void %1 DebugTypeComposite %3 %uint_0 %8 %uint_0 %uint_0 %9 %3 %uint_0 %uint_0 %12 + %2 = OpFunction %void None %7 + %13 = OpLabel + %18 = OpExtInstWithForwardRefs %f32 %extinst FMin %f32_0 %19 + %19 = OpExtInst %f32 %extinst FMin %f32_0 %f32_1 + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(body); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpExtInstWithForwardRefs is only allowed with non-semantic " + "instructions.\n" + " %18 = OpExtInstWithForwardRefs %float %2 FMin %float_0 %19\n")); +} + +TEST_F(ValidateExtInst, OpExtInstRequiresNonSemanticBefore16) { + const std::string body = R"( + OpCapability Shader + OpExtension "SPV_KHR_non_semantic_info" + %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + %extinst = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpExecutionMode %2 LocalSize 1 1 1 + %3 = OpString "sample" + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %7 = OpTypeFunction %void + %8 = OpExtInst %void %1 DebugSource %3 %3 + %9 = OpExtInst %void %1 DebugCompilationUnit %uint_0 %uint_0 %8 %uint_0 + %10 = OpExtInstWithForwardRefs %void %1 DebugTypeFunction %uint_0 %11 + %12 = OpExtInstWithForwardRefs %void %1 DebugFunction %3 %10 %8 %uint_0 %uint_0 %11 %3 %uint_0 %uint_0 + %11 = OpExtInst %void %1 DebugTypeComposite %3 %uint_0 %8 %uint_0 %uint_0 %9 %3 %uint_0 %uint_0 %12 + %2 = OpFunction %void None %7 + %13 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(body); + ASSERT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("ExtInstWithForwardRefs requires one of the following " + "extensions: SPV_KHR_relaxed_extended_instruction \n" + " %11 = OpExtInstWithForwardRefs %void %1 " + "DebugTypeFunction %uint_0 %12\n")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/test/val/val_extensions_test.cpp b/test/val/val_extensions_test.cpp index 932bbee8f5..bdeb3293c7 100644 --- a/test/val/val_extensions_test.cpp +++ b/test/val/val_extensions_test.cpp @@ -61,7 +61,8 @@ INSTANTIATE_TEST_SUITE_P( "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_fragment_mask", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_NV_shader_subgroup_partitioned", "SPV_EXT_descriptor_indexing", - "SPV_KHR_terminate_invocation")); + "SPV_KHR_terminate_invocation", + "SPV_KHR_relaxed_extended_instruction")); INSTANTIATE_TEST_SUITE_P(FailSilently, ValidateUnknownExtensions, Values("ERROR_unknown_extension", "SPV_KHR_", @@ -550,6 +551,43 @@ INSTANTIATE_TEST_SUITE_P( })); // clang-format on +using ValidateRelaxedExtendedInstructionExt = spvtest::ValidateBase; + +TEST_F(ValidateRelaxedExtendedInstructionExt, RequiresExtension) { + const std::string str = R"( + OpCapability Shader + OpExtension "SPV_KHR_non_semantic_info" + %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpExecutionMode %2 LocalSize 1 1 1 + %3 = OpString "sample" + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %7 = OpTypeFunction %void + %8 = OpExtInst %void %1 DebugSource %3 %3 + %9 = OpExtInst %void %1 DebugCompilationUnit %uint_0 %uint_0 %8 %uint_0 + %10 = OpExtInstWithForwardRefs %void %1 DebugTypeFunction %uint_0 %11 + %12 = OpExtInstWithForwardRefs %void %1 DebugFunction %3 %10 %8 %uint_0 %uint_0 %11 %3 %uint_0 %uint_0 + %11 = OpExtInst %void %1 DebugTypeComposite %3 %uint_0 %8 %uint_0 %uint_0 %9 %3 %uint_0 %uint_0 %12 + %2 = OpFunction %void None %7 + %13 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(str.c_str()); + EXPECT_NE(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "ExtInstWithForwardRefs requires one of the following extensions:" + " SPV_KHR_relaxed_extended_instruction \n" + " %10 = OpExtInstWithForwardRefs %void %1 DebugTypeFunction %uint_0 " + "%11\n")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/test/val/val_id_test.cpp b/test/val/val_id_test.cpp index cc2973696c..c4e25620e4 100644 --- a/test/val/val_id_test.cpp +++ b/test/val/val_id_test.cpp @@ -6907,6 +6907,113 @@ TEST_P(ValidateIdWithMessage, NVBindlessSamplerInStruct) { EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } +TEST_P(ValidateIdWithMessage, OpExtInstWithForwardRefsDisallowedNoForwardRef) { + std::string spirv = R"( + OpCapability Shader + OpExtension "SPV_KHR_non_semantic_info" + OpExtension "SPV_KHR_relaxed_extended_instruction" + %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + %void = OpTypeVoid +%main_type = OpTypeFunction %void + %4 = OpExtInstWithForwardRefs %void %1 DebugInfoNone + %main = OpFunction %void None %main_type + %5 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_6); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_6)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr(make_message("Opcode OpExtInstWithForwardRefs must have at " + "least one forward declared ID."))); +} + +TEST_P(ValidateIdWithMessage, OpExtInstNoForwardRef) { + std::string spirv = R"( + OpCapability Shader + OpExtension "SPV_KHR_non_semantic_info" + OpExtension "SPV_KHR_relaxed_extended_instruction" + %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + %void = OpTypeVoid +%main_type = OpTypeFunction %void + %4 = OpExtInst %void %1 DebugInfoNone + %main = OpFunction %void None %main_type + %5 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_6); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_6)); +} + +TEST_P(ValidateIdWithMessage, + OpExtInstWithForwardRefsAllowedForwardReferenceInNonSemantic) { + std::string spirv = R"( + OpCapability Shader + OpExtension "SPV_KHR_non_semantic_info" + OpExtension "SPV_KHR_relaxed_extended_instruction" + %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpExecutionMode %2 LocalSize 1 1 1 + %3 = OpString "sample" + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %7 = OpTypeFunction %void + %8 = OpExtInst %void %1 DebugSource %3 %3 + %9 = OpExtInst %void %1 DebugCompilationUnit %uint_0 %uint_0 %8 %uint_0 + %10 = OpExtInstWithForwardRefs %void %1 DebugTypeFunction %uint_0 %11 + %12 = OpExtInstWithForwardRefs %void %1 DebugFunction %3 %10 %8 %uint_0 %uint_0 %11 %3 %uint_0 %uint_0 + %11 = OpExtInst %void %1 DebugTypeComposite %3 %uint_0 %8 %uint_0 %uint_0 %9 %3 %uint_0 %uint_0 %12 + %2 = OpFunction %void None %7 + %13 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_6); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_6)); +} + +TEST_P(ValidateIdWithMessage, OpExtInstNoForwardDeclAllowed) { + std::string spirv = R"( + OpCapability Shader + %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %2 "main" + OpExecutionMode %2 LocalSize 1 1 1 + %3 = OpString "sample" + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %7 = OpTypeFunction %void + %8 = OpExtInst %void %1 DebugSource %3 %3 + %9 = OpExtInst %void %1 DebugCompilationUnit %uint_0 %uint_0 %8 %uint_0 + %10 = OpExtInst %void %1 DebugTypeFunction %uint_0 %11 + %12 = OpExtInst %void %1 DebugFunction %3 %10 %8 %uint_0 %uint_0 %11 %3 %uint_0 %uint_0 + %11 = OpExtInst %void %1 DebugTypeComposite %3 %uint_0 %8 %uint_0 %uint_0 %9 %3 %uint_0 %uint_0 %12 + %2 = OpFunction %void None %7 + %13 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_6); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_6)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr(make_message("ID '11[%11]' has not been defined"))); +} + INSTANTIATE_TEST_SUITE_P(, ValidateIdWithMessage, ::testing::Bool()); } // namespace From 9db5b5ec19444dba6720afe165b1bd6ce08fb4bf Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 5 Jun 2024 09:22:58 -0400 Subject: [PATCH 450/523] Add assert header to val/decoration.h (#5703) Some platforms fail to compile if the cassert header is not included in decoration.h. Adding it to make those work. --- source/val/decoration.h | 1 + 1 file changed, 1 insertion(+) diff --git a/source/val/decoration.h b/source/val/decoration.h index 85755b3d04..77e0f615e1 100644 --- a/source/val/decoration.h +++ b/source/val/decoration.h @@ -15,6 +15,7 @@ #ifndef SOURCE_VAL_DECORATION_H_ #define SOURCE_VAL_DECORATION_H_ +#include #include #include #include From e1c0ad23f7458f6a78b317f8199b6b59d584fd79 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:22:32 -0700 Subject: [PATCH 451/523] build(deps): bump the github-actions group across 1 directory with 2 updates (#5702) Bumps the github-actions group with 2 updates in the / directory: [lukka/get-cmake](https://github.com/lukka/get-cmake) and [github/codeql-action](https://github.com/github/codeql-action). Updates `lukka/get-cmake` from 3.29.3 to 3.29.4 - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/c57ffe818cee3ee5f08fc1cc78c8bbede1cbbe59...85652a37b177d946c9f4fad0f696b2927ee7754d) Updates `github/codeql-action` from 3.25.6 to 3.25.8 - [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/9fdb3e49720b44c48891d036bb502feb25684276...2e230e8fe0ad3a14a340ad0815ddb96d599d2aff) --- updated-dependencies: - dependency-name: lukka/get-cmake 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/ios.yml | 2 +- .github/workflows/scorecard.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index cfd6c16de1..2deead54e7 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@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - - uses: lukka/get-cmake@c57ffe818cee3ee5f08fc1cc78c8bbede1cbbe59 # v3.29.3 + - uses: lukka/get-cmake@85652a37b177d946c9f4fad0f696b2927ee7754d # v3.29.4 - name: Download dependencies run: python3 utils/git-sync-deps # NOTE: The MacOS SDK ships universal binaries. CI should reflect this. diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 62561addb8..3aa30b6856 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@9fdb3e49720b44c48891d036bb502feb25684276 # v3.25.6 + uses: github/codeql-action/upload-sarif@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # v3.25.8 with: sarif_file: results.sarif From 7b5691084a4a54f48bb6ee36219eed06366cace3 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Wed, 5 Jun 2024 16:23:01 -0400 Subject: [PATCH 452/523] update tests for disassembly changes (#5694) * update tests for disassembly changes * use DEPS in wasm build --- DEPS | 2 +- source/wasm/build.sh | 4 ++-- test/opt/aggressive_dead_code_elim_test.cpp | 6 +++--- test/opt/spread_volatile_semantics_test.cpp | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/DEPS b/DEPS index 4f0ff6e7ca..3ecaba5b24 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 're2_revision': '917047f3606d3ba9e2de0d383c3cd80c94ed732c', - 'spirv_headers_revision': 'ff2afc3afc48dff4eec2a10f0212402a80708e38', + 'spirv_headers_revision': 'fbf2402969ed9aec34a8f8b4f5afab342319f07b', } deps = { diff --git a/source/wasm/build.sh b/source/wasm/build.sh index 69468c9ceb..f4663565e9 100755 --- a/source/wasm/build.sh +++ b/source/wasm/build.sh @@ -70,8 +70,8 @@ build() { } if [ ! -d external/spirv-headers ] ; then - echo "Fetching SPIRV-headers" - git clone https://github.com/KhronosGroup/SPIRV-Headers.git external/spirv-headers + echo "Fetching deps" + utils/git-sync-deps fi echo Building ${BASH_REMATCH[1]} diff --git a/test/opt/aggressive_dead_code_elim_test.cpp b/test/opt/aggressive_dead_code_elim_test.cpp index 845c6a5886..66f5887165 100644 --- a/test/opt/aggressive_dead_code_elim_test.cpp +++ b/test/opt/aggressive_dead_code_elim_test.cpp @@ -7568,7 +7568,7 @@ TEST_F(AggressiveDCETest, PreserveInterface) { OpExtension "SPV_KHR_ray_tracing" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 -OpEntryPoint RayGenerationNV %2 "main" %3 %4 +OpEntryPoint RayGenerationKHR %2 "main" %3 %4 OpDecorate %3 Location 0 OpDecorate %4 DescriptorSet 2 OpDecorate %4 Binding 0 @@ -7577,8 +7577,8 @@ OpDecorate %4 Binding 0 %uint = OpTypeInt 32 0 %uint_0 = OpConstant %uint 0 %float = OpTypeFloat 32 -%_ptr_CallableDataNV_float = OpTypePointer CallableDataNV %float -%3 = OpVariable %_ptr_CallableDataNV_float CallableDataNV +%_ptr_CallableDataKHR_float = OpTypePointer CallableDataKHR %float +%3 = OpVariable %_ptr_CallableDataKHR_float CallableDataKHR %13 = OpTypeAccelerationStructureKHR %_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13 %4 = OpVariable %_ptr_UniformConstant_13 UniformConstant diff --git a/test/opt/spread_volatile_semantics_test.cpp b/test/opt/spread_volatile_semantics_test.cpp index 4328c396d9..664c986f6e 100644 --- a/test/opt/spread_volatile_semantics_test.cpp +++ b/test/opt/spread_volatile_semantics_test.cpp @@ -306,7 +306,7 @@ OpDecorate %images DescriptorSet 0 OpDecorate %images Binding 1 OpDecorate %images NonWritable -; CHECK: OpEntryPoint RayGenerationNV {{%\w+}} "RayGeneration" [[var:%\w+]] +; CHECK: OpEntryPoint RayGenerationKHR {{%\w+}} "RayGeneration" [[var:%\w+]] ; CHECK: OpDecorate [[var]] BuiltIn SubgroupSize ; CHECK: OpDecorate [[var]] Volatile ; CHECK-NOT: OpDecorate {{%\w+}} Volatile @@ -397,8 +397,8 @@ OpDecorate %images DescriptorSet 0 OpDecorate %images Binding 1 OpDecorate %images NonWritable -; CHECK: OpEntryPoint RayGenerationNV {{%\w+}} "RayGeneration" [[var:%\w+]] -; CHECK: OpEntryPoint ClosestHitNV {{%\w+}} "ClosestHit" [[var]] +; CHECK: OpEntryPoint RayGenerationKHR {{%\w+}} "RayGeneration" [[var:%\w+]] +; CHECK: OpEntryPoint ClosestHitKHR {{%\w+}} "ClosestHit" [[var]] ; CHECK: OpDecorate [[var]] BuiltIn SubgroupSize ; CHECK: OpDecorate [[var]] Volatile ; CHECK-NOT: OpDecorate {{%\w+}} Volatile From ce46482db7ab3ea9c52fce832d27ca40b14f8e87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 6 Jun 2024 12:17:51 +0200 Subject: [PATCH 453/523] Add KHR suffix to OpExtInstWithForwardRef opcode. (#5704) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The KHR suffix was missing from the published SPIR-V extension. This is now fixed, but requires some patches in SPIRV-Tools. Signed-off-by: Nathan Gauër --- DEPS | 2 +- source/opcode.cpp | 2 +- source/opcode.h | 2 +- source/operand.cpp | 4 ++-- source/opt/ir_context.h | 5 +++-- source/val/validate_adjacency.cpp | 2 +- source/val/validate_decorations.cpp | 2 +- source/val/validate_id.cpp | 11 ++++++----- source/val/validate_layout.cpp | 4 ++-- source/val/validation_state.cpp | 2 +- test/val/val_ext_inst_test.cpp | 25 +++++++++++++------------ test/val/val_extensions_test.cpp | 9 +++++---- test/val/val_id_test.cpp | 13 +++++++------ 13 files changed, 44 insertions(+), 39 deletions(-) diff --git a/DEPS b/DEPS index 3ecaba5b24..5c5b2ee26c 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 're2_revision': '917047f3606d3ba9e2de0d383c3cd80c94ed732c', - 'spirv_headers_revision': 'fbf2402969ed9aec34a8f8b4f5afab342319f07b', + 'spirv_headers_revision': 'eb49bb7b1136298b77945c52b4bbbc433f7885de', } deps = { diff --git a/source/opcode.cpp b/source/opcode.cpp index c28f26bf70..5076bbddc2 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -723,7 +723,7 @@ bool spvOpcodeIsImageSample(const spv::Op opcode) { bool spvIsExtendedInstruction(const spv::Op opcode) { switch (opcode) { case spv::Op::OpExtInst: - case spv::Op::OpExtInstWithForwardRefs: + case spv::Op::OpExtInstWithForwardRefsKHR: return true; default: return false; diff --git a/source/opcode.h b/source/opcode.h index 6578e80845..cecd566330 100644 --- a/source/opcode.h +++ b/source/opcode.h @@ -146,7 +146,7 @@ bool spvOpcodeIsLinearAlgebra(spv::Op opcode); // Returns true for opcodes that represent image sample instructions. bool spvOpcodeIsImageSample(spv::Op opcode); -// Returns true if the opcode is either OpExtInst or OpExtInstWithForwardRefs +// Returns true if the opcode is either OpExtInst or OpExtInstWithForwardRefsKHR bool spvIsExtendedInstruction(spv::Op opcode); // Returns a vector containing the indices of the memory semantics diff --git a/source/operand.cpp b/source/operand.cpp index dc80588219..e15004541b 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -584,10 +584,10 @@ std::function spvOperandCanBeForwardDeclaredFunction( std::function spvDbgInfoExtOperandCanBeForwardDeclaredFunction( spv::Op opcode, spv_ext_inst_type_t ext_type, uint32_t key) { // The Vulkan debug info extended instruction set is non-semantic so allows no - // forward references except if used through OpExtInstWithForwardRefs. + // forward references except if used through OpExtInstWithForwardRefsKHR. if (ext_type == SPV_EXT_INST_TYPE_NONSEMANTIC_SHADER_DEBUGINFO_100) { return [opcode](unsigned) { - return opcode == spv::Op::OpExtInstWithForwardRefs; + return opcode == spv::Op::OpExtInstWithForwardRefsKHR; }; } diff --git a/source/opt/ir_context.h b/source/opt/ir_context.h index 6e1713cdfb..3857696618 100644 --- a/source/opt/ir_context.h +++ b/source/opt/ir_context.h @@ -202,8 +202,9 @@ class IRContext { inline IteratorRange debugs3() const; // Iterators for debug info instructions (excluding OpLine & OpNoLine) - // contained in this module. These are OpExtInst & OpExtInstWithForwardRefs - // for DebugInfo extension placed between section 9 and 10. + // contained in this module. These are OpExtInst & + // OpExtInstWithForwardRefsKHR for DebugInfo extension placed between section + // 9 and 10. inline Module::inst_iterator ext_inst_debuginfo_begin(); inline Module::inst_iterator ext_inst_debuginfo_end(); inline IteratorRange ext_inst_debuginfo(); diff --git a/source/val/validate_adjacency.cpp b/source/val/validate_adjacency.cpp index 013c167f3b..e6b00424d4 100644 --- a/source/val/validate_adjacency.cpp +++ b/source/val/validate_adjacency.cpp @@ -52,7 +52,7 @@ spv_result_t ValidateAdjacency(ValidationState_t& _) { adjacency_status == IN_NEW_FUNCTION ? IN_ENTRY_BLOCK : PHI_VALID; break; case spv::Op::OpExtInst: - case spv::Op::OpExtInstWithForwardRefs: + case spv::Op::OpExtInstWithForwardRefsKHR: // If it is a debug info instruction, we do not change the status to // allow debug info instructions before OpVariable in a function. // TODO(https://gitlab.khronos.org/spirv/SPIR-V/issues/533): We need diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp index 13b2aa2bf4..7364cab7ae 100644 --- a/source/val/validate_decorations.cpp +++ b/source/val/validate_decorations.cpp @@ -1684,7 +1684,7 @@ spv_result_t CheckIntegerWrapDecoration(ValidationState_t& vstate, case spv::Op::OpSNegate: return SPV_SUCCESS; case spv::Op::OpExtInst: - case spv::Op::OpExtInstWithForwardRefs: + case spv::Op::OpExtInstWithForwardRefsKHR: // TODO(dneto): Only certain extended instructions allow these // decorations. For now allow anything. return SPV_SUCCESS; diff --git a/source/val/validate_id.cpp b/source/val/validate_id.cpp index d7d3e8f4fc..23512125d0 100644 --- a/source/val/validate_id.cpp +++ b/source/val/validate_id.cpp @@ -178,7 +178,7 @@ spv_result_t IdPass(ValidationState_t& _, Instruction* inst) { !inst->IsNonSemantic() && !spvOpcodeIsDecoration(opcode) && !spvOpcodeIsBranch(opcode) && opcode != spv::Op::OpPhi && opcode != spv::Op::OpExtInst && - opcode != spv::Op::OpExtInstWithForwardRefs && + opcode != spv::Op::OpExtInstWithForwardRefsKHR && opcode != spv::Op::OpExtInstImport && opcode != spv::Op::OpSelectionMerge && opcode != spv::Op::OpLoopMerge && @@ -239,10 +239,10 @@ spv_result_t IdPass(ValidationState_t& _, Instruction* inst) { // defined" error before we could give a more helpful message. For this // reason, this test is done here, so we can be more helpful to the // user. - if (inst->opcode() == spv::Op::OpExtInstWithForwardRefs && + if (inst->opcode() == spv::Op::OpExtInstWithForwardRefsKHR && !inst->IsNonSemantic()) return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "OpExtInstWithForwardRefs is only allowed with " + << "OpExtInstWithForwardRefsKHR is only allowed with " "non-semantic instructions."; ret = SPV_SUCCESS; break; @@ -253,10 +253,11 @@ spv_result_t IdPass(ValidationState_t& _, Instruction* inst) { if (SPV_SUCCESS != ret) return ret; } const bool must_have_forward_declared_ids = - inst->opcode() == spv::Op::OpExtInstWithForwardRefs; + inst->opcode() == spv::Op::OpExtInstWithForwardRefsKHR; if (must_have_forward_declared_ids && !has_forward_declared_ids) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "Opcode OpExtInstWithForwardRefs must have at least one forward " + << "Opcode OpExtInstWithForwardRefsKHR must have at least one " + "forward " "declared ID."; } diff --git a/source/val/validate_layout.cpp b/source/val/validate_layout.cpp index 3efeea62fe..05a8675101 100644 --- a/source/val/validate_layout.cpp +++ b/source/val/validate_layout.cpp @@ -35,7 +35,7 @@ spv_result_t ModuleScopedInstructions(ValidationState_t& _, const Instruction* inst, spv::Op opcode) { switch (opcode) { case spv::Op::OpExtInst: - case spv::Op::OpExtInstWithForwardRefs: + case spv::Op::OpExtInstWithForwardRefsKHR: if (spvExtInstIsDebugInfo(inst->ext_inst_type())) { const uint32_t ext_inst_index = inst->word(4); bool local_debug_info = false; @@ -244,7 +244,7 @@ spv_result_t FunctionScopedInstructions(ValidationState_t& _, break; case spv::Op::OpExtInst: - case spv::Op::OpExtInstWithForwardRefs: + case spv::Op::OpExtInstWithForwardRefsKHR: if (spvExtInstIsDebugInfo(inst->ext_inst_type())) { const uint32_t ext_inst_index = inst->word(4); bool local_debug_info = false; diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index e4c7014f79..b5ed65fc25 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -76,7 +76,7 @@ ModuleLayoutSection InstructionLayoutSection( if (current_section == kLayoutTypes) return kLayoutTypes; return kLayoutFunctionDefinitions; case spv::Op::OpExtInst: - case spv::Op::OpExtInstWithForwardRefs: + case spv::Op::OpExtInstWithForwardRefsKHR: // spv::Op::OpExtInst is only allowed in types section for certain // extended instruction sets. This will be checked separately. if (current_section == kLayoutTypes) return kLayoutTypes; diff --git a/test/val/val_ext_inst_test.cpp b/test/val/val_ext_inst_test.cpp index 30f25a5b67..996b9dabc4 100644 --- a/test/val/val_ext_inst_test.cpp +++ b/test/val/val_ext_inst_test.cpp @@ -7492,12 +7492,12 @@ TEST_F(ValidateExtInst, OpExtInstWithForwardNotAllowedSemantic) { %7 = OpTypeFunction %void %8 = OpExtInst %void %1 DebugSource %3 %3 %9 = OpExtInst %void %1 DebugCompilationUnit %uint_0 %uint_0 %8 %uint_0 - %10 = OpExtInstWithForwardRefs %void %1 DebugTypeFunction %uint_0 %11 - %12 = OpExtInstWithForwardRefs %void %1 DebugFunction %3 %10 %8 %uint_0 %uint_0 %11 %3 %uint_0 %uint_0 + %10 = OpExtInstWithForwardRefsKHR %void %1 DebugTypeFunction %uint_0 %11 + %12 = OpExtInstWithForwardRefsKHR %void %1 DebugFunction %3 %10 %8 %uint_0 %uint_0 %11 %3 %uint_0 %uint_0 %11 = OpExtInst %void %1 DebugTypeComposite %3 %uint_0 %8 %uint_0 %uint_0 %9 %3 %uint_0 %uint_0 %12 %2 = OpFunction %void None %7 %13 = OpLabel - %18 = OpExtInstWithForwardRefs %f32 %extinst FMin %f32_0 %19 + %18 = OpExtInstWithForwardRefsKHR %f32 %extinst FMin %f32_0 %19 %19 = OpExtInst %f32 %extinst FMin %f32_0 %f32_1 OpReturn OpFunctionEnd @@ -7508,9 +7508,9 @@ TEST_F(ValidateExtInst, OpExtInstWithForwardNotAllowedSemantic) { EXPECT_THAT( getDiagnosticString(), HasSubstr( - "OpExtInstWithForwardRefs is only allowed with non-semantic " + "OpExtInstWithForwardRefsKHR is only allowed with non-semantic " "instructions.\n" - " %18 = OpExtInstWithForwardRefs %float %2 FMin %float_0 %19\n")); + " %18 = OpExtInstWithForwardRefsKHR %float %2 FMin %float_0 %19\n")); } TEST_F(ValidateExtInst, OpExtInstRequiresNonSemanticBefore16) { @@ -7529,8 +7529,8 @@ TEST_F(ValidateExtInst, OpExtInstRequiresNonSemanticBefore16) { %7 = OpTypeFunction %void %8 = OpExtInst %void %1 DebugSource %3 %3 %9 = OpExtInst %void %1 DebugCompilationUnit %uint_0 %uint_0 %8 %uint_0 - %10 = OpExtInstWithForwardRefs %void %1 DebugTypeFunction %uint_0 %11 - %12 = OpExtInstWithForwardRefs %void %1 DebugFunction %3 %10 %8 %uint_0 %uint_0 %11 %3 %uint_0 %uint_0 + %10 = OpExtInstWithForwardRefsKHR %void %1 DebugTypeFunction %uint_0 %11 + %12 = OpExtInstWithForwardRefsKHR %void %1 DebugFunction %3 %10 %8 %uint_0 %uint_0 %11 %3 %uint_0 %uint_0 %11 = OpExtInst %void %1 DebugTypeComposite %3 %uint_0 %8 %uint_0 %uint_0 %9 %3 %uint_0 %uint_0 %12 %2 = OpFunction %void None %7 %13 = OpLabel @@ -7540,11 +7540,12 @@ TEST_F(ValidateExtInst, OpExtInstRequiresNonSemanticBefore16) { CompileSuccessfully(body); ASSERT_EQ(SPV_ERROR_MISSING_EXTENSION, ValidateInstructions()); - EXPECT_THAT(getDiagnosticString(), - HasSubstr("ExtInstWithForwardRefs requires one of the following " - "extensions: SPV_KHR_relaxed_extended_instruction \n" - " %11 = OpExtInstWithForwardRefs %void %1 " - "DebugTypeFunction %uint_0 %12\n")); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("ExtInstWithForwardRefsKHR requires one of the following " + "extensions: SPV_KHR_relaxed_extended_instruction \n" + " %11 = OpExtInstWithForwardRefsKHR %void %1 " + "DebugTypeFunction %uint_0 %12\n")); } } // namespace diff --git a/test/val/val_extensions_test.cpp b/test/val/val_extensions_test.cpp index bdeb3293c7..bc8e9728ae 100644 --- a/test/val/val_extensions_test.cpp +++ b/test/val/val_extensions_test.cpp @@ -568,8 +568,8 @@ TEST_F(ValidateRelaxedExtendedInstructionExt, RequiresExtension) { %7 = OpTypeFunction %void %8 = OpExtInst %void %1 DebugSource %3 %3 %9 = OpExtInst %void %1 DebugCompilationUnit %uint_0 %uint_0 %8 %uint_0 - %10 = OpExtInstWithForwardRefs %void %1 DebugTypeFunction %uint_0 %11 - %12 = OpExtInstWithForwardRefs %void %1 DebugFunction %3 %10 %8 %uint_0 %uint_0 %11 %3 %uint_0 %uint_0 + %10 = OpExtInstWithForwardRefsKHR %void %1 DebugTypeFunction %uint_0 %11 + %12 = OpExtInstWithForwardRefsKHR %void %1 DebugFunction %3 %10 %8 %uint_0 %uint_0 %11 %3 %uint_0 %uint_0 %11 = OpExtInst %void %1 DebugTypeComposite %3 %uint_0 %8 %uint_0 %uint_0 %9 %3 %uint_0 %uint_0 %12 %2 = OpFunction %void None %7 %13 = OpLabel @@ -582,9 +582,10 @@ TEST_F(ValidateRelaxedExtendedInstructionExt, RequiresExtension) { EXPECT_THAT( getDiagnosticString(), HasSubstr( - "ExtInstWithForwardRefs requires one of the following extensions:" + "ExtInstWithForwardRefsKHR requires one of the following extensions:" " SPV_KHR_relaxed_extended_instruction \n" - " %10 = OpExtInstWithForwardRefs %void %1 DebugTypeFunction %uint_0 " + " %10 = OpExtInstWithForwardRefsKHR %void %1 DebugTypeFunction " + "%uint_0 " "%11\n")); } diff --git a/test/val/val_id_test.cpp b/test/val/val_id_test.cpp index c4e25620e4..c1b8e41f94 100644 --- a/test/val/val_id_test.cpp +++ b/test/val/val_id_test.cpp @@ -6907,7 +6907,8 @@ TEST_P(ValidateIdWithMessage, NVBindlessSamplerInStruct) { EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); } -TEST_P(ValidateIdWithMessage, OpExtInstWithForwardRefsDisallowedNoForwardRef) { +TEST_P(ValidateIdWithMessage, + OpExtInstWithForwardRefsKHRDisallowedNoForwardRef) { std::string spirv = R"( OpCapability Shader OpExtension "SPV_KHR_non_semantic_info" @@ -6918,7 +6919,7 @@ TEST_P(ValidateIdWithMessage, OpExtInstWithForwardRefsDisallowedNoForwardRef) { OpExecutionMode %main LocalSize 1 1 1 %void = OpTypeVoid %main_type = OpTypeFunction %void - %4 = OpExtInstWithForwardRefs %void %1 DebugInfoNone + %4 = OpExtInstWithForwardRefsKHR %void %1 DebugInfoNone %main = OpFunction %void None %main_type %5 = OpLabel OpReturn @@ -6929,7 +6930,7 @@ TEST_P(ValidateIdWithMessage, OpExtInstWithForwardRefsDisallowedNoForwardRef) { EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_6)); EXPECT_THAT( getDiagnosticString(), - HasSubstr(make_message("Opcode OpExtInstWithForwardRefs must have at " + HasSubstr(make_message("Opcode OpExtInstWithForwardRefsKHR must have at " "least one forward declared ID."))); } @@ -6956,7 +6957,7 @@ TEST_P(ValidateIdWithMessage, OpExtInstNoForwardRef) { } TEST_P(ValidateIdWithMessage, - OpExtInstWithForwardRefsAllowedForwardReferenceInNonSemantic) { + OpExtInstWithForwardRefsKHRAllowedForwardReferenceInNonSemantic) { std::string spirv = R"( OpCapability Shader OpExtension "SPV_KHR_non_semantic_info" @@ -6972,8 +6973,8 @@ TEST_P(ValidateIdWithMessage, %7 = OpTypeFunction %void %8 = OpExtInst %void %1 DebugSource %3 %3 %9 = OpExtInst %void %1 DebugCompilationUnit %uint_0 %uint_0 %8 %uint_0 - %10 = OpExtInstWithForwardRefs %void %1 DebugTypeFunction %uint_0 %11 - %12 = OpExtInstWithForwardRefs %void %1 DebugFunction %3 %10 %8 %uint_0 %uint_0 %11 %3 %uint_0 %uint_0 + %10 = OpExtInstWithForwardRefsKHR %void %1 DebugTypeFunction %uint_0 %11 + %12 = OpExtInstWithForwardRefsKHR %void %1 DebugFunction %3 %10 %8 %uint_0 %uint_0 %11 %3 %uint_0 %uint_0 %11 = OpExtInst %void %1 DebugTypeComposite %3 %uint_0 %8 %uint_0 %uint_0 %9 %3 %uint_0 %uint_0 %12 %2 = OpFunction %void None %7 %13 = OpLabel From c3178da8eac9bc7d1788e95f8d555918ba483c23 Mon Sep 17 00:00:00 2001 From: Shahbaz Youssefi Date: Mon, 10 Jun 2024 15:22:25 -0400 Subject: [PATCH 454/523] spirv-dis: add decorations to comments (#5675) --- source/disassemble.cpp | 222 +++++++++++++----- source/disassemble.h | 26 ++- test/binary_to_text_test.cpp | 420 ++++++++++++++++++++++++++++++++++- 3 files changed, 601 insertions(+), 67 deletions(-) diff --git a/source/disassemble.cpp b/source/disassemble.cpp index f8f6f44a34..8fc4ee2710 100644 --- a/source/disassemble.cpp +++ b/source/disassemble.cpp @@ -194,7 +194,27 @@ spv_result_t DisassembleTargetInstruction( return SPV_SUCCESS; } +uint32_t GetLineLengthWithoutColor(const std::string line) { + // Currently, every added color is in the form \x1b...m, so instead of doing a + // lot of string comparisons with spvtools::clr::* strings, we just ignore + // those ranges. + uint32_t length = 0; + for (size_t i = 0; i < line.size(); ++i) { + if (line[i] == '\x1b') { + do { + ++i; + } while (line[i] != 'm'); + continue; + } + + ++length; + } + + return length; +} + constexpr int kStandardIndent = 15; +constexpr uint32_t kCommentColumn = 50; } // namespace namespace disassemble { @@ -212,7 +232,8 @@ InstructionDisassembler::InstructionDisassembler(const AssemblyGrammar& grammar, comment_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_COMMENT, options)), show_byte_offset_( spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET, options)), - name_mapper_(std::move(name_mapper)) {} + name_mapper_(std::move(name_mapper)), + last_instruction_comment_alignment_(0) {} void InstructionDisassembler::EmitHeaderSpirv() { stream_ << "; SPIR-V\n"; } @@ -246,47 +267,119 @@ void InstructionDisassembler::EmitInstruction( const spv_parsed_instruction_t& inst, size_t inst_byte_offset) { auto opcode = static_cast(inst.opcode); + // To better align the comments (if any), write the instruction to a line + // first so its length can be readily available. + std::ostringstream line; + if (inst.result_id) { SetBlue(); const std::string id_name = name_mapper_(inst.result_id); if (indent_) - stream_ << std::setw(std::max(0, indent_ - 3 - int(id_name.size()))); - stream_ << "%" << id_name; + line << std::setw(std::max(0, indent_ - 3 - int(id_name.size()))); + line << "%" << id_name; ResetColor(); - stream_ << " = "; + line << " = "; } else { - stream_ << std::string(indent_, ' '); + line << std::string(indent_, ' '); } - stream_ << "Op" << spvOpcodeString(opcode); + line << "Op" << spvOpcodeString(opcode); for (uint16_t i = 0; i < inst.num_operands; i++) { const spv_operand_type_t type = inst.operands[i].type; assert(type != SPV_OPERAND_TYPE_NONE); if (type == SPV_OPERAND_TYPE_RESULT_ID) continue; - stream_ << " "; - EmitOperand(inst, i); + line << " "; + EmitOperand(line, inst, i); + } + + // For the sake of comment generation, store information from some + // instructions for the future. + if (comment_) { + GenerateCommentForDecoratedId(inst); + } + + std::ostringstream comments; + const char* comment_separator = ""; + + if (show_byte_offset_) { + SetGrey(comments); + auto saved_flags = comments.flags(); + auto saved_fill = comments.fill(); + comments << comment_separator << "0x" << std::setw(8) << std::hex + << std::setfill('0') << inst_byte_offset; + comments.flags(saved_flags); + comments.fill(saved_fill); + ResetColor(comments); + comment_separator = ", "; } if (comment_ && opcode == spv::Op::OpName) { const spv_parsed_operand_t& operand = inst.operands[0]; const uint32_t word = inst.words[operand.offset]; - stream_ << " ; id %" << word; + comments << comment_separator << "id %" << word; + comment_separator = ", "; } - if (show_byte_offset_) { - SetGrey(); - auto saved_flags = stream_.flags(); - auto saved_fill = stream_.fill(); - stream_ << " ; 0x" << std::setw(8) << std::hex << std::setfill('0') - << inst_byte_offset; - stream_.flags(saved_flags); - stream_.fill(saved_fill); - ResetColor(); + if (comment_ && inst.result_id && id_comments_.count(inst.result_id) > 0) { + comments << comment_separator << id_comments_[inst.result_id].str(); + comment_separator = ", "; } + + stream_ << line.str(); + + if (!comments.str().empty()) { + // Align the comments + const uint32_t line_length = GetLineLengthWithoutColor(line.str()); + uint32_t align = std::max( + {line_length + 2, last_instruction_comment_alignment_, kCommentColumn}); + // Round up the alignment to a multiple of 4 for more niceness. + align = (align + 3) & ~0x3u; + last_instruction_comment_alignment_ = align; + + stream_ << std::string(align - line_length, ' ') << "; " << comments.str(); + } else { + last_instruction_comment_alignment_ = 0; + } + stream_ << "\n"; } +void InstructionDisassembler::GenerateCommentForDecoratedId( + const spv_parsed_instruction_t& inst) { + assert(comment_); + auto opcode = static_cast(inst.opcode); + + std::ostringstream partial; + uint32_t id = 0; + const char* separator = ""; + + switch (opcode) { + case spv::Op::OpDecorate: + // Take everything after `OpDecorate %id` and associate it with id. + id = inst.words[inst.operands[0].offset]; + for (uint16_t i = 1; i < inst.num_operands; i++) { + partial << separator; + separator = " "; + EmitOperand(partial, inst, i); + } + break; + default: + break; + } + + if (id == 0) { + return; + } + + // Add the new comment to the comments of this id + std::ostringstream& id_comment = id_comments_[id]; + if (!id_comment.str().empty()) { + id_comment << ", "; + } + id_comment << partial.str(); +} + void InstructionDisassembler::EmitSectionComment( const spv_parsed_instruction_t& inst, bool& inserted_decoration_space, bool& inserted_debug_space, bool& inserted_type_space) { @@ -316,36 +409,37 @@ void InstructionDisassembler::EmitSectionComment( } } -void InstructionDisassembler::EmitOperand(const spv_parsed_instruction_t& inst, - const uint16_t operand_index) { +void InstructionDisassembler::EmitOperand(std::ostream& stream, + const spv_parsed_instruction_t& inst, + const uint16_t operand_index) const { assert(operand_index < inst.num_operands); const spv_parsed_operand_t& operand = inst.operands[operand_index]; const uint32_t word = inst.words[operand.offset]; switch (operand.type) { case SPV_OPERAND_TYPE_RESULT_ID: assert(false && " is not supposed to be handled here"); - SetBlue(); - stream_ << "%" << name_mapper_(word); + SetBlue(stream); + stream << "%" << name_mapper_(word); break; case SPV_OPERAND_TYPE_ID: case SPV_OPERAND_TYPE_TYPE_ID: case SPV_OPERAND_TYPE_SCOPE_ID: case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: - SetYellow(); - stream_ << "%" << name_mapper_(word); + SetYellow(stream); + stream << "%" << name_mapper_(word); break; case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: { spv_ext_inst_desc ext_inst; - SetRed(); + SetRed(stream); if (grammar_.lookupExtInst(inst.ext_inst_type, word, &ext_inst) == SPV_SUCCESS) { - stream_ << ext_inst->name; + stream << ext_inst->name; } else { if (!spvExtInstIsNonSemantic(inst.ext_inst_type)) { assert(false && "should have caught this earlier"); } else { // for non-semantic instruction sets we can just print the number - stream_ << word; + stream << word; } } } break; @@ -353,27 +447,27 @@ void InstructionDisassembler::EmitOperand(const spv_parsed_instruction_t& inst, spv_opcode_desc opcode_desc; if (grammar_.lookupOpcode(spv::Op(word), &opcode_desc)) assert(false && "should have caught this earlier"); - SetRed(); - stream_ << opcode_desc->name; + SetRed(stream); + stream << opcode_desc->name; } break; case SPV_OPERAND_TYPE_LITERAL_INTEGER: case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: case SPV_OPERAND_TYPE_LITERAL_FLOAT: { - SetRed(); - EmitNumericLiteral(&stream_, inst, operand); - ResetColor(); + SetRed(stream); + EmitNumericLiteral(&stream, inst, operand); + ResetColor(stream); } break; case SPV_OPERAND_TYPE_LITERAL_STRING: { - stream_ << "\""; - SetGreen(); + stream << "\""; + SetGreen(stream); std::string str = spvDecodeLiteralStringOperand(inst, operand_index); for (char const& c : str) { - if (c == '"' || c == '\\') stream_ << '\\'; - stream_ << c; + if (c == '"' || c == '\\') stream << '\\'; + stream << c; } - ResetColor(); - stream_ << '"'; + ResetColor(stream); + stream << '"'; } break; case SPV_OPERAND_TYPE_CAPABILITY: case SPV_OPERAND_TYPE_SOURCE_LANGUAGE: @@ -415,7 +509,7 @@ void InstructionDisassembler::EmitOperand(const spv_parsed_instruction_t& inst, spv_operand_desc entry; if (grammar_.lookupOperand(operand.type, word, &entry)) assert(false && "should have caught this earlier"); - stream_ << entry->name; + stream << entry->name; } break; case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE: case SPV_OPERAND_TYPE_FUNCTION_CONTROL: @@ -426,26 +520,27 @@ void InstructionDisassembler::EmitOperand(const spv_parsed_instruction_t& inst, case SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS: case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_INFO_FLAGS: case SPV_OPERAND_TYPE_RAW_ACCESS_CHAIN_OPERANDS: - EmitMaskOperand(operand.type, word); + EmitMaskOperand(stream, operand.type, word); break; default: if (spvOperandIsConcreteMask(operand.type)) { - EmitMaskOperand(operand.type, word); + EmitMaskOperand(stream, operand.type, word); } else if (spvOperandIsConcrete(operand.type)) { spv_operand_desc entry; if (grammar_.lookupOperand(operand.type, word, &entry)) assert(false && "should have caught this earlier"); - stream_ << entry->name; + stream << entry->name; } else { assert(false && "unhandled or invalid case"); } break; } - ResetColor(); + ResetColor(stream); } -void InstructionDisassembler::EmitMaskOperand(const spv_operand_type_t type, - const uint32_t word) { +void InstructionDisassembler::EmitMaskOperand(std::ostream& stream, + const spv_operand_type_t type, + const uint32_t word) const { // Scan the mask from least significant bit to most significant bit. For each // set bit, emit the name of that bit. Separate multiple names with '|'. uint32_t remaining_word = word; @@ -457,8 +552,8 @@ void InstructionDisassembler::EmitMaskOperand(const spv_operand_type_t type, spv_operand_desc entry; if (grammar_.lookupOperand(type, mask, &entry)) assert(false && "should have caught this earlier"); - if (num_emitted) stream_ << "|"; - stream_ << entry->name; + if (num_emitted) stream << "|"; + stream << entry->name; num_emitted++; } } @@ -467,28 +562,35 @@ void InstructionDisassembler::EmitMaskOperand(const spv_operand_type_t type, // of the 0 value. In many cases, that's "None". spv_operand_desc entry; if (SPV_SUCCESS == grammar_.lookupOperand(type, 0, &entry)) - stream_ << entry->name; + stream << entry->name; } } -void InstructionDisassembler::ResetColor() { - if (color_) stream_ << spvtools::clr::reset{print_}; +void InstructionDisassembler::ResetColor(std::ostream& stream) const { + if (color_) stream << spvtools::clr::reset{print_}; } -void InstructionDisassembler::SetGrey() { - if (color_) stream_ << spvtools::clr::grey{print_}; +void InstructionDisassembler::SetGrey(std::ostream& stream) const { + if (color_) stream << spvtools::clr::grey{print_}; } -void InstructionDisassembler::SetBlue() { - if (color_) stream_ << spvtools::clr::blue{print_}; +void InstructionDisassembler::SetBlue(std::ostream& stream) const { + if (color_) stream << spvtools::clr::blue{print_}; } -void InstructionDisassembler::SetYellow() { - if (color_) stream_ << spvtools::clr::yellow{print_}; +void InstructionDisassembler::SetYellow(std::ostream& stream) const { + if (color_) stream << spvtools::clr::yellow{print_}; } -void InstructionDisassembler::SetRed() { - if (color_) stream_ << spvtools::clr::red{print_}; +void InstructionDisassembler::SetRed(std::ostream& stream) const { + if (color_) stream << spvtools::clr::red{print_}; } -void InstructionDisassembler::SetGreen() { - if (color_) stream_ << spvtools::clr::green{print_}; +void InstructionDisassembler::SetGreen(std::ostream& stream) const { + if (color_) stream << spvtools::clr::green{print_}; } + +void InstructionDisassembler::ResetColor() { ResetColor(stream_); } +void InstructionDisassembler::SetGrey() { SetGrey(stream_); } +void InstructionDisassembler::SetBlue() { SetBlue(stream_); } +void InstructionDisassembler::SetYellow() { SetYellow(stream_); } +void InstructionDisassembler::SetRed() { SetRed(stream_); } +void InstructionDisassembler::SetGreen() { SetGreen(stream_); } } // namespace disassemble std::string spvInstructionBinaryToText(const spv_target_env env, diff --git a/source/disassemble.h b/source/disassemble.h index b520a1ea91..0dab3c5223 100644 --- a/source/disassemble.h +++ b/source/disassemble.h @@ -16,6 +16,7 @@ #define SOURCE_DISASSEMBLE_H_ #include +#include #include #include "source/name_mapper.h" @@ -74,13 +75,25 @@ class InstructionDisassembler { void SetGreen(); private: + void ResetColor(std::ostream& stream) const; + void SetGrey(std::ostream& stream) const; + void SetBlue(std::ostream& stream) const; + void SetYellow(std::ostream& stream) const; + void SetRed(std::ostream& stream) const; + void SetGreen(std::ostream& stream) const; + // Emits an operand for the given instruction, where the instruction // is at offset words from the start of the binary. - void EmitOperand(const spv_parsed_instruction_t& inst, - const uint16_t operand_index); + void EmitOperand(std::ostream& stream, const spv_parsed_instruction_t& inst, + const uint16_t operand_index) const; // Emits a mask expression for the given mask word of the specified type. - void EmitMaskOperand(const spv_operand_type_t type, const uint32_t word); + void EmitMaskOperand(std::ostream& stream, const spv_operand_type_t type, + const uint32_t word) const; + + // Generate part of the instruction as a comment to be added to + // |id_comments_|. + void GenerateCommentForDecoratedId(const spv_parsed_instruction_t& inst); const spvtools::AssemblyGrammar& grammar_; std::ostream& stream_; @@ -90,6 +103,13 @@ class InstructionDisassembler { const int comment_; // Should we comment the source const bool show_byte_offset_; // Should we print byte offset, in hex? spvtools::NameMapper name_mapper_; + + // Some comments are generated as instructions (such as OpDecorate) are + // visited so that when the instruction with that result id is visited, the + // comment can be output. + std::unordered_map id_comments_; + // Align the comments in consecutive lines for more readability. + uint32_t last_instruction_comment_alignment_; }; } // namespace disassemble diff --git a/test/binary_to_text_test.cpp b/test/binary_to_text_test.cpp index 85d5bd1d2d..d17e5011fc 100644 --- a/test/binary_to_text_test.cpp +++ b/test/binary_to_text_test.cpp @@ -494,16 +494,428 @@ OpMemoryModel Logical GLSL450 %2 = OpTypeVoid )"; const std::string expected = - R"(OpCapability Shader ; 0x00000014 -OpMemoryModel Logical GLSL450 ; 0x0000001c -%1 = OpTypeInt 32 0 ; 0x00000028 -%2 = OpTypeVoid ; 0x00000038 + R"(OpCapability Shader ; 0x00000014 +OpMemoryModel Logical GLSL450 ; 0x0000001c +%1 = OpTypeInt 32 0 ; 0x00000028 +%2 = OpTypeVoid ; 0x00000038 )"; EXPECT_THAT(EncodeAndDecodeSuccessfully( input, SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET), expected); } +TEST_F(TextToBinaryTest, Comments) { + const std::string input = R"(OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %63 "main" %4 %22 +OpExecutionMode %63 OriginUpperLeft +OpSource GLSL 450 +OpName %4 "_ue" +OpName %8 "_uf" +OpName %11 "_ug" +OpName %12 "_uA" +OpMemberName %12 0 "_ux" +OpName %14 "_uc" +OpName %15 "_uB" +OpMemberName %15 0 "_ux" +OpName %20 "_ud" +OpName %22 "_ucol" +OpName %26 "ANGLEDepthRangeParams" +OpMemberName %26 0 "near" +OpMemberName %26 1 "far" +OpMemberName %26 2 "diff" +OpMemberName %26 3 "reserved" +OpName %27 "ANGLEUniformBlock" +OpMemberName %27 0 "viewport" +OpMemberName %27 1 "clipDistancesEnabled" +OpMemberName %27 2 "xfbActiveUnpaused" +OpMemberName %27 3 "xfbVerticesPerInstance" +OpMemberName %27 4 "numSamples" +OpMemberName %27 5 "xfbBufferOffsets" +OpMemberName %27 6 "acbBufferOffsets" +OpMemberName %27 7 "depthRange" +OpName %29 "ANGLEUniforms" +OpName %33 "_uc" +OpName %32 "_uh" +OpName %49 "_ux" +OpName %50 "_uy" +OpName %48 "_ui" +OpName %63 "main" +OpName %65 "param" +OpName %68 "param" +OpName %73 "param" +OpDecorate %4 Location 0 +OpDecorate %8 RelaxedPrecision +OpDecorate %8 DescriptorSet 0 +OpDecorate %8 Binding 0 +OpDecorate %11 DescriptorSet 0 +OpDecorate %11 Binding 1 +OpMemberDecorate %12 0 Offset 0 +OpMemberDecorate %12 0 RelaxedPrecision +OpDecorate %12 Block +OpDecorate %14 DescriptorSet 0 +OpDecorate %14 Binding 2 +OpMemberDecorate %15 0 Offset 0 +OpMemberDecorate %15 0 RelaxedPrecision +OpDecorate %15 BufferBlock +OpDecorate %20 DescriptorSet 0 +OpDecorate %20 Binding 3 +OpDecorate %22 RelaxedPrecision +OpDecorate %22 Location 0 +OpMemberDecorate %26 0 Offset 0 +OpMemberDecorate %26 1 Offset 4 +OpMemberDecorate %26 2 Offset 8 +OpMemberDecorate %26 3 Offset 12 +OpMemberDecorate %27 0 Offset 0 +OpMemberDecorate %27 1 Offset 16 +OpMemberDecorate %27 2 Offset 20 +OpMemberDecorate %27 3 Offset 24 +OpMemberDecorate %27 4 Offset 28 +OpMemberDecorate %27 5 Offset 32 +OpMemberDecorate %27 6 Offset 48 +OpMemberDecorate %27 7 Offset 64 +OpMemberDecorate %27 2 RelaxedPrecision +OpMemberDecorate %27 4 RelaxedPrecision +OpDecorate %27 Block +OpDecorate %29 DescriptorSet 0 +OpDecorate %29 Binding 4 +OpDecorate %32 RelaxedPrecision +OpDecorate %33 RelaxedPrecision +OpDecorate %36 RelaxedPrecision +OpDecorate %37 RelaxedPrecision +OpDecorate %38 RelaxedPrecision +OpDecorate %39 RelaxedPrecision +OpDecorate %41 RelaxedPrecision +OpDecorate %42 RelaxedPrecision +OpDecorate %43 RelaxedPrecision +OpDecorate %48 RelaxedPrecision +OpDecorate %49 RelaxedPrecision +OpDecorate %50 RelaxedPrecision +OpDecorate %52 RelaxedPrecision +OpDecorate %53 RelaxedPrecision +OpDecorate %54 RelaxedPrecision +OpDecorate %55 RelaxedPrecision +OpDecorate %56 RelaxedPrecision +OpDecorate %57 RelaxedPrecision +OpDecorate %58 RelaxedPrecision +OpDecorate %59 RelaxedPrecision +OpDecorate %60 RelaxedPrecision +OpDecorate %67 RelaxedPrecision +OpDecorate %68 RelaxedPrecision +OpDecorate %72 RelaxedPrecision +OpDecorate %73 RelaxedPrecision +OpDecorate %75 RelaxedPrecision +OpDecorate %76 RelaxedPrecision +OpDecorate %77 RelaxedPrecision +OpDecorate %80 RelaxedPrecision +OpDecorate %81 RelaxedPrecision +%1 = OpTypeFloat 32 +%2 = OpTypeVector %1 4 +%5 = OpTypeImage %1 2D 0 0 0 1 Unknown +%6 = OpTypeSampledImage %5 +%9 = OpTypeImage %1 2D 0 0 0 2 Rgba8 +%12 = OpTypeStruct %2 +%15 = OpTypeStruct %2 +%16 = OpTypeInt 32 0 +%17 = OpConstant %16 2 +%18 = OpTypeArray %15 %17 +%23 = OpTypeInt 32 1 +%24 = OpTypeVector %23 4 +%25 = OpTypeVector %16 4 +%26 = OpTypeStruct %1 %1 %1 %1 +%27 = OpTypeStruct %2 %16 %16 %23 %23 %24 %25 %26 +%35 = OpTypeVector %1 2 +%40 = OpTypeVector %23 2 +%61 = OpTypeVoid +%69 = OpConstant %16 0 +%78 = OpConstant %16 1 +%3 = OpTypePointer Input %2 +%7 = OpTypePointer UniformConstant %6 +%10 = OpTypePointer UniformConstant %9 +%13 = OpTypePointer Uniform %12 +%19 = OpTypePointer Uniform %18 +%21 = OpTypePointer Output %2 +%28 = OpTypePointer Uniform %27 +%30 = OpTypePointer Function %2 +%70 = OpTypePointer Uniform %2 +%31 = OpTypeFunction %2 %30 +%47 = OpTypeFunction %2 %30 %30 +%62 = OpTypeFunction %61 +%4 = OpVariable %3 Input +%8 = OpVariable %7 UniformConstant +%11 = OpVariable %10 UniformConstant +%14 = OpVariable %13 Uniform +%20 = OpVariable %19 Uniform +%22 = OpVariable %21 Output +%29 = OpVariable %28 Uniform +%32 = OpFunction %2 None %31 +%33 = OpFunctionParameter %30 +%34 = OpLabel +%36 = OpLoad %6 %8 +%37 = OpLoad %2 %33 +%38 = OpVectorShuffle %35 %37 %37 0 1 +%39 = OpImageSampleImplicitLod %2 %36 %38 +%41 = OpLoad %2 %33 +%42 = OpVectorShuffle %35 %41 %41 2 3 +%43 = OpConvertFToS %40 %42 +%44 = OpLoad %9 %11 +%45 = OpImageRead %2 %44 %43 +%46 = OpFAdd %2 %39 %45 +OpReturnValue %46 +OpFunctionEnd +%48 = OpFunction %2 None %47 +%49 = OpFunctionParameter %30 +%50 = OpFunctionParameter %30 +%51 = OpLabel +%52 = OpLoad %2 %49 +%53 = OpVectorShuffle %35 %52 %52 0 1 +%54 = OpLoad %2 %50 +%55 = OpVectorShuffle %35 %54 %54 2 3 +%56 = OpCompositeExtract %1 %53 0 +%57 = OpCompositeExtract %1 %53 1 +%58 = OpCompositeExtract %1 %55 0 +%59 = OpCompositeExtract %1 %55 1 +%60 = OpCompositeConstruct %2 %56 %57 %58 %59 +OpReturnValue %60 +OpFunctionEnd +%63 = OpFunction %61 None %62 +%64 = OpLabel +%65 = OpVariable %30 Function +%68 = OpVariable %30 Function +%73 = OpVariable %30 Function +%66 = OpLoad %2 %4 +OpStore %65 %66 +%67 = OpFunctionCall %2 %32 %65 +%71 = OpAccessChain %70 %14 %69 +%72 = OpLoad %2 %71 +OpStore %68 %72 +%74 = OpAccessChain %70 %20 %69 %69 +%75 = OpLoad %2 %74 +OpStore %73 %75 +%76 = OpFunctionCall %2 %48 %68 %73 +%77 = OpFAdd %2 %67 %76 +%79 = OpAccessChain %70 %20 %78 %69 +%80 = OpLoad %2 %79 +%81 = OpFAdd %2 %77 %80 +OpStore %22 %81 +OpReturn +OpFunctionEnd +)"; + const std::string expected = R"( OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %1 "main" %2 %3 + OpExecutionMode %1 OriginUpperLeft + + ; Debug Information + OpSource GLSL 450 + OpName %2 "_ue" ; id %2 + OpName %4 "_uf" ; id %4 + OpName %5 "_ug" ; id %5 + OpName %6 "_uA" ; id %6 + OpMemberName %6 0 "_ux" + OpName %7 "_uc" ; id %7 + OpName %8 "_uB" ; id %8 + OpMemberName %8 0 "_ux" + OpName %9 "_ud" ; id %9 + OpName %3 "_ucol" ; id %3 + OpName %10 "ANGLEDepthRangeParams" ; id %10 + OpMemberName %10 0 "near" + OpMemberName %10 1 "far" + OpMemberName %10 2 "diff" + OpMemberName %10 3 "reserved" + OpName %11 "ANGLEUniformBlock" ; id %11 + OpMemberName %11 0 "viewport" + OpMemberName %11 1 "clipDistancesEnabled" + OpMemberName %11 2 "xfbActiveUnpaused" + OpMemberName %11 3 "xfbVerticesPerInstance" + OpMemberName %11 4 "numSamples" + OpMemberName %11 5 "xfbBufferOffsets" + OpMemberName %11 6 "acbBufferOffsets" + OpMemberName %11 7 "depthRange" + OpName %12 "ANGLEUniforms" ; id %12 + OpName %13 "_uc" ; id %13 + OpName %14 "_uh" ; id %14 + OpName %15 "_ux" ; id %15 + OpName %16 "_uy" ; id %16 + OpName %17 "_ui" ; id %17 + OpName %1 "main" ; id %1 + OpName %18 "param" ; id %18 + OpName %19 "param" ; id %19 + OpName %20 "param" ; id %20 + + ; Annotations + OpDecorate %2 Location 0 + OpDecorate %4 RelaxedPrecision + OpDecorate %4 DescriptorSet 0 + OpDecorate %4 Binding 0 + OpDecorate %5 DescriptorSet 0 + OpDecorate %5 Binding 1 + OpMemberDecorate %6 0 Offset 0 + OpMemberDecorate %6 0 RelaxedPrecision + OpDecorate %6 Block + OpDecorate %7 DescriptorSet 0 + OpDecorate %7 Binding 2 + OpMemberDecorate %8 0 Offset 0 + OpMemberDecorate %8 0 RelaxedPrecision + OpDecorate %8 BufferBlock + OpDecorate %9 DescriptorSet 0 + OpDecorate %9 Binding 3 + OpDecorate %3 RelaxedPrecision + OpDecorate %3 Location 0 + OpMemberDecorate %10 0 Offset 0 + OpMemberDecorate %10 1 Offset 4 + OpMemberDecorate %10 2 Offset 8 + OpMemberDecorate %10 3 Offset 12 + OpMemberDecorate %11 0 Offset 0 + OpMemberDecorate %11 1 Offset 16 + OpMemberDecorate %11 2 Offset 20 + OpMemberDecorate %11 3 Offset 24 + OpMemberDecorate %11 4 Offset 28 + OpMemberDecorate %11 5 Offset 32 + OpMemberDecorate %11 6 Offset 48 + OpMemberDecorate %11 7 Offset 64 + OpMemberDecorate %11 2 RelaxedPrecision + OpMemberDecorate %11 4 RelaxedPrecision + OpDecorate %11 Block + OpDecorate %12 DescriptorSet 0 + OpDecorate %12 Binding 4 + OpDecorate %14 RelaxedPrecision + OpDecorate %13 RelaxedPrecision + OpDecorate %21 RelaxedPrecision + OpDecorate %22 RelaxedPrecision + OpDecorate %23 RelaxedPrecision + OpDecorate %24 RelaxedPrecision + OpDecorate %25 RelaxedPrecision + OpDecorate %26 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + OpDecorate %17 RelaxedPrecision + OpDecorate %15 RelaxedPrecision + OpDecorate %16 RelaxedPrecision + OpDecorate %28 RelaxedPrecision + OpDecorate %29 RelaxedPrecision + OpDecorate %30 RelaxedPrecision + OpDecorate %31 RelaxedPrecision + OpDecorate %32 RelaxedPrecision + OpDecorate %33 RelaxedPrecision + OpDecorate %34 RelaxedPrecision + OpDecorate %35 RelaxedPrecision + OpDecorate %36 RelaxedPrecision + OpDecorate %37 RelaxedPrecision + OpDecorate %19 RelaxedPrecision + OpDecorate %38 RelaxedPrecision + OpDecorate %20 RelaxedPrecision + OpDecorate %39 RelaxedPrecision + OpDecorate %40 RelaxedPrecision + OpDecorate %41 RelaxedPrecision + OpDecorate %42 RelaxedPrecision + OpDecorate %43 RelaxedPrecision + + ; Types, variables and constants + %44 = OpTypeFloat 32 + %45 = OpTypeVector %44 4 + %46 = OpTypeImage %44 2D 0 0 0 1 Unknown + %47 = OpTypeSampledImage %46 + %48 = OpTypeImage %44 2D 0 0 0 2 Rgba8 + %6 = OpTypeStruct %45 ; Block + %8 = OpTypeStruct %45 ; BufferBlock + %49 = OpTypeInt 32 0 + %50 = OpConstant %49 2 + %51 = OpTypeArray %8 %50 + %52 = OpTypeInt 32 1 + %53 = OpTypeVector %52 4 + %54 = OpTypeVector %49 4 + %10 = OpTypeStruct %44 %44 %44 %44 + %11 = OpTypeStruct %45 %49 %49 %52 %52 %53 %54 %10 ; Block + %55 = OpTypeVector %44 2 + %56 = OpTypeVector %52 2 + %57 = OpTypeVoid + %58 = OpConstant %49 0 + %59 = OpConstant %49 1 + %60 = OpTypePointer Input %45 + %61 = OpTypePointer UniformConstant %47 + %62 = OpTypePointer UniformConstant %48 + %63 = OpTypePointer Uniform %6 + %64 = OpTypePointer Uniform %51 + %65 = OpTypePointer Output %45 + %66 = OpTypePointer Uniform %11 + %67 = OpTypePointer Function %45 + %68 = OpTypePointer Uniform %45 + %69 = OpTypeFunction %45 %67 + %70 = OpTypeFunction %45 %67 %67 + %71 = OpTypeFunction %57 + %2 = OpVariable %60 Input ; Location 0 + %4 = OpVariable %61 UniformConstant ; RelaxedPrecision, DescriptorSet 0, Binding 0 + %5 = OpVariable %62 UniformConstant ; DescriptorSet 0, Binding 1 + %7 = OpVariable %63 Uniform ; DescriptorSet 0, Binding 2 + %9 = OpVariable %64 Uniform ; DescriptorSet 0, Binding 3 + %3 = OpVariable %65 Output ; RelaxedPrecision, Location 0 + %12 = OpVariable %66 Uniform ; DescriptorSet 0, Binding 4 + + ; Function 14 + %14 = OpFunction %45 None %69 ; RelaxedPrecision + %13 = OpFunctionParameter %67 ; RelaxedPrecision + %72 = OpLabel + %21 = OpLoad %47 %4 ; RelaxedPrecision + %22 = OpLoad %45 %13 ; RelaxedPrecision + %23 = OpVectorShuffle %55 %22 %22 0 1 ; RelaxedPrecision + %24 = OpImageSampleImplicitLod %45 %21 %23 ; RelaxedPrecision + %25 = OpLoad %45 %13 ; RelaxedPrecision + %26 = OpVectorShuffle %55 %25 %25 2 3 ; RelaxedPrecision + %27 = OpConvertFToS %56 %26 ; RelaxedPrecision + %73 = OpLoad %48 %5 + %74 = OpImageRead %45 %73 %27 + %75 = OpFAdd %45 %24 %74 + OpReturnValue %75 + OpFunctionEnd + + ; Function 17 + %17 = OpFunction %45 None %70 ; RelaxedPrecision + %15 = OpFunctionParameter %67 ; RelaxedPrecision + %16 = OpFunctionParameter %67 ; RelaxedPrecision + %76 = OpLabel + %28 = OpLoad %45 %15 ; RelaxedPrecision + %29 = OpVectorShuffle %55 %28 %28 0 1 ; RelaxedPrecision + %30 = OpLoad %45 %16 ; RelaxedPrecision + %31 = OpVectorShuffle %55 %30 %30 2 3 ; RelaxedPrecision + %32 = OpCompositeExtract %44 %29 0 ; RelaxedPrecision + %33 = OpCompositeExtract %44 %29 1 ; RelaxedPrecision + %34 = OpCompositeExtract %44 %31 0 ; RelaxedPrecision + %35 = OpCompositeExtract %44 %31 1 ; RelaxedPrecision + %36 = OpCompositeConstruct %45 %32 %33 %34 %35 ; RelaxedPrecision + OpReturnValue %36 + OpFunctionEnd + + ; Function 1 + %1 = OpFunction %57 None %71 + %77 = OpLabel + %18 = OpVariable %67 Function + %19 = OpVariable %67 Function ; RelaxedPrecision + %20 = OpVariable %67 Function ; RelaxedPrecision + %78 = OpLoad %45 %2 + OpStore %18 %78 + %37 = OpFunctionCall %45 %14 %18 ; RelaxedPrecision + %79 = OpAccessChain %68 %7 %58 + %38 = OpLoad %45 %79 ; RelaxedPrecision + OpStore %19 %38 + %80 = OpAccessChain %68 %9 %58 %58 + %39 = OpLoad %45 %80 ; RelaxedPrecision + OpStore %20 %39 + %40 = OpFunctionCall %45 %17 %19 %20 ; RelaxedPrecision + %41 = OpFAdd %45 %37 %40 ; RelaxedPrecision + %81 = OpAccessChain %68 %9 %59 %58 + %42 = OpLoad %45 %81 ; RelaxedPrecision + %43 = OpFAdd %45 %41 %42 ; RelaxedPrecision + OpStore %3 %43 + OpReturn + OpFunctionEnd +)"; + + EXPECT_THAT( + EncodeAndDecodeSuccessfully(input, SPV_BINARY_TO_TEXT_OPTION_COMMENT | + SPV_BINARY_TO_TEXT_OPTION_INDENT), + expected); +} + // Test version string. TEST_F(TextToBinaryTest, VersionString) { auto words = CompileSuccessfully(""); From 65d30c31508e47d34f7698f511aea4800e3d44fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 11 Jun 2024 17:13:46 +0200 Subject: [PATCH 455/523] opt: fix Subgroup* trimming (#5706) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #5648 added support for the GroupNonUniformPartitionedNV. But there was an issue: the opcodes are enabled by multiple capabilities, and the actual operand is what matters. Added testing coverage and the implementation to correctly trim a few NonUniform capabilities. Signed-off-by: Nathan Gauër --- source/opt/trim_capabilities_pass.cpp | 32 +- source/opt/trim_capabilities_pass.h | 6 +- test/opt/trim_capabilities_pass_test.cpp | 499 +++++++++++++++++++++++ 3 files changed, 532 insertions(+), 5 deletions(-) diff --git a/source/opt/trim_capabilities_pass.cpp b/source/opt/trim_capabilities_pass.cpp index 24f9e4670e..aaf4d322a8 100644 --- a/source/opt/trim_capabilities_pass.cpp +++ b/source/opt/trim_capabilities_pass.cpp @@ -399,6 +399,33 @@ ExtensionSet getExtensionsRelatedTo(const CapabilitySet& capabilities, return output; } + +bool hasOpcodeConflictingCapabilities(spv::Op opcode) { + switch (opcode) { + case spv::Op::OpBeginInvocationInterlockEXT: + case spv::Op::OpEndInvocationInterlockEXT: + case spv::Op::OpGroupNonUniformIAdd: + case spv::Op::OpGroupNonUniformFAdd: + case spv::Op::OpGroupNonUniformIMul: + case spv::Op::OpGroupNonUniformFMul: + case spv::Op::OpGroupNonUniformSMin: + case spv::Op::OpGroupNonUniformUMin: + case spv::Op::OpGroupNonUniformFMin: + case spv::Op::OpGroupNonUniformSMax: + case spv::Op::OpGroupNonUniformUMax: + case spv::Op::OpGroupNonUniformFMax: + case spv::Op::OpGroupNonUniformBitwiseAnd: + case spv::Op::OpGroupNonUniformBitwiseOr: + case spv::Op::OpGroupNonUniformBitwiseXor: + case spv::Op::OpGroupNonUniformLogicalAnd: + case spv::Op::OpGroupNonUniformLogicalOr: + case spv::Op::OpGroupNonUniformLogicalXor: + return true; + default: + return false; + } +} + } // namespace TrimCapabilitiesPass::TrimCapabilitiesPass() @@ -416,10 +443,7 @@ 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) { + if (hasOpcodeConflictingCapabilities(opcode)) { return; } diff --git a/source/opt/trim_capabilities_pass.h b/source/opt/trim_capabilities_pass.h index 81c07b8227..3ff6dba2d2 100644 --- a/source/opt/trim_capabilities_pass.h +++ b/source/opt/trim_capabilities_pass.h @@ -81,6 +81,11 @@ class TrimCapabilitiesPass : public Pass { spv::Capability::FragmentShaderPixelInterlockEXT, spv::Capability::FragmentShaderSampleInterlockEXT, spv::Capability::FragmentShaderShadingRateInterlockEXT, + spv::Capability::GroupNonUniform, + spv::Capability::GroupNonUniformArithmetic, + spv::Capability::GroupNonUniformClustered, + spv::Capability::GroupNonUniformPartitionedNV, + spv::Capability::GroupNonUniformVote, spv::Capability::Groups, spv::Capability::ImageMSArray, spv::Capability::Int16, @@ -99,7 +104,6 @@ class TrimCapabilitiesPass : public Pass { spv::Capability::StorageUniform16, spv::Capability::StorageUniformBufferBlock16, spv::Capability::VulkanMemoryModelDeviceScope, - spv::Capability::GroupNonUniformPartitionedNV // clang-format on }; diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index d74ccdf2f8..9b2d767d59 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -2660,6 +2660,505 @@ TEST_F(TrimCapabilitiesPassTest, EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); } +TEST_F(TrimCapabilitiesPassTest, GroupNonUniform_RemovedWhenUnused) { + const std::string kTest = R"( + OpCapability Shader + OpCapability GroupNonUniformVote +; CHECK-NOT: OpCapability GroupNonUniformVote + OpCapability GroupNonUniformArithmetic +; CHECK-NOT: OpCapability GroupNonUniformArithmetic + OpCapability GroupNonUniformClustered +; CHECK-NOT: OpCapability GroupNonUniformClustered + OpCapability GroupNonUniformPartitionedNV +; CHECK-NOT: OpCapability GroupNonUniformPartitionedNV + OpCapability GroupNonUniform +; CHECK-NOT: OpCapability GroupNonUniform + OpExtension "SPV_NV_shader_subgroup_partitioned" +; CHECK-NOT: OpExtension "SPV_NV_shader_subgroup_partitioned" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + OpReturn + OpFunctionEnd; + )"; + const auto result = SinglePassRunAndMatch( + kTest, /* do_validation= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + GroupNonUniform_RemainsGroupNonUniformWhenInUse) { + const std::string kTest = R"( + OpCapability GroupNonUniformVote +; CHECK-NOT: OpCapability GroupNonUniformVote + OpCapability GroupNonUniformArithmetic +; CHECK-NOT: OpCapability GroupNonUniformArithmetic + OpCapability GroupNonUniformClustered +; CHECK-NOT: OpCapability GroupNonUniformClustered + OpCapability GroupNonUniformPartitionedNV +; CHECK-NOT: OpCapability GroupNonUniformPartitionedNV + OpCapability GroupNonUniform +; CHECK: OpCapability GroupNonUniform + OpCapability Shader + OpExtension "SPV_NV_shader_subgroup_partitioned" +; CHECK-NOT: OpExtension "SPV_NV_shader_subgroup_partitioned" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + %void = OpTypeVoid + %bool = OpTypeBool + %uint = OpTypeInt 32 0 + %scope_subgroup = OpConstant %uint 3 + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + %7 = OpGroupNonUniformElect %bool %scope_subgroup + OpReturn + OpFunctionEnd; + )"; + const auto result = SinglePassRunAndMatch( + kTest, /* do_validation= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + GroupNonUniformVote_Remains_OpGroupNonUniformAll) { + const std::string kTest = R"( + OpCapability Shader + OpCapability GroupNonUniformVote +; CHECK: OpCapability GroupNonUniformVote + OpCapability GroupNonUniformArithmetic +; CHECK-NOT: OpCapability GroupNonUniformArithmetic + OpCapability GroupNonUniformClustered +; CHECK-NOT: OpCapability GroupNonUniformClustered + OpCapability GroupNonUniformPartitionedNV +; CHECK-NOT: OpCapability GroupNonUniformPartitionedNV + OpCapability GroupNonUniform +; CHECK-NOT: OpCapability GroupNonUniform + OpExtension "SPV_NV_shader_subgroup_partitioned" +; CHECK-NOT: OpExtension "SPV_NV_shader_subgroup_partitioned" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + %void = OpTypeVoid + %bool = OpTypeBool + %uint = OpTypeInt 32 0 + %scope_subgroup = OpConstant %uint 3 + %true = OpConstantTrue %bool + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + %7 = OpGroupNonUniformAll %bool %scope_subgroup %true + OpReturn + OpFunctionEnd; + )"; + const auto result = SinglePassRunAndMatch( + kTest, /* do_validation= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + GroupNonUniformVote_Remains_OpGroupNonUniformAny) { + const std::string kTest = R"( + OpCapability Shader + OpCapability GroupNonUniformVote +; CHECK: OpCapability GroupNonUniformVote + OpCapability GroupNonUniformArithmetic +; CHECK-NOT: OpCapability GroupNonUniformArithmetic + OpCapability GroupNonUniformClustered +; CHECK-NOT: OpCapability GroupNonUniformClustered + OpCapability GroupNonUniformPartitionedNV +; CHECK-NOT: OpCapability GroupNonUniformPartitionedNV + OpCapability GroupNonUniform +; CHECK-NOT: OpCapability GroupNonUniform + OpExtension "SPV_NV_shader_subgroup_partitioned" +; CHECK-NOT: OpExtension "SPV_NV_shader_subgroup_partitioned" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + %void = OpTypeVoid + %bool = OpTypeBool + %uint = OpTypeInt 32 0 + %scope_subgroup = OpConstant %uint 3 + %true = OpConstantTrue %bool + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + %7 = OpGroupNonUniformAny %bool %scope_subgroup %true + OpReturn + OpFunctionEnd; + )"; + const auto result = SinglePassRunAndMatch( + kTest, /* do_validation= */ false); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + GroupNonUniformArithmetic_Remains_OpGroupNonUniformIAdd_Reduce) { + const std::string kTest = R"( + OpCapability Shader + OpCapability GroupNonUniformVote +; CHECK-NOT: OpCapability GroupNonUniformVote + OpCapability GroupNonUniformArithmetic +; CHECK: OpCapability GroupNonUniformArithmetic + OpCapability GroupNonUniformClustered +; CHECK-NOT: OpCapability GroupNonUniformClustered + OpCapability GroupNonUniformPartitionedNV +; CHECK-NOT: OpCapability GroupNonUniformPartitionedNV + OpCapability GroupNonUniform +; CHECK-NOT: OpCapability GroupNonUniform + OpExtension "SPV_NV_shader_subgroup_partitioned" +; CHECK-NOT: OpExtension "SPV_NV_shader_subgroup_partitioned" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + %void = OpTypeVoid + %bool = OpTypeBool + %uint = OpTypeInt 32 0 + %scope_subgroup = OpConstant %uint 3 + %uint_1 = OpConstant %uint 1 + %true = OpConstantTrue %bool + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + %7 = OpGroupNonUniformIAdd %uint %scope_subgroup Reduce %uint_1 + OpReturn + OpFunctionEnd; + )"; + const auto result = SinglePassRunAndMatch( + kTest, /* do_validation= */ true); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + GroupNonUniformArithmetic_Remains_OpGroupNonUniformIAdd_InclusiveScan) { + const std::string kTest = R"( + OpCapability Shader + OpCapability GroupNonUniformVote +; CHECK-NOT: OpCapability GroupNonUniformVote + OpCapability GroupNonUniformArithmetic +; CHECK: OpCapability GroupNonUniformArithmetic + OpCapability GroupNonUniformClustered +; CHECK-NOT: OpCapability GroupNonUniformClustered + OpCapability GroupNonUniformPartitionedNV +; CHECK-NOT: OpCapability GroupNonUniformPartitionedNV + OpCapability GroupNonUniform +; CHECK-NOT: OpCapability GroupNonUniform + OpExtension "SPV_NV_shader_subgroup_partitioned" +; CHECK-NOT: OpExtension "SPV_NV_shader_subgroup_partitioned" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + %void = OpTypeVoid + %bool = OpTypeBool + %uint = OpTypeInt 32 0 + %scope_subgroup = OpConstant %uint 3 + %uint_1 = OpConstant %uint 1 + %true = OpConstantTrue %bool + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + %7 = OpGroupNonUniformIAdd %uint %scope_subgroup InclusiveScan %uint_1 + OpReturn + OpFunctionEnd; + )"; + const auto result = SinglePassRunAndMatch( + kTest, /* do_validation= */ true); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + GroupNonUniformArithmetic_Remains_OpGroupNonUniformIAdd_ExclusiveScan) { + const std::string kTest = R"( + OpCapability Shader + OpCapability GroupNonUniformVote +; CHECK-NOT: OpCapability GroupNonUniformVote + OpCapability GroupNonUniformArithmetic +; CHECK: OpCapability GroupNonUniformArithmetic + OpCapability GroupNonUniformClustered +; CHECK-NOT: OpCapability GroupNonUniformClustered + OpCapability GroupNonUniformPartitionedNV +; CHECK-NOT: OpCapability GroupNonUniformPartitionedNV + OpCapability GroupNonUniform +; CHECK-NOT: OpCapability GroupNonUniform + OpExtension "SPV_NV_shader_subgroup_partitioned" +; CHECK-NOT: OpExtension "SPV_NV_shader_subgroup_partitioned" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + %void = OpTypeVoid + %bool = OpTypeBool + %uint = OpTypeInt 32 0 + %scope_subgroup = OpConstant %uint 3 + %uint_1 = OpConstant %uint 1 + %true = OpConstantTrue %bool + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + %7 = OpGroupNonUniformIAdd %uint %scope_subgroup ExclusiveScan %uint_1 + OpReturn + OpFunctionEnd; + )"; + const auto result = SinglePassRunAndMatch( + kTest, /* do_validation= */ true); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(TrimCapabilitiesPassTest, + GroupNonUniformClustered_Remains_OpGroupNonUniformIAdd_ClusteredReduce) { + const std::string kTest = R"( + OpCapability Shader + OpCapability GroupNonUniformVote +; CHECK-NOT: OpCapability GroupNonUniformVote + OpCapability GroupNonUniformArithmetic +; CHECK-NOT: OpCapability GroupNonUniformArithmetic + OpCapability GroupNonUniformClustered +; CHECK: OpCapability GroupNonUniformClustered + OpCapability GroupNonUniformPartitionedNV +; CHECK-NOT: OpCapability GroupNonUniformPartitionedNV + OpCapability GroupNonUniform +; CHECK-NOT: OpCapability GroupNonUniform + OpExtension "SPV_NV_shader_subgroup_partitioned" +; CHECK-NOT: OpExtension "SPV_NV_shader_subgroup_partitioned" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + %void = OpTypeVoid + %bool = OpTypeBool + %uint = OpTypeInt 32 0 + %scope_subgroup = OpConstant %uint 3 + %uint_1 = OpConstant %uint 1 + %true = OpConstantTrue %bool + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + %7 = OpGroupNonUniformIAdd %uint %scope_subgroup ClusteredReduce %uint_1 %uint_1 + OpReturn + OpFunctionEnd; + )"; + const auto result = SinglePassRunAndMatch( + kTest, /* do_validation= */ true); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +struct SubgroupTestCase { + // The result type of the subgroup instruction. + std::string resultType; + // The opcode of the subgroup instruction. + std::string opcode; + // The actual operand of the subgroup instruction. + std::string operand; +}; + +static const std::vector kSubgroupTestCases{ + // clang-format off + { "uint", "OpGroupNonUniformIAdd", "uint_1" }, + { "float", "OpGroupNonUniformFAdd", "float_1" }, + { "uint", "OpGroupNonUniformIMul", "uint_1" }, + { "float", "OpGroupNonUniformFMul", "float_1" }, + { "int", "OpGroupNonUniformSMin", "int_1" }, + { "uint", "OpGroupNonUniformUMin", "uint_1" }, + { "float", "OpGroupNonUniformFMin", "float_1" }, + { "int", "OpGroupNonUniformSMax", "int_1" }, + { "uint", "OpGroupNonUniformUMax", "uint_1" }, + { "float", "OpGroupNonUniformFMax", "float_1" }, + { "uint", "OpGroupNonUniformBitwiseAnd", "uint_1" }, + { "uint", "OpGroupNonUniformBitwiseOr", "uint_1" }, + { "uint", "OpGroupNonUniformBitwiseXor", "uint_1" }, + { "bool", "OpGroupNonUniformLogicalAnd", "true" }, + { "bool", "OpGroupNonUniformLogicalOr", "true" }, + { "bool", "OpGroupNonUniformLogicalXor", "true" } + // clang-format on +}; + +using TrimCapabilitiesPassTestSubgroupNV_Unsigned = PassTest< + ::testing::TestWithParam>>; +TEST_P(TrimCapabilitiesPassTestSubgroupNV_Unsigned, + GroupNonUniformPartitionedNV_Remains) { + SubgroupTestCase test_case = std::get<0>(GetParam()); + const std::string operation = std::get<1>(GetParam()); + + const std::string kTest = R"( + OpCapability Shader + OpCapability GroupNonUniformVote +; CHECK-NOT: OpCapability GroupNonUniformVote + OpCapability GroupNonUniformArithmetic +; CHECK-NOT: OpCapability GroupNonUniformArithmetic + OpCapability GroupNonUniformClustered +; CHECK-NOT: OpCapability GroupNonUniformClustered + OpCapability GroupNonUniformPartitionedNV +; CHECK: OpCapability GroupNonUniformPartitionedNV + OpCapability GroupNonUniform +; CHECK-NOT: OpCapability GroupNonUniform + OpExtension "SPV_NV_shader_subgroup_partitioned" +; CHECK: OpExtension "SPV_NV_shader_subgroup_partitioned" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + %void = OpTypeVoid + %bool = OpTypeBool + %uint = OpTypeInt 32 0 + %int = OpTypeInt 32 1 + %float = OpTypeFloat 32 + %v4uint = OpTypeVector %uint 4 + %scope_subgroup = OpConstant %uint 3 + %uint_1 = OpConstant %uint 1 + %int_1 = OpConstant %int 1 + %float_1 = OpConstant %float 1 + %uint4_1111 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1 + %true = OpConstantTrue %bool + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + %7 = )" + test_case.opcode + + " %" + test_case.resultType + " %scope_subgroup " + + operation + " %" + test_case.operand + + R"( %uint4_1111 + OpReturn + OpFunctionEnd; + )"; + const auto result = SinglePassRunAndMatch( + kTest, /* do_validation= */ true); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +INSTANTIATE_TEST_SUITE_P( + TrimCapabilitiesPassTestSubgroupNV_Unsigned_I, + TrimCapabilitiesPassTestSubgroupNV_Unsigned, + ::testing::Combine(::testing::ValuesIn(kSubgroupTestCases), + ::testing::Values("PartitionedReduceNV", + "PartitionedInclusiveScanNV", + "PartitionedExclusiveScanNV")), + [](const ::testing::TestParamInfo< + TrimCapabilitiesPassTestSubgroupNV_Unsigned::ParamType>& info) { + return std::get<0>(info.param).opcode + "_" + std::get<1>(info.param); + }); + +using TrimCapabilitiesPassTestSubgroupArithmetic_Unsigned = PassTest< + ::testing::TestWithParam>>; +TEST_P(TrimCapabilitiesPassTestSubgroupArithmetic_Unsigned, + GroupNonUniformPartitionedArithmetic_Remains) { + SubgroupTestCase test_case = std::get<0>(GetParam()); + const std::string operation = std::get<1>(GetParam()); + + const std::string kTest = R"( + OpCapability Shader + OpCapability GroupNonUniformVote +; CHECK-NOT: OpCapability GroupNonUniformVote + OpCapability GroupNonUniformArithmetic +; CHECK: OpCapability GroupNonUniformArithmetic + OpCapability GroupNonUniformClustered +; CHECK-NOT: OpCapability GroupNonUniformClustered + OpCapability GroupNonUniformPartitionedNV +; CHECK-NOT: OpCapability GroupNonUniformPartitionedNV + OpCapability GroupNonUniform +; CHECK-NOT: OpCapability GroupNonUniform + OpExtension "SPV_NV_shader_subgroup_partitioned" +; CHECK-NOT: OpExtension "SPV_NV_shader_subgroup_partitioned" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + %void = OpTypeVoid + %bool = OpTypeBool + %uint = OpTypeInt 32 0 + %int = OpTypeInt 32 1 + %float = OpTypeFloat 32 + %v4uint = OpTypeVector %uint 4 + %scope_subgroup = OpConstant %uint 3 + %uint_1 = OpConstant %uint 1 + %int_1 = OpConstant %int 1 + %float_1 = OpConstant %float 1 + %uint4_1111 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1 + %true = OpConstantTrue %bool + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + %7 = )" + test_case.opcode + + " %" + test_case.resultType + " %scope_subgroup " + + operation + " %" + test_case.operand + R"( %uint_1 + OpReturn + OpFunctionEnd; + )"; + const auto result = SinglePassRunAndMatch( + kTest, /* do_validation= */ true); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +INSTANTIATE_TEST_SUITE_P( + TrimCapabilitiesPassTestSubgroupArithmetic_Unsigned_I, + TrimCapabilitiesPassTestSubgroupArithmetic_Unsigned, + ::testing::Combine(::testing::ValuesIn(kSubgroupTestCases), + ::testing::Values("Reduce", "InclusiveScan", + "ExclusiveScan")), + [](const ::testing::TestParamInfo< + TrimCapabilitiesPassTestSubgroupArithmetic_Unsigned::ParamType>& info) { + return std::get<0>(info.param).opcode + "_" + std::get<1>(info.param); + }); + +using TrimCapabilitiesPassTestSubgroupClustered_Unsigned = PassTest< + ::testing::TestWithParam>>; +TEST_P(TrimCapabilitiesPassTestSubgroupClustered_Unsigned, + GroupNonUniformPartitionedClustered_Remains) { + SubgroupTestCase test_case = std::get<0>(GetParam()); + const std::string operation = std::get<1>(GetParam()); + + const std::string kTest = R"( + OpCapability Shader + OpCapability GroupNonUniformVote +; CHECK-NOT: OpCapability GroupNonUniformVote + OpCapability GroupNonUniformArithmetic +; CHECK-NOT: OpCapability GroupNonUniformArithmetic + OpCapability GroupNonUniformClustered +; CHECK: OpCapability GroupNonUniformClustered + OpCapability GroupNonUniformPartitionedNV +; CHECK-NOT: OpCapability GroupNonUniformPartitionedNV + OpCapability GroupNonUniform +; CHECK-NOT: OpCapability GroupNonUniform + OpExtension "SPV_NV_shader_subgroup_partitioned" +; CHECK-NOT: OpExtension "SPV_NV_shader_subgroup_partitioned" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 2 4 + %void = OpTypeVoid + %bool = OpTypeBool + %uint = OpTypeInt 32 0 + %int = OpTypeInt 32 1 + %float = OpTypeFloat 32 + %v4uint = OpTypeVector %uint 4 + %scope_subgroup = OpConstant %uint 3 + %uint_1 = OpConstant %uint 1 + %int_1 = OpConstant %int 1 + %float_1 = OpConstant %float 1 + %uint4_1111 = OpConstantComposite %v4uint %uint_1 %uint_1 %uint_1 %uint_1 + %true = OpConstantTrue %bool + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + %7 = )" + test_case.opcode + + " %" + test_case.resultType + " %scope_subgroup " + + operation + " %" + test_case.operand + R"( %uint_1 + OpReturn + OpFunctionEnd; + )"; + const auto result = SinglePassRunAndMatch( + kTest, /* do_validation= */ true); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +INSTANTIATE_TEST_SUITE_P( + TrimCapabilitiesPassTestSubgroupClustered_Unsigned_I, + TrimCapabilitiesPassTestSubgroupClustered_Unsigned, + ::testing::Combine(::testing::ValuesIn(kSubgroupTestCases), + ::testing::Values("ClusteredReduce")), + [](const ::testing::TestParamInfo< + TrimCapabilitiesPassTestSubgroupClustered_Unsigned::ParamType>& info) { + return std::get<0>(info.param).opcode + "_" + std::get<1>(info.param); + }); + } // namespace } // namespace opt } // namespace spvtools From bc28ac7c195f59b14535edec8472d97fd32a91ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Thu, 13 Jun 2024 11:09:58 +0200 Subject: [PATCH 456/523] opt: add OpExtInst forward ref fixup pass (#5708) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This pass fixups the opcode used for OpExtInst instructions to use OpExtInstWithForwardRefsKHR when it contains a forward reference. This pass is agnostic to the extension used, hence the validity of the code depends of the validity of the usage: If a forward reference is used on a non-semantic extended instruction, the generated code will remain invalid, but the opcode will change. What this pass guarantees is valid code won't become invalid. --------- Signed-off-by: Nathan Gauër Co-authored-by: Steven Perron --- Android.mk | 1 + BUILD.gn | 2 + include/spirv-tools/optimizer.hpp | 6 + source/opt/CMakeLists.txt | 2 + .../opt/opextinst_forward_ref_fixup_pass.cpp | 112 ++++++ source/opt/opextinst_forward_ref_fixup_pass.h | 48 +++ source/opt/optimizer.cpp | 11 +- source/opt/passes.h | 1 + test/opt/CMakeLists.txt | 1 + .../opextinst_forward_ref_fixup_pass_test.cpp | 338 ++++++++++++++++++ 10 files changed, 521 insertions(+), 1 deletion(-) create mode 100644 source/opt/opextinst_forward_ref_fixup_pass.cpp create mode 100644 source/opt/opextinst_forward_ref_fixup_pass.h create mode 100644 test/opt/opextinst_forward_ref_fixup_pass_test.cpp diff --git a/Android.mk b/Android.mk index 2357864708..af3ff30401 100644 --- a/Android.mk +++ b/Android.mk @@ -157,6 +157,7 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/merge_return_pass.cpp \ source/opt/modify_maximal_reconvergence.cpp \ source/opt/module.cpp \ + source/opt/opextinst_forward_ref_fixup_pass.cpp \ source/opt/optimizer.cpp \ source/opt/pass.cpp \ source/opt/pass_manager.cpp \ diff --git a/BUILD.gn b/BUILD.gn index 1a0f534fbb..8648043afa 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -742,6 +742,8 @@ static_library("spvtools_opt") { "source/opt/module.cpp", "source/opt/module.h", "source/opt/null_pass.h", + "source/opt/opextinst_forward_ref_fixup_pass.cpp", + "source/opt/opextinst_forward_ref_fixup_pass.h", "source/opt/optimizer.cpp", "source/opt/pass.cpp", "source/opt/pass.h", diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp index e8ac260904..216e68ade5 100644 --- a/include/spirv-tools/optimizer.hpp +++ b/include/spirv-tools/optimizer.hpp @@ -856,6 +856,12 @@ Optimizer::PassToken CreateAmdExtToKhrPass(); // propagated into their final positions. Optimizer::PassToken CreateInterpolateFixupPass(); +// Replace OpExtInst instructions with OpExtInstWithForwardRefsKHR when +// the instruction contains a forward reference to another debug instuction. +// Replace OpExtInstWithForwardRefsKHR with OpExtInst when there are no forward +// reference to another debug instruction. +Optimizer::PassToken CreateOpExtInstWithForwardReferenceFixupPass(); + // Removes unused components from composite input variables. Current // implementation just removes trailing unused components from input arrays // and structs. The pass performs best after maximizing dead code removal. diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt index 3994403eaa..51153d7ab6 100644 --- a/source/opt/CMakeLists.txt +++ b/source/opt/CMakeLists.txt @@ -71,6 +71,7 @@ set(SPIRV_TOOLS_OPT_SOURCES interface_var_sroa.h invocation_interlock_placement_pass.h interp_fixup_pass.h + opextinst_forward_ref_fixup_pass.h ir_builder.h ir_context.h ir_loader.h @@ -191,6 +192,7 @@ set(SPIRV_TOOLS_OPT_SOURCES interface_var_sroa.cpp invocation_interlock_placement_pass.cpp interp_fixup_pass.cpp + opextinst_forward_ref_fixup_pass.cpp ir_context.cpp ir_loader.cpp licm_pass.cpp diff --git a/source/opt/opextinst_forward_ref_fixup_pass.cpp b/source/opt/opextinst_forward_ref_fixup_pass.cpp new file mode 100644 index 0000000000..8684feb4e0 --- /dev/null +++ b/source/opt/opextinst_forward_ref_fixup_pass.cpp @@ -0,0 +1,112 @@ +// Copyright (c) 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/opextinst_forward_ref_fixup_pass.h" + +#include +#include + +#include "source/extensions.h" +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "type_manager.h" + +namespace spvtools { +namespace opt { +namespace { + +// Returns true if the instruction |inst| has a forward reference to another +// debug instruction. +// |debug_ids| contains the list of IDs belonging to debug instructions. +// |seen_ids| contains the list of IDs already seen. +bool HasForwardReference(const Instruction& inst, + const std::unordered_set& debug_ids, + const std::unordered_set& seen_ids) { + const uint32_t num_in_operands = inst.NumInOperands(); + for (uint32_t i = 0; i < num_in_operands; ++i) { + const Operand& op = inst.GetInOperand(i); + if (!spvIsIdType(op.type)) continue; + + if (debug_ids.count(op.AsId()) == 0) continue; + + if (seen_ids.count(op.AsId()) == 0) return true; + } + + return false; +} + +// Replace |inst| opcode with OpExtInstWithForwardRefsKHR or OpExtInst +// if required to comply with forward references. +bool ReplaceOpcodeIfRequired(Instruction& inst, bool hasForwardReferences) { + if (hasForwardReferences && + inst.opcode() != spv::Op::OpExtInstWithForwardRefsKHR) + inst.SetOpcode(spv::Op::OpExtInstWithForwardRefsKHR); + else if (!hasForwardReferences && inst.opcode() != spv::Op::OpExtInst) + inst.SetOpcode(spv::Op::OpExtInst); + else + return false; + return true; +} + +// Returns all the result IDs of the instructions in |range|. +std::unordered_set gatherResultIds( + const IteratorRange& range) { + std::unordered_set output; + for (const auto& it : range) output.insert(it.result_id()); + return output; +} + +} // namespace + +Pass::Status OpExtInstWithForwardReferenceFixupPass::Process() { + std::unordered_set seen_ids = + gatherResultIds(get_module()->ext_inst_imports()); + std::unordered_set debug_ids = + gatherResultIds(get_module()->ext_inst_debuginfo()); + for (uint32_t id : seen_ids) debug_ids.insert(id); + + bool moduleChanged = false; + bool hasAtLeastOneForwardReference = false; + IRContext* ctx = context(); + for (Instruction& inst : get_module()->ext_inst_debuginfo()) { + if (inst.opcode() != spv::Op::OpExtInst && + inst.opcode() != spv::Op::OpExtInstWithForwardRefsKHR) + continue; + + seen_ids.insert(inst.result_id()); + bool hasForwardReferences = HasForwardReference(inst, debug_ids, seen_ids); + hasAtLeastOneForwardReference |= hasForwardReferences; + + if (ReplaceOpcodeIfRequired(inst, hasForwardReferences)) { + moduleChanged = true; + ctx->AnalyzeUses(&inst); + } + } + + if (hasAtLeastOneForwardReference != + ctx->get_feature_mgr()->HasExtension( + kSPV_KHR_relaxed_extended_instruction)) { + if (hasAtLeastOneForwardReference) + ctx->AddExtension("SPV_KHR_relaxed_extended_instruction"); + else + ctx->RemoveExtension(Extension::kSPV_KHR_relaxed_extended_instruction); + moduleChanged = true; + } + + return moduleChanged ? Status::SuccessWithChange + : Status::SuccessWithoutChange; +} + +} // namespace opt +} // namespace spvtools diff --git a/source/opt/opextinst_forward_ref_fixup_pass.h b/source/opt/opextinst_forward_ref_fixup_pass.h new file mode 100644 index 0000000000..26e5b81cb4 --- /dev/null +++ b/source/opt/opextinst_forward_ref_fixup_pass.h @@ -0,0 +1,48 @@ +// Copyright (c) 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_OPEXTINST_FORWARD_REF_FIXUP_H +#define SOURCE_OPT_OPEXTINST_FORWARD_REF_FIXUP_H + +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +class OpExtInstWithForwardReferenceFixupPass : public Pass { + public: + const char* name() const override { return "fix-opextinst-opcodes"; } + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | + IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | + IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisScalarEvolution | + IRContext::kAnalysisRegisterPressure | + IRContext::kAnalysisValueNumberTable | + IRContext::kAnalysisStructuredCFG | + IRContext::kAnalysisBuiltinVarId | + IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes | + IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants; + } +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_OPEXTINST_FORWARD_REF_FIXUP_H diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index e29bbf7b27..4add68a232 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -169,7 +169,8 @@ Optimizer& Optimizer::RegisterLegalizationPasses(bool preserve_interface) { .RegisterPass(CreateAggressiveDCEPass(preserve_interface)) .RegisterPass(CreateRemoveUnusedInterfaceVariablesPass()) .RegisterPass(CreateInterpolateFixupPass()) - .RegisterPass(CreateInvocationInterlockPlacementPass()); + .RegisterPass(CreateInvocationInterlockPlacementPass()) + .RegisterPass(CreateOpExtInstWithForwardReferenceFixupPass()); } Optimizer& Optimizer::RegisterLegalizationPasses() { @@ -323,6 +324,8 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag, RegisterPass(CreateStripReflectInfoPass()); } else if (pass_name == "strip-nonsemantic") { RegisterPass(CreateStripNonSemanticInfoPass()); + } else if (pass_name == "fix-opextinst-opcodes") { + RegisterPass(CreateOpExtInstWithForwardReferenceFixupPass()); } else if (pass_name == "set-spec-const-default-value") { if (pass_args.size() > 0) { auto spec_ids_vals = @@ -1146,6 +1149,12 @@ Optimizer::PassToken CreateModifyMaximalReconvergencePass(bool add) { return MakeUnique( MakeUnique(add)); } + +Optimizer::PassToken CreateOpExtInstWithForwardReferenceFixupPass() { + return MakeUnique( + MakeUnique()); +} + } // namespace spvtools extern "C" { diff --git a/source/opt/passes.h b/source/opt/passes.h index 8b6755f413..ac68ccdc8a 100644 --- a/source/opt/passes.h +++ b/source/opt/passes.h @@ -65,6 +65,7 @@ #include "source/opt/merge_return_pass.h" #include "source/opt/modify_maximal_reconvergence.h" #include "source/opt/null_pass.h" +#include "source/opt/opextinst_forward_ref_fixup_pass.h" #include "source/opt/private_to_local_pass.h" #include "source/opt/reduce_load_size.h" #include "source/opt/redundancy_elimination.h" diff --git a/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt index 384f361040..4126452d5e 100644 --- a/test/opt/CMakeLists.txt +++ b/test/opt/CMakeLists.txt @@ -79,6 +79,7 @@ add_spvtools_unittest(TARGET opt modify_maximal_reconvergence_test.cpp module_test.cpp module_utils.h + opextinst_forward_ref_fixup_pass_test.cpp optimizer_test.cpp pass_manager_test.cpp pass_merge_return_test.cpp diff --git a/test/opt/opextinst_forward_ref_fixup_pass_test.cpp b/test/opt/opextinst_forward_ref_fixup_pass_test.cpp new file mode 100644 index 0000000000..b9ac5d27a8 --- /dev/null +++ b/test/opt/opextinst_forward_ref_fixup_pass_test.cpp @@ -0,0 +1,338 @@ +// Copyright (c) 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "spirv-tools/optimizer.hpp" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using OpExtInstForwardRefFixupPassTest = PassTest<::testing::Test>; + +TEST_F(OpExtInstForwardRefFixupPassTest, NoChangeWithougExtendedInstructions) { + const std::string kTest = R"( +; CHECK-NOT: SomeOpcode + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + %void = OpTypeVoid + %3 = OpTypeFunction %void + %main = OpFunction %void None %3 + %6 = OpLabel + OpReturn + OpFunctionEnd; + )"; + const auto result = + SinglePassRunAndMatch( + kTest, /* do_validation= */ true); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); +} + +TEST_F(OpExtInstForwardRefFixupPassTest, NoForwardRef_NoChange) { + const std::string kTest = R"(OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +%1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%3 = OpString "/usr/local/google/home/nathangauer/projects/DirectXShaderCompiler/repro.hlsl" +%4 = OpString "// RUN: %dxc -T cs_6_0 %s -E main -spirv -fspv-target-env=vulkan1.1 -fspv-debug=vulkan-with-source | FileCheck %s + +[numthreads(1, 1, 1)] +void main() { +} +" +%5 = OpString "main" +%6 = OpString "" +%7 = OpString "3f3d3740" +%8 = OpString " -E main -T cs_6_0 -spirv -fspv-target-env=vulkan1.1 -fspv-debug=vulkan-with-source -Qembed_debug" +OpName %main "main" +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%uint_3 = OpConstant %uint 3 +%uint_1 = OpConstant %uint 1 +%uint_4 = OpConstant %uint 4 +%uint_5 = OpConstant %uint 5 +%15 = OpTypeFunction %void +%16 = OpExtInst %void %1 DebugTypeFunction %uint_3 %void +%17 = OpExtInst %void %1 DebugSource %3 %4 +%18 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %17 %uint_5 +%19 = OpExtInst %void %1 DebugFunction %5 %16 %17 %uint_4 %uint_1 %18 %6 %uint_3 %uint_4 +%20 = OpExtInst %void %1 DebugEntryPoint %19 %18 %7 %8 +%main = OpFunction %void None %15 +%21 = OpLabel +%22 = OpExtInst %void %1 DebugFunctionDefinition %19 %main +%23 = OpExtInst %void %1 DebugLine %17 %uint_5 %uint_5 %uint_1 %uint_1 +OpReturn +OpFunctionEnd +)"; + SinglePassRunAndCheck( + kTest, kTest, /* skip_nop= */ false); +} + +TEST_F(OpExtInstForwardRefFixupPassTest, + NoForwardRef_ReplaceOpExtInstWithForwardWithOpExtInst) { + const std::string kTest = R"( + OpCapability Shader + OpExtension "SPV_KHR_non_semantic_info" + OpExtension "SPV_KHR_relaxed_extended_instruction" +; CHECK-NOT: OpExtension "SPV_KHR_relaxed_extended_instruction" + %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + %3 = OpString "/usr/local/google/home/nathangauer/projects/DirectXShaderCompiler/repro.hlsl" + %4 = OpString "// RUN: %dxc -T cs_6_0 %s -E main -spirv -fspv-target-env=vulkan1.1 -fspv-debug=vulkan-with-source | FileCheck %s + +[numthreads(1, 1, 1)] +void main() { +} +" + %5 = OpString "main" + %6 = OpString "" + %7 = OpString "3f3d3740" + %8 = OpString " -E main -T cs_6_0 -spirv -fspv-target-env=vulkan1.1 -fspv-debug=vulkan-with-source -Qembed_debug" + OpName %main "main" + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %uint_3 = OpConstant %uint 3 + %uint_1 = OpConstant %uint 1 + %uint_4 = OpConstant %uint 4 + %uint_5 = OpConstant %uint 5 + %20 = OpTypeFunction %void + %10 = OpExtInstWithForwardRefsKHR %void %1 DebugTypeFunction %uint_3 %void + %12 = OpExtInstWithForwardRefsKHR %void %1 DebugSource %3 %4 + %13 = OpExtInstWithForwardRefsKHR %void %1 DebugCompilationUnit %uint_1 %uint_4 %12 %uint_5 + %17 = OpExtInstWithForwardRefsKHR %void %1 DebugFunction %5 %10 %12 %uint_4 %uint_1 %13 %6 %uint_3 %uint_4 + %18 = OpExtInstWithForwardRefsKHR %void %1 DebugEntryPoint %17 %13 %7 %8 +; CHECK-NOT: {{.*}} = OpExtInstWithForwardRefsKHR %void %1 DebugTypeFunction %uint_3 %void +; CHECK-NOT: {{.*}} = OpExtInstWithForwardRefsKHR %void %1 DebugSource {{.*}} {{.*}} +; CHECK-NOT: {{.*}} = OpExtInstWithForwardRefsKHR %void %1 DebugCompilationUnit %uint_1 %uint_4 {{.*}} %uint_5 +; CHECK-NOT: {{.*}} = OpExtInstWithForwardRefsKHR %void %1 DebugFunction {{.*}} {{.*}} {{.*}} %uint_4 %uint_1 {{.*}} {{.*}} %uint_3 %uint_4 +; CHECK-NOT: {{.*}} = OpExtInstWithForwardRefsKHR %void %1 DebugEntryPoint {{.*}} {{.*}} {{.*}} {{.*}} +; CHECK: {{.*}} = OpExtInst %void %1 DebugTypeFunction %uint_3 %void +; CHECK: {{.*}} = OpExtInst %void %1 DebugSource {{.*}} {{.*}} +; CHECK: {{.*}} = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 {{.*}} %uint_5 +; CHECK: {{.*}} = OpExtInst %void %1 DebugFunction {{.*}} {{.*}} {{.*}} %uint_4 %uint_1 {{.*}} {{.*}} %uint_3 %uint_4 +; CHECK: {{.*}} = OpExtInst %void %1 DebugEntryPoint {{.*}} {{.*}} {{.*}} {{.*}} + %main = OpFunction %void None %20 + %21 = OpLabel + %22 = OpExtInst %void %1 DebugFunctionDefinition %17 %main + %23 = OpExtInst %void %1 DebugLine %12 %uint_5 %uint_5 %uint_1 %uint_1 +; CHECK: {{.*}} = OpExtInst %void %1 DebugFunctionDefinition {{.*}} %main +; CHECK: {{.*}} = OpExtInst %void %1 DebugLine {{.*}} %uint_5 %uint_5 %uint_1 %uint_1 + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch( + kTest, /* do_validation= */ true); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +TEST_F(OpExtInstForwardRefFixupPassTest, ForwardRefs_NoChange) { + const std::string kTest = R"(OpCapability Shader +OpExtension "SPV_KHR_non_semantic_info" +OpExtension "SPV_KHR_relaxed_extended_instruction" +%1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%3 = OpString "/usr/local/google/home/nathangauer/projects/DirectXShaderCompiler/repro.hlsl" +%4 = OpString "// RUN: %dxc -T cs_6_0 %s -E main -spirv -fspv-target-env=vulkan1.1 -fspv-debug=vulkan-with-source | FileCheck %s + +class A { + void foo() { + } +}; + +[numthreads(1, 1, 1)] +void main() { + A a; + a.foo(); +} +" +%5 = OpString "A" +%6 = OpString "A.foo" +%7 = OpString "" +%8 = OpString "this" +%9 = OpString "main" +%10 = OpString "a" +%11 = OpString "d59ae9c2" +%12 = OpString " -E main -T cs_6_0 -spirv -fspv-target-env=vulkan1.1 -fspv-debug=vulkan-with-source -Vd -Qembed_debug" +OpName %main "main" +OpName %A "A" +%void = OpTypeVoid +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 +%uint_4 = OpConstant %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_0 = OpConstant %uint 0 +%uint_3 = OpConstant %uint 3 +%uint_7 = OpConstant %uint 7 +%uint_288 = OpConstant %uint 288 +%uint_9 = OpConstant %uint 9 +%uint_13 = OpConstant %uint 13 +%uint_10 = OpConstant %uint 10 +%26 = OpTypeFunction %void +%uint_12 = OpConstant %uint 12 +%A = OpTypeStruct +%_ptr_Function_A = OpTypePointer Function %A +%uint_11 = OpConstant %uint 11 +%30 = OpExtInst %void %1 DebugExpression +%31 = OpExtInst %void %1 DebugSource %3 %4 +%32 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %31 %uint_5 +%33 = OpExtInstWithForwardRefsKHR %void %1 DebugTypeComposite %5 %uint_0 %31 %uint_3 %uint_7 %32 %5 %uint_0 %uint_3 %34 +%35 = OpExtInst %void %1 DebugTypeFunction %uint_3 %void %33 +%34 = OpExtInst %void %1 DebugFunction %6 %35 %31 %uint_4 %uint_3 %33 %7 %uint_3 %uint_4 +%36 = OpExtInst %void %1 DebugLocalVariable %8 %33 %31 %uint_4 %uint_3 %34 %uint_288 %uint_1 +%37 = OpExtInst %void %1 DebugTypeFunction %uint_3 %void +%38 = OpExtInst %void %1 DebugFunction %9 %37 %31 %uint_9 %uint_1 %32 %7 %uint_3 %uint_9 +%39 = OpExtInst %void %1 DebugLexicalBlock %31 %uint_9 %uint_13 %38 +%40 = OpExtInst %void %1 DebugLocalVariable %10 %33 %31 %uint_10 %uint_5 %39 %uint_4 +%41 = OpExtInst %void %1 DebugEntryPoint %38 %32 %11 %12 +%42 = OpExtInst %void %1 DebugInlinedAt %uint_11 %39 +%main = OpFunction %void None %26 +%43 = OpLabel +%44 = OpVariable %_ptr_Function_A Function +%45 = OpExtInst %void %1 DebugFunctionDefinition %38 %main +%57 = OpExtInst %void %1 DebugScope %39 +%47 = OpExtInst %void %1 DebugLine %31 %uint_10 %uint_10 %uint_3 %uint_5 +%48 = OpExtInst %void %1 DebugDeclare %40 %44 %30 +%58 = OpExtInst %void %1 DebugScope %34 %42 +%50 = OpExtInst %void %1 DebugLine %31 %uint_4 %uint_5 %uint_3 %uint_3 +%51 = OpExtInst %void %1 DebugDeclare %36 %44 %30 +%59 = OpExtInst %void %1 DebugNoScope +%53 = OpExtInst %void %1 DebugLine %31 %uint_12 %uint_12 %uint_1 %uint_1 +OpReturn +OpFunctionEnd +)"; + SinglePassRunAndCheck( + kTest, kTest, /* skip_nop= */ false); +} + +TEST_F(OpExtInstForwardRefFixupPassTest, + ForwardRefs_ReplaceOpExtInstWithOpExtInstWithForwardRefs) { + const std::string kTest = R"( + OpCapability Shader + OpExtension "SPV_KHR_non_semantic_info" +; CHECK: OpExtension "SPV_KHR_relaxed_extended_instruction" + %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + %3 = OpString "/usr/local/google/home/nathangauer/projects/DirectXShaderCompiler/repro.hlsl" + %4 = OpString "// RUN: %dxc -T cs_6_0 %s -E main -spirv -fspv-target-env=vulkan1.1 -fspv-debug=vulkan-with-source | FileCheck %s + +class A { + void foo() { + } +}; + +[numthreads(1, 1, 1)] +void main() { + A a; + a.foo(); +} +" + %5 = OpString "A" + %6 = OpString "A.foo" + %7 = OpString "" + %8 = OpString "this" + %9 = OpString "main" + %10 = OpString "a" + %11 = OpString "d59ae9c2" + %12 = OpString " -E main -T cs_6_0 -spirv -fspv-target-env=vulkan1.1 -fspv-debug=vulkan-with-source -Vd -Qembed_debug" + OpName %main "main" + OpName %A "A" + %void = OpTypeVoid + %uint = OpTypeInt 32 0 + %uint_1 = OpConstant %uint 1 + %uint_4 = OpConstant %uint 4 + %uint_5 = OpConstant %uint 5 + %uint_0 = OpConstant %uint 0 + %uint_3 = OpConstant %uint 3 + %uint_7 = OpConstant %uint 7 + %uint_288 = OpConstant %uint 288 + %uint_9 = OpConstant %uint 9 + %uint_13 = OpConstant %uint 13 + %uint_10 = OpConstant %uint 10 + %40 = OpTypeFunction %void + %uint_12 = OpConstant %uint 12 + %A = OpTypeStruct + %_ptr_Function_A = OpTypePointer Function %A + %uint_11 = OpConstant %uint 11 + %15 = OpExtInst %void %1 DebugExpression + %16 = OpExtInst %void %1 DebugSource %3 %4 + %17 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %16 %uint_5 + %21 = OpExtInst %void %1 DebugTypeComposite %5 %uint_0 %16 %uint_3 %uint_7 %17 %5 %uint_0 %uint_3 %25 + %26 = OpExtInst %void %1 DebugTypeFunction %uint_3 %void %21 + %25 = OpExtInst %void %1 DebugFunction %6 %26 %16 %uint_4 %uint_3 %21 %7 %uint_3 %uint_4 + %27 = OpExtInst %void %1 DebugLocalVariable %8 %21 %16 %uint_4 %uint_3 %25 %uint_288 %uint_1 + %29 = OpExtInst %void %1 DebugTypeFunction %uint_3 %void + %30 = OpExtInst %void %1 DebugFunction %9 %29 %16 %uint_9 %uint_1 %17 %7 %uint_3 %uint_9 + %32 = OpExtInst %void %1 DebugLexicalBlock %16 %uint_9 %uint_13 %30 + %34 = OpExtInst %void %1 DebugLocalVariable %10 %21 %16 %uint_10 %uint_5 %32 %uint_4 + %36 = OpExtInst %void %1 DebugEntryPoint %30 %17 %11 %12 + %37 = OpExtInst %void %1 DebugInlinedAt %uint_11 %32 +; CHECK: {{.*}} = OpExtInst %void %1 DebugExpression +; CHECK: {{.*}} = OpExtInst %void %1 DebugSource +; CHECK: {{.*}} = OpExtInst %void %1 DebugCompilationUnit +; CHECK: {{.*}} = OpExtInstWithForwardRefsKHR %void {{.*}} DebugTypeComposite +; CHECK-NOT: {{.*}} = OpExtInst %void {{.*}} DebugTypeComposite +; CHECK: {{.*}} = OpExtInst %void %1 DebugTypeFunction +; CHECK: {{.*}} = OpExtInst %void %1 DebugFunction +; CHECK: {{.*}} = OpExtInst %void %1 DebugLocalVariable +; CHECK: {{.*}} = OpExtInst %void %1 DebugTypeFunction +; CHECK: {{.*}} = OpExtInst %void %1 DebugFunction +; CHECK: {{.*}} = OpExtInst %void %1 DebugLexicalBlock +; CHECK: {{.*}} = OpExtInst %void %1 DebugLocalVariable +; CHECK: {{.*}} = OpExtInst %void %1 DebugEntryPoint +; CHECK: {{.*}} = OpExtInst %void %1 DebugInlinedAt + %main = OpFunction %void None %40 + %43 = OpLabel + %44 = OpVariable %_ptr_Function_A Function + %45 = OpExtInst %void %1 DebugFunctionDefinition %30 %main + %51 = OpExtInst %void %1 DebugScope %32 + %46 = OpExtInst %void %1 DebugLine %16 %uint_10 %uint_10 %uint_3 %uint_5 + %47 = OpExtInst %void %1 DebugDeclare %34 %44 %15 + %52 = OpExtInst %void %1 DebugScope %25 %37 + %48 = OpExtInst %void %1 DebugLine %16 %uint_4 %uint_5 %uint_3 %uint_3 + %49 = OpExtInst %void %1 DebugDeclare %27 %44 %15 + %53 = OpExtInst %void %1 DebugNoScope + %50 = OpExtInst %void %1 DebugLine %16 %uint_12 %uint_12 %uint_1 %uint_1 +; CHECK: {{.*}} = OpExtInst %void %1 DebugFunctionDefinition +; CHECK: {{.*}} = OpExtInst %void %1 DebugScope +; CHECK: {{.*}} = OpExtInst %void %1 DebugLine +; CHECK: {{.*}} = OpExtInst %void %1 DebugDeclare +; CHECK: {{.*}} = OpExtInst %void %1 DebugScope +; CHECK: {{.*}} = OpExtInst %void %1 DebugLine +; CHECK: {{.*}} = OpExtInst %void %1 DebugDeclare +; CHECK: {{.*}} = OpExtInst %void %1 DebugNoScope +; CHECK: {{.*}} = OpExtInst %void %1 DebugLine + OpReturn + OpFunctionEnd + )"; + const auto result = + SinglePassRunAndMatch( + kTest, /* do_validation= */ true); + EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); +} + +} // namespace +} // namespace opt +} // namespace spvtools From 7564e142d691739cf305bf47aa4016e73f4d2d39 Mon Sep 17 00:00:00 2001 From: Shahbaz Youssefi Date: Mon, 17 Jun 2024 09:54:18 -0400 Subject: [PATCH 457/523] spirv-dis: Add --nested-indent and --reorder-blocks (#5671) With --nested-indent, the SPIR-V blocks are nested according to the structured control flow. Each OpLabel is nested that much with the contents of the block nested a little more. The blocks are separated by a blank line for better visualization. With --reorder-blocks, the SPIR-V blocks are reordered according to the structured control flow. This is particularly useful with --nested-indent. Note that with --nested-indent, the disassembly does not exactly show the binary as-is, and the instructions may be reordered. --- include/spirv-tools/libspirv.h | 5 + source/disassemble.cpp | 441 ++++- source/disassemble.h | 18 +- source/opt/build_module.h | 4 +- test/binary_to_text.literal_test.cpp | 2 + test/binary_to_text_test.cpp | 2014 +++++++++++++++++++++-- test/ext_inst.non_semantic_test.cpp | 3 +- test/test_fixture.h | 6 +- test/text_to_binary.annotation_test.cpp | 24 +- test/text_to_binary.composite_test.cpp | 3 +- test/text_to_binary.extension_test.cpp | 7 +- test/text_to_binary.memory_test.cpp | 84 +- tools/dis/dis.cpp | 67 +- 13 files changed, 2394 insertions(+), 284 deletions(-) diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index 83b1a8e9b6..162553d891 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -382,6 +382,11 @@ typedef enum spv_binary_to_text_options_t { SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES = SPV_BIT(6), // Add some comments to the generated assembly SPV_BINARY_TO_TEXT_OPTION_COMMENT = SPV_BIT(7), + // Use nested indentation for more readable SPIR-V + SPV_BINARY_TO_TEXT_OPTION_NESTED_INDENT = SPV_BIT(8), + // Reorder blocks to match the structured control flow of SPIR-V to increase + // readability. + SPV_BINARY_TO_TEXT_OPTION_REORDER_BLOCKS = SPV_BIT(9), SPV_FORCE_32_BIT_ENUM(spv_binary_to_text_options_t) } spv_binary_to_text_options_t; diff --git a/source/disassemble.cpp b/source/disassemble.cpp index 8fc4ee2710..aa20fab65e 100644 --- a/source/disassemble.cpp +++ b/source/disassemble.cpp @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -43,6 +45,70 @@ namespace spvtools { namespace { +// Indices to ControlFlowGraph's list of blocks from one block to its successors +struct BlockSuccessors { + // Merge block in OpLoopMerge and OpSelectionMerge + uint32_t merge_block_id = 0; + // The continue block in OpLoopMerge + uint32_t continue_block_id = 0; + // The true and false blocks in OpBranchConditional + uint32_t true_block_id = 0; + uint32_t false_block_id = 0; + // The body block of a loop, as specified by OpBranch after a merge + // instruction + uint32_t body_block_id = 0; + // The same-nesting-level block that follows this one, indicated by an + // OpBranch with no merge instruction. + uint32_t next_block_id = 0; + // The cases (including default) of an OpSwitch + std::vector case_block_ids; +}; + +class ParsedInstruction { + public: + ParsedInstruction(const spv_parsed_instruction_t* instruction) { + // Make a copy of the parsed instruction, including stable memory for its + // operands. + instruction_ = *instruction; + operands_ = + std::make_unique(instruction->num_operands); + memcpy(operands_.get(), instruction->operands, + instruction->num_operands * sizeof(*instruction->operands)); + instruction_.operands = operands_.get(); + } + + const spv_parsed_instruction_t* get() const { return &instruction_; } + + private: + spv_parsed_instruction_t instruction_; + std::unique_ptr operands_; +}; + +// One block in the CFG +struct SingleBlock { + // The byte offset in the SPIR-V where the block starts. Used for printing in + // a comment. + size_t byte_offset; + + // Block instructions + std::vector instructions; + + // Successors of this block + BlockSuccessors successors; + + // The nesting level for this block. + uint32_t nest_level = 0; + bool nest_level_assigned = false; + + // Whether the block was reachable + bool reachable = false; +}; + +// CFG for one function +struct ControlFlowGraph { + std::vector blocks; +}; + // A Disassembler instance converts a SPIR-V binary to its assembly // representation. class Disassembler { @@ -50,6 +116,10 @@ class Disassembler { Disassembler(const AssemblyGrammar& grammar, uint32_t options, NameMapper name_mapper) : print_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_PRINT, options)), + nested_indent_( + spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_NESTED_INDENT, options)), + reorder_blocks_( + spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_REORDER_BLOCKS, options)), text_(), out_(print_ ? out_stream() : out_stream(text_)), instruction_disassembler_(grammar, out_.get(), options, name_mapper), @@ -70,7 +140,13 @@ class Disassembler { spv_result_t SaveTextResult(spv_text* text_result) const; private: + void EmitCFG(); + const bool print_; // Should we also print to the standard output stream? + const bool nested_indent_; // Should the blocks be indented according to the + // control flow structure? + const bool + reorder_blocks_; // Should the blocks be reordered for readability? spv_endianness_t endian_; // The detected endianness of the binary. std::stringstream text_; // Captures the text, if not printing. out_stream out_; // The Output stream. Either to text_ or standard output. @@ -80,6 +156,9 @@ class Disassembler { bool inserted_decoration_space_ = false; bool inserted_debug_space_ = false; bool inserted_type_space_ = false; + + // The CFG for the current function + ControlFlowGraph current_function_cfg_; }; spv_result_t Disassembler::HandleHeader(spv_endianness_t endian, @@ -106,13 +185,336 @@ spv_result_t Disassembler::HandleInstruction( inserted_debug_space_, inserted_type_space_); - instruction_disassembler_.EmitInstruction(inst, byte_offset_); + // When nesting needs to be calculated or when the blocks are reordered, we + // have to have the full picture of the CFG first. Defer processing of the + // instructions until the entire function is visited. This is not done + // without those options (even if simpler) to improve debuggability; for + // example to be able to see whatever is parsed so far even if there is a + // parse error. + if (nested_indent_ || reorder_blocks_) { + switch (static_cast(inst.opcode)) { + case spv::Op::OpLabel: { + // Add a new block to the CFG + SingleBlock new_block; + new_block.byte_offset = byte_offset_; + new_block.instructions.emplace_back(&inst); + current_function_cfg_.blocks.push_back(std::move(new_block)); + break; + } + case spv::Op::OpFunctionEnd: + // Process the CFG and output the instructions + EmitCFG(); + // Output OpFunctionEnd itself too + [[fallthrough]]; + default: + if (!current_function_cfg_.blocks.empty()) { + // If in a function, stash the instruction for later. + current_function_cfg_.blocks.back().instructions.emplace_back(&inst); + } else { + // Otherwise emit the instruction right away. + instruction_disassembler_.EmitInstruction(inst, byte_offset_); + } + break; + } + } else { + instruction_disassembler_.EmitInstruction(inst, byte_offset_); + } byte_offset_ += inst.num_words * sizeof(uint32_t); return SPV_SUCCESS; } +// Helper to get the operand of an instruction as an id. +uint32_t GetOperand(const spv_parsed_instruction_t* instruction, + uint32_t operand) { + return instruction->words[instruction->operands[operand].offset]; +} + +std::unordered_map BuildControlFlowGraph( + ControlFlowGraph& cfg) { + std::unordered_map id_to_index; + + for (size_t index = 0; index < cfg.blocks.size(); ++index) { + SingleBlock& block = cfg.blocks[index]; + + // For future use, build the ID->index map + assert(static_cast(block.instructions[0].get()->opcode) == + spv::Op::OpLabel); + const uint32_t id = block.instructions[0].get()->result_id; + + id_to_index[id] = static_cast(index); + + // Look for a merge instruction first. The function of OpBranch depends on + // that. + if (block.instructions.size() >= 3) { + const spv_parsed_instruction_t* maybe_merge = + block.instructions[block.instructions.size() - 2].get(); + + switch (static_cast(maybe_merge->opcode)) { + case spv::Op::OpLoopMerge: + block.successors.merge_block_id = GetOperand(maybe_merge, 0); + block.successors.continue_block_id = GetOperand(maybe_merge, 1); + break; + + case spv::Op::OpSelectionMerge: + block.successors.merge_block_id = GetOperand(maybe_merge, 0); + break; + + default: + break; + } + } + + // Then look at the last instruction; it must be a branch + assert(block.instructions.size() >= 2); + + const spv_parsed_instruction_t* branch = block.instructions.back().get(); + switch (static_cast(branch->opcode)) { + case spv::Op::OpBranch: + if (block.successors.merge_block_id != 0) { + block.successors.body_block_id = GetOperand(branch, 0); + } else { + block.successors.next_block_id = GetOperand(branch, 0); + } + break; + + case spv::Op::OpBranchConditional: + block.successors.true_block_id = GetOperand(branch, 1); + block.successors.false_block_id = GetOperand(branch, 2); + break; + + case spv::Op::OpSwitch: + for (uint32_t case_index = 1; case_index < branch->num_operands; + case_index += 2) { + block.successors.case_block_ids.push_back( + GetOperand(branch, case_index)); + } + break; + + default: + break; + } + } + + return id_to_index; +} + +// Helper to deal with nesting and non-existing ids / previously-assigned +// levels. It assigns a given nesting level `level` to the block identified by +// `id` (unless that block already has a nesting level assigned). +void Nest(ControlFlowGraph& cfg, + const std::unordered_map& id_to_index, + uint32_t id, uint32_t level) { + if (id == 0) { + return; + } + + const uint32_t block_index = id_to_index.at(id); + SingleBlock& block = cfg.blocks[block_index]; + + if (!block.nest_level_assigned) { + block.nest_level = level; + block.nest_level_assigned = true; + } +} + +// For a given block, assign nesting level to its successors. +void NestSuccessors(ControlFlowGraph& cfg, const SingleBlock& block, + const std::unordered_map& id_to_index) { + assert(block.nest_level_assigned); + + // Nest loops as such: + // + // %loop = OpLabel + // OpLoopMerge %merge %cont ... + // OpBranch %body + // %body = OpLabel + // Op... + // %cont = OpLabel + // Op... + // %merge = OpLabel + // Op... + // + // Nest conditional branches as such: + // + // %header = OpLabel + // OpSelectionMerge %merge ... + // OpBranchConditional ... %true %false + // %true = OpLabel + // Op... + // %false = OpLabel + // Op... + // %merge = OpLabel + // Op... + // + // Nest switch/case as such: + // + // %header = OpLabel + // OpSelectionMerge %merge ... + // OpSwitch ... %default ... %case0 ... %case1 ... + // %default = OpLabel + // Op... + // %case0 = OpLabel + // Op... + // %case1 = OpLabel + // Op... + // ... + // %merge = OpLabel + // Op... + // + // The following can be observed: + // + // - In all cases, the merge block has the same nesting as this block + // - The continue block of loops is nested 1 level deeper + // - The body/branches/cases are nested 2 levels deeper + // + // Back branches to the header block, branches to the merge block, etc + // are correctly handled by processing the header block first (that is + // _this_ block, already processed), then following the above rules + // (in the same order) for any block that is not already processed. + Nest(cfg, id_to_index, block.successors.merge_block_id, block.nest_level); + Nest(cfg, id_to_index, block.successors.continue_block_id, + block.nest_level + 1); + Nest(cfg, id_to_index, block.successors.true_block_id, block.nest_level + 2); + Nest(cfg, id_to_index, block.successors.false_block_id, block.nest_level + 2); + Nest(cfg, id_to_index, block.successors.body_block_id, block.nest_level + 2); + Nest(cfg, id_to_index, block.successors.next_block_id, block.nest_level); + for (uint32_t case_block_id : block.successors.case_block_ids) { + Nest(cfg, id_to_index, case_block_id, block.nest_level + 2); + } +} + +struct StackEntry { + // The index of the block (in ControlFlowGraph::blocks) to process. + uint32_t block_index; + // Whether this is the pre or post visit of the block. Because a post-visit + // traversal is needed, the same block is pushed back on the stack on + // pre-visit so it can be visited again on post-visit. + bool post_visit = false; +}; + +// Helper to deal with DFS traversal and non-existing ids +void VisitSuccesor(std::stack* dfs_stack, + const std::unordered_map& id_to_index, + uint32_t id) { + if (id != 0) { + dfs_stack->push({id_to_index.at(id), false}); + } +} + +// Given the control flow graph, calculates and returns the reverse post-order +// ordering of the blocks. The blocks are then disassembled in that order for +// readability. +std::vector OrderBlocks( + ControlFlowGraph& cfg, + const std::unordered_map& id_to_index) { + std::vector post_order; + + // Nest level of a function's first block is 0. + cfg.blocks[0].nest_level = 0; + cfg.blocks[0].nest_level_assigned = true; + + // Stack of block indices as they are visited. + std::stack dfs_stack; + dfs_stack.push({0, false}); + + std::set visited; + + while (!dfs_stack.empty()) { + const uint32_t block_index = dfs_stack.top().block_index; + const bool post_visit = dfs_stack.top().post_visit; + dfs_stack.pop(); + + // If this is the second time the block is visited, that's the post-order + // visit. + if (post_visit) { + post_order.push_back(block_index); + continue; + } + + // If already visited, another path got to it first (like a case + // fallthrough), avoid reprocessing it. + if (visited.count(block_index) > 0) { + continue; + } + visited.insert(block_index); + + // Push it back in the stack for post-order visit + dfs_stack.push({block_index, true}); + + SingleBlock& block = cfg.blocks[block_index]; + + // Assign nest levels of successors right away. The successors are either + // nested under this block, or are back or forward edges to blocks outside + // this nesting level (no farther than the merge block), whose nesting + // levels are already assigned before this block is visited. + NestSuccessors(cfg, block, id_to_index); + block.reachable = true; + + // The post-order visit yields the order in which the blocks are naturally + // ordered _backwards_. So blocks to be ordered last should be visited + // first. In other words, they should be pushed to the DFS stack last. + VisitSuccesor(&dfs_stack, id_to_index, block.successors.true_block_id); + VisitSuccesor(&dfs_stack, id_to_index, block.successors.false_block_id); + VisitSuccesor(&dfs_stack, id_to_index, block.successors.body_block_id); + VisitSuccesor(&dfs_stack, id_to_index, block.successors.next_block_id); + for (uint32_t case_block_id : block.successors.case_block_ids) { + VisitSuccesor(&dfs_stack, id_to_index, case_block_id); + } + VisitSuccesor(&dfs_stack, id_to_index, block.successors.continue_block_id); + VisitSuccesor(&dfs_stack, id_to_index, block.successors.merge_block_id); + } + + std::vector order(post_order.rbegin(), post_order.rend()); + + // Finally, dump all unreachable blocks at the end + for (size_t index = 0; index < cfg.blocks.size(); ++index) { + SingleBlock& block = cfg.blocks[index]; + + if (!block.reachable) { + order.push_back(static_cast(index)); + block.nest_level = 0; + block.nest_level_assigned = true; + } + } + + return order; +} + +void Disassembler::EmitCFG() { + // Build the CFG edges. At the same time, build an ID->block index map to + // simplify building the CFG edges. + const std::unordered_map id_to_index = + BuildControlFlowGraph(current_function_cfg_); + + // Walk the CFG in reverse post-order to find the best ordering of blocks for + // presentation + std::vector block_order = + OrderBlocks(current_function_cfg_, id_to_index); + assert(block_order.size() == current_function_cfg_.blocks.size()); + + // Walk the CFG either in block order or input order based on whether the + // reorder_blocks_ option is given. + for (uint32_t index = 0; index < current_function_cfg_.blocks.size(); + ++index) { + const uint32_t block_index = reorder_blocks_ ? block_order[index] : index; + const SingleBlock& block = current_function_cfg_.blocks[block_index]; + + // Emit instructions for this block + size_t byte_offset = block.byte_offset; + assert(block.nest_level_assigned); + + for (const ParsedInstruction& inst : block.instructions) { + instruction_disassembler_.EmitInstructionInBlock(*inst.get(), byte_offset, + block.nest_level); + byte_offset += inst.get()->num_words * sizeof(uint32_t); + } + } + + current_function_cfg_.blocks.clear(); +} + spv_result_t Disassembler::SaveTextResult(spv_text* text_result) const { if (!print_) { size_t length = text_.str().size(); @@ -214,6 +616,8 @@ uint32_t GetLineLengthWithoutColor(const std::string line) { } constexpr int kStandardIndent = 15; +constexpr int kBlockNestIndent = 2; +constexpr int kBlockBodyIndentOffset = 2; constexpr uint32_t kCommentColumn = 50; } // namespace @@ -229,6 +633,8 @@ InstructionDisassembler::InstructionDisassembler(const AssemblyGrammar& grammar, indent_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_INDENT, options) ? kStandardIndent : 0), + nested_indent_( + spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_NESTED_INDENT, options)), comment_(spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_COMMENT, options)), show_byte_offset_( spvIsInBitfield(SPV_BINARY_TO_TEXT_OPTION_SHOW_BYTE_OFFSET, options)), @@ -265,12 +671,29 @@ void InstructionDisassembler::EmitHeaderSchema(uint32_t schema) { void InstructionDisassembler::EmitInstruction( const spv_parsed_instruction_t& inst, size_t inst_byte_offset) { + EmitInstructionImpl(inst, inst_byte_offset, 0, false); +} + +void InstructionDisassembler::EmitInstructionInBlock( + const spv_parsed_instruction_t& inst, size_t inst_byte_offset, + uint32_t block_indent) { + EmitInstructionImpl(inst, inst_byte_offset, block_indent, true); +} + +void InstructionDisassembler::EmitInstructionImpl( + const spv_parsed_instruction_t& inst, size_t inst_byte_offset, + uint32_t block_indent, bool is_in_block) { auto opcode = static_cast(inst.opcode); // To better align the comments (if any), write the instruction to a line // first so its length can be readily available. std::ostringstream line; + if (nested_indent_ && opcode == spv::Op::OpLabel) { + // Separate the blocks by an empty line to make them easier to separate + stream_ << std::endl; + } + if (inst.result_id) { SetBlue(); const std::string id_name = name_mapper_(inst.result_id); @@ -283,6 +706,17 @@ void InstructionDisassembler::EmitInstruction( line << std::string(indent_, ' '); } + if (nested_indent_ && is_in_block) { + // Output OpLabel at the specified nest level, and instructions inside + // blocks nested a little more. + uint32_t indent = block_indent; + bool body_indent = opcode != spv::Op::OpLabel; + + line << std::string( + indent * kBlockNestIndent + (body_indent ? kBlockBodyIndentOffset : 0), + ' '); + } + line << "Op" << spvOpcodeString(opcode); for (uint16_t i = 0; i < inst.num_operands; i++) { @@ -386,6 +820,11 @@ void InstructionDisassembler::EmitSectionComment( auto opcode = static_cast(inst.opcode); if (comment_ && opcode == spv::Op::OpFunction) { stream_ << std::endl; + if (nested_indent_) { + // Double the empty lines between Function sections since nested_indent_ + // also separates blocks by a blank. + stream_ << std::endl; + } stream_ << std::string(indent_, ' '); stream_ << "; Function " << name_mapper_(inst.result_id) << std::endl; } diff --git a/source/disassemble.h b/source/disassemble.h index 0dab3c5223..9baeaa43e0 100644 --- a/source/disassemble.h +++ b/source/disassemble.h @@ -58,6 +58,11 @@ class InstructionDisassembler { // Emits the assembly text for the given instruction. void EmitInstruction(const spv_parsed_instruction_t& inst, size_t inst_byte_offset); + // Same as EmitInstruction, but only for block instructions (including + // OpLabel) and useful for nested indentation. If nested indentation is not + // desired, EmitInstruction can still be used for block instructions. + void EmitInstructionInBlock(const spv_parsed_instruction_t& inst, + size_t inst_byte_offset, uint32_t block_indent); // Emits a comment between different sections of the module. void EmitSectionComment(const spv_parsed_instruction_t& inst, @@ -82,6 +87,10 @@ class InstructionDisassembler { void SetRed(std::ostream& stream) const; void SetGreen(std::ostream& stream) const; + void EmitInstructionImpl(const spv_parsed_instruction_t& inst, + size_t inst_byte_offset, uint32_t block_indent, + bool is_in_block); + // Emits an operand for the given instruction, where the instruction // is at offset words from the start of the binary. void EmitOperand(std::ostream& stream, const spv_parsed_instruction_t& inst, @@ -97,10 +106,11 @@ class InstructionDisassembler { const spvtools::AssemblyGrammar& grammar_; std::ostream& stream_; - const bool print_; // Should we also print to the standard output stream? - const bool color_; // Should we print in colour? - const int indent_; // How much to indent. 0 means don't indent - const int comment_; // Should we comment the source + const bool print_; // Should we also print to the standard output stream? + const bool color_; // Should we print in colour? + const int indent_; // How much to indent. 0 means don't indent + const bool nested_indent_; // Whether indentation should indicate nesting + const int comment_; // Should we comment the source const bool show_byte_offset_; // Should we print byte offset, in hex? spvtools::NameMapper name_mapper_; diff --git a/source/opt/build_module.h b/source/opt/build_module.h index 29eaf66139..0f906c88bf 100644 --- a/source/opt/build_module.h +++ b/source/opt/build_module.h @@ -24,7 +24,7 @@ namespace spvtools { -// Builds an Module returns the owning IRContext from the given SPIR-V +// Builds a Module and returns the owning IRContext from the given SPIR-V // |binary|. |size| specifies number of words in |binary|. The |binary| will be // decoded according to the given target |env|. Returns nullptr if errors occur // and sends the errors to |consumer|. When |extra_line_tracking| is true, @@ -41,7 +41,7 @@ std::unique_ptr BuildModule(spv_target_env env, const uint32_t* binary, size_t size); -// Builds an Module and returns the owning IRContext from the given +// Builds a Module and returns the owning IRContext from the given // SPIR-V assembly |text|. The |text| will be encoded according to the given // target |env|. Returns nullptr if errors occur and sends the errors to // |consumer|. diff --git a/test/binary_to_text.literal_test.cpp b/test/binary_to_text.literal_test.cpp index 5956984b13..58e1f187a1 100644 --- a/test/binary_to_text.literal_test.cpp +++ b/test/binary_to_text.literal_test.cpp @@ -33,6 +33,7 @@ TEST_P(RoundTripLiteralsTest, Sample) { for (bool endian_swap : kSwapEndians) { EXPECT_THAT( EncodeAndDecodeSuccessfully(GetParam(), SPV_BINARY_TO_TEXT_OPTION_NONE, + SPV_TEXT_TO_BINARY_OPTION_NONE, SPV_ENV_UNIVERSAL_1_0, endian_swap), Eq(GetParam())); } @@ -68,6 +69,7 @@ TEST_P(RoundTripSpecialCaseLiteralsTest, Sample) { for (bool endian_swap : kSwapEndians) { EXPECT_THAT(EncodeAndDecodeSuccessfully(std::get<0>(GetParam()), SPV_BINARY_TO_TEXT_OPTION_NONE, + SPV_TEXT_TO_BINARY_OPTION_NONE, SPV_ENV_UNIVERSAL_1_0, endian_swap), Eq(std::get<1>(GetParam()))); } diff --git a/test/binary_to_text_test.cpp b/test/binary_to_text_test.cpp index d17e5011fc..dd7569382f 100644 --- a/test/binary_to_text_test.cpp +++ b/test/binary_to_text_test.cpp @@ -247,9 +247,9 @@ using RoundTripInstructionsTest = spvtest::TextToBinaryTestBase< ::testing::TestWithParam>>; TEST_P(RoundTripInstructionsTest, Sample) { - EXPECT_THAT(EncodeAndDecodeSuccessfully(std::get<1>(GetParam()), - SPV_BINARY_TO_TEXT_OPTION_NONE, - std::get<0>(GetParam())), + EXPECT_THAT(EncodeAndDecodeSuccessfully( + std::get<1>(GetParam()), SPV_BINARY_TO_TEXT_OPTION_NONE, + SPV_TEXT_TO_BINARY_OPTION_NONE, std::get<0>(GetParam())), Eq(std::get<1>(GetParam()))); } @@ -464,6 +464,1462 @@ OpStore %2 %3 Aligned|Volatile 4 ; bogus, but not indented expected); } +TEST_F(IndentTest, NestedIf) { + const std::string input = R"( +OpCapability Shader +OpMemoryModel Logical Simple +OpEntryPoint Fragment %100 "main" +OpExecutionMode %100 OriginUpperLeft +OpName %var "var" +%void = OpTypeVoid +%3 = OpTypeFunction %void +%bool = OpTypeBool +%5 = OpConstantNull %bool +%true = OpConstantTrue %bool +%false = OpConstantFalse %bool +%uint = OpTypeInt 32 0 +%int = OpTypeInt 32 1 +%uint_42 = OpConstant %uint 42 +%int_42 = OpConstant %int 42 +%13 = OpTypeFunction %uint +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%uint_4 = OpConstant %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_10 = OpConstant %uint 10 +%uint_20 = OpConstant %uint 20 +%uint_30 = OpConstant %uint 30 +%uint_40 = OpConstant %uint 40 +%uint_50 = OpConstant %uint 50 +%uint_90 = OpConstant %uint 90 +%uint_99 = OpConstant %uint 99 +%_ptr_Private_uint = OpTypePointer Private %uint +%var = OpVariable %_ptr_Private_uint Private +%uint_999 = OpConstant %uint 999 +%100 = OpFunction %void None %3 +%10 = OpLabel +OpStore %var %uint_0 +OpSelectionMerge %99 None +OpBranchConditional %5 %30 %40 +%30 = OpLabel +OpStore %var %uint_1 +OpBranch %99 +%40 = OpLabel +OpStore %var %uint_2 +OpBranch %99 +%99 = OpLabel +OpStore %var %uint_999 +OpReturn +OpFunctionEnd +)"; + const std::string expected = + R"( OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Fragment %100 "main" + OpExecutionMode %100 OriginUpperLeft + OpName %1 "var" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpTypeBool + %5 = OpConstantNull %4 + %6 = OpConstantTrue %4 + %7 = OpConstantFalse %4 + %8 = OpTypeInt 32 0 + %9 = OpTypeInt 32 1 + %11 = OpConstant %8 42 + %12 = OpConstant %9 42 + %13 = OpTypeFunction %8 + %14 = OpConstant %8 0 + %15 = OpConstant %8 1 + %16 = OpConstant %8 2 + %17 = OpConstant %8 3 + %18 = OpConstant %8 4 + %19 = OpConstant %8 5 + %20 = OpConstant %8 6 + %21 = OpConstant %8 7 + %22 = OpConstant %8 8 + %23 = OpConstant %8 10 + %24 = OpConstant %8 20 + %25 = OpConstant %8 30 + %26 = OpConstant %8 40 + %27 = OpConstant %8 50 + %28 = OpConstant %8 90 + %29 = OpConstant %8 99 + %31 = OpTypePointer Private %8 + %1 = OpVariable %31 Private + %32 = OpConstant %8 999 + %100 = OpFunction %2 None %3 + + %10 = OpLabel + OpStore %1 %14 + OpSelectionMerge %99 None + OpBranchConditional %5 %30 %40 + + %30 = OpLabel + OpStore %1 %15 + OpBranch %99 + + %40 = OpLabel + OpStore %1 %16 + OpBranch %99 + + %99 = OpLabel + OpStore %1 %32 + OpReturn + OpFunctionEnd +)"; + EXPECT_THAT(EncodeAndDecodeSuccessfully( + input, + SPV_BINARY_TO_TEXT_OPTION_INDENT | + SPV_BINARY_TO_TEXT_OPTION_NESTED_INDENT, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS), + expected); +} + +TEST_F(IndentTest, NestedWhile) { + const std::string input = R"( +OpCapability Shader +OpMemoryModel Logical Simple +OpEntryPoint Fragment %100 "main" +OpExecutionMode %100 OriginUpperLeft +OpName %var "var" +%void = OpTypeVoid +%3 = OpTypeFunction %void +%bool = OpTypeBool +%5 = OpConstantNull %bool +%true = OpConstantTrue %bool +%false = OpConstantFalse %bool +%uint = OpTypeInt 32 0 +%int = OpTypeInt 32 1 +%uint_42 = OpConstant %uint 42 +%int_42 = OpConstant %int 42 +%13 = OpTypeFunction %uint +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%uint_4 = OpConstant %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_10 = OpConstant %uint 10 +%uint_20 = OpConstant %uint 20 +%uint_30 = OpConstant %uint 30 +%uint_40 = OpConstant %uint 40 +%uint_50 = OpConstant %uint 50 +%uint_90 = OpConstant %uint 90 +%uint_99 = OpConstant %uint 99 +%_ptr_Private_uint = OpTypePointer Private %uint +%var = OpVariable %_ptr_Private_uint Private +%uint_999 = OpConstant %uint 999 +%100 = OpFunction %void None %3 +%10 = OpLabel +OpStore %var %uint_0 +OpBranch %20 +%20 = OpLabel +OpStore %var %uint_1 +OpLoopMerge %99 %20 None +OpBranch %80 +%80 = OpLabel +OpStore %var %uint_2 +OpBranchConditional %5 %99 %20 +%99 = OpLabel +OpStore %var %uint_3 +OpReturn +OpFunctionEnd +)"; + const std::string expected = + R"( OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Fragment %100 "main" + OpExecutionMode %100 OriginUpperLeft + OpName %1 "var" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpTypeBool + %5 = OpConstantNull %4 + %6 = OpConstantTrue %4 + %7 = OpConstantFalse %4 + %8 = OpTypeInt 32 0 + %9 = OpTypeInt 32 1 + %11 = OpConstant %8 42 + %12 = OpConstant %9 42 + %13 = OpTypeFunction %8 + %14 = OpConstant %8 0 + %15 = OpConstant %8 1 + %16 = OpConstant %8 2 + %17 = OpConstant %8 3 + %18 = OpConstant %8 4 + %19 = OpConstant %8 5 + %21 = OpConstant %8 6 + %22 = OpConstant %8 7 + %23 = OpConstant %8 8 + %24 = OpConstant %8 10 + %25 = OpConstant %8 20 + %26 = OpConstant %8 30 + %27 = OpConstant %8 40 + %28 = OpConstant %8 50 + %29 = OpConstant %8 90 + %30 = OpConstant %8 99 + %31 = OpTypePointer Private %8 + %1 = OpVariable %31 Private + %32 = OpConstant %8 999 + %100 = OpFunction %2 None %3 + + %10 = OpLabel + OpStore %1 %14 + OpBranch %20 + + %20 = OpLabel + OpStore %1 %15 + OpLoopMerge %99 %20 None + OpBranch %80 + + %80 = OpLabel + OpStore %1 %16 + OpBranchConditional %5 %99 %20 + + %99 = OpLabel + OpStore %1 %17 + OpReturn + OpFunctionEnd +)"; + EXPECT_THAT(EncodeAndDecodeSuccessfully( + input, + SPV_BINARY_TO_TEXT_OPTION_INDENT | + SPV_BINARY_TO_TEXT_OPTION_NESTED_INDENT, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS), + expected); +} + +TEST_F(IndentTest, NestedLoopInLoop) { + const std::string input = R"( +OpCapability Shader +OpMemoryModel Logical Simple +OpEntryPoint Fragment %100 "main" +OpExecutionMode %100 OriginUpperLeft +OpName %var "var" +%void = OpTypeVoid +%3 = OpTypeFunction %void +%bool = OpTypeBool +%5 = OpConstantNull %bool +%true = OpConstantTrue %bool +%false = OpConstantFalse %bool +%uint = OpTypeInt 32 0 +%int = OpTypeInt 32 1 +%uint_42 = OpConstant %uint 42 +%int_42 = OpConstant %int 42 +%13 = OpTypeFunction %uint +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%uint_4 = OpConstant %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_10 = OpConstant %uint 10 +%uint_20 = OpConstant %uint 20 +%uint_30 = OpConstant %uint 30 +%uint_40 = OpConstant %uint 40 +%uint_50 = OpConstant %uint 50 +%uint_90 = OpConstant %uint 90 +%uint_99 = OpConstant %uint 99 +%_ptr_Private_uint = OpTypePointer Private %uint +%var = OpVariable %_ptr_Private_uint Private +%uint_999 = OpConstant %uint 999 +%100 = OpFunction %void None %3 +%10 = OpLabel +OpBranch %20 +%20 = OpLabel +OpLoopMerge %99 %50 None +OpBranchConditional %5 %30 %99 +%30 = OpLabel +OpLoopMerge %49 %40 None +OpBranchConditional %true %35 %49 +%35 = OpLabel +OpBranch %37 +%37 = OpLabel +OpBranch %40 +%40 = OpLabel +OpBranch %30 +%49 = OpLabel +OpBranch %50 +%50 = OpLabel +OpBranch %20 +%99 = OpLabel +OpReturn +OpFunctionEnd +)"; + const std::string expected = + R"( OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Fragment %100 "main" + OpExecutionMode %100 OriginUpperLeft + OpName %1 "var" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpTypeBool + %5 = OpConstantNull %4 + %6 = OpConstantTrue %4 + %7 = OpConstantFalse %4 + %8 = OpTypeInt 32 0 + %9 = OpTypeInt 32 1 + %11 = OpConstant %8 42 + %12 = OpConstant %9 42 + %13 = OpTypeFunction %8 + %14 = OpConstant %8 0 + %15 = OpConstant %8 1 + %16 = OpConstant %8 2 + %17 = OpConstant %8 3 + %18 = OpConstant %8 4 + %19 = OpConstant %8 5 + %21 = OpConstant %8 6 + %22 = OpConstant %8 7 + %23 = OpConstant %8 8 + %24 = OpConstant %8 10 + %25 = OpConstant %8 20 + %26 = OpConstant %8 30 + %27 = OpConstant %8 40 + %28 = OpConstant %8 50 + %29 = OpConstant %8 90 + %31 = OpConstant %8 99 + %32 = OpTypePointer Private %8 + %1 = OpVariable %32 Private + %33 = OpConstant %8 999 + %100 = OpFunction %2 None %3 + + %10 = OpLabel + OpBranch %20 + + %20 = OpLabel + OpLoopMerge %99 %50 None + OpBranchConditional %5 %30 %99 + + %30 = OpLabel + OpLoopMerge %49 %40 None + OpBranchConditional %6 %35 %49 + + %35 = OpLabel + OpBranch %37 + + %37 = OpLabel + OpBranch %40 + + %40 = OpLabel + OpBranch %30 + + %49 = OpLabel + OpBranch %50 + + %50 = OpLabel + OpBranch %20 + + %99 = OpLabel + OpReturn + OpFunctionEnd +)"; + EXPECT_THAT(EncodeAndDecodeSuccessfully( + input, + SPV_BINARY_TO_TEXT_OPTION_INDENT | + SPV_BINARY_TO_TEXT_OPTION_NESTED_INDENT, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS), + expected); +} + +TEST_F(IndentTest, NestedSwitch) { + const std::string input = R"( +OpCapability Shader +OpMemoryModel Logical Simple +OpEntryPoint Fragment %100 "main" +OpExecutionMode %100 OriginUpperLeft +OpName %var "var" +%void = OpTypeVoid +%3 = OpTypeFunction %void +%bool = OpTypeBool +%5 = OpConstantNull %bool +%true = OpConstantTrue %bool +%false = OpConstantFalse %bool +%uint = OpTypeInt 32 0 +%int = OpTypeInt 32 1 +%uint_42 = OpConstant %uint 42 +%int_42 = OpConstant %int 42 +%13 = OpTypeFunction %uint +%uint_0 = OpConstant %uint 0 +%uint_1 = OpConstant %uint 1 +%uint_2 = OpConstant %uint 2 +%uint_3 = OpConstant %uint 3 +%uint_4 = OpConstant %uint 4 +%uint_5 = OpConstant %uint 5 +%uint_6 = OpConstant %uint 6 +%uint_7 = OpConstant %uint 7 +%uint_8 = OpConstant %uint 8 +%uint_10 = OpConstant %uint 10 +%uint_20 = OpConstant %uint 20 +%uint_30 = OpConstant %uint 30 +%uint_40 = OpConstant %uint 40 +%uint_50 = OpConstant %uint 50 +%uint_90 = OpConstant %uint 90 +%uint_99 = OpConstant %uint 99 +%_ptr_Private_uint = OpTypePointer Private %uint +%var = OpVariable %_ptr_Private_uint Private +%uint_999 = OpConstant %uint 999 +%100 = OpFunction %void None %3 +%10 = OpLabel +OpSelectionMerge %99 None +OpSwitch %uint_42 %80 20 %20 30 %30 +%20 = OpLabel +OpBranch %80 +%80 = OpLabel +OpBranch %30 +%30 = OpLabel +OpBranch %99 +%99 = OpLabel +OpReturn +OpFunctionEnd +)"; + const std::string expected = + R"( OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Fragment %100 "main" + OpExecutionMode %100 OriginUpperLeft + OpName %1 "var" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpTypeBool + %5 = OpConstantNull %4 + %6 = OpConstantTrue %4 + %7 = OpConstantFalse %4 + %8 = OpTypeInt 32 0 + %9 = OpTypeInt 32 1 + %11 = OpConstant %8 42 + %12 = OpConstant %9 42 + %13 = OpTypeFunction %8 + %14 = OpConstant %8 0 + %15 = OpConstant %8 1 + %16 = OpConstant %8 2 + %17 = OpConstant %8 3 + %18 = OpConstant %8 4 + %19 = OpConstant %8 5 + %21 = OpConstant %8 6 + %22 = OpConstant %8 7 + %23 = OpConstant %8 8 + %24 = OpConstant %8 10 + %25 = OpConstant %8 20 + %26 = OpConstant %8 30 + %27 = OpConstant %8 40 + %28 = OpConstant %8 50 + %29 = OpConstant %8 90 + %31 = OpConstant %8 99 + %32 = OpTypePointer Private %8 + %1 = OpVariable %32 Private + %33 = OpConstant %8 999 + %100 = OpFunction %2 None %3 + + %10 = OpLabel + OpSelectionMerge %99 None + OpSwitch %11 %80 20 %20 30 %30 + + %20 = OpLabel + OpBranch %80 + + %80 = OpLabel + OpBranch %30 + + %30 = OpLabel + OpBranch %99 + + %99 = OpLabel + OpReturn + OpFunctionEnd +)"; + EXPECT_THAT(EncodeAndDecodeSuccessfully( + input, + SPV_BINARY_TO_TEXT_OPTION_INDENT | + SPV_BINARY_TO_TEXT_OPTION_NESTED_INDENT, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS), + expected); +} + +TEST_F(IndentTest, ReorderedIf) { + const std::string input = R"( + OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Fragment %100 "main" + OpExecutionMode %100 OriginUpperLeft + OpName %1 "var" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpTypeBool + %5 = OpConstantNull %4 + %6 = OpConstantTrue %4 + %7 = OpConstantFalse %4 + %8 = OpTypeInt 32 0 + %9 = OpTypeInt 32 1 + %11 = OpConstant %8 42 + %12 = OpConstant %9 42 + %13 = OpTypeFunction %8 + %14 = OpConstant %8 0 + %15 = OpConstant %8 1 + %16 = OpConstant %8 2 + %17 = OpConstant %8 3 + %18 = OpConstant %8 4 + %19 = OpConstant %8 5 + %21 = OpConstant %8 6 + %22 = OpConstant %8 7 + %23 = OpConstant %8 8 + %24 = OpConstant %8 10 + %25 = OpConstant %8 20 + %26 = OpConstant %8 30 + %27 = OpConstant %8 40 + %28 = OpConstant %8 50 + %29 = OpConstant %8 90 + %31 = OpConstant %8 99 + %32 = OpTypePointer Private %8 + %1 = OpVariable %32 Private + %33 = OpConstant %8 999 + %100 = OpFunction %2 None %3 + %10 = OpLabel + OpSelectionMerge %99 None + OpBranchConditional %5 %20 %50 + %99 = OpLabel + OpReturn + %20 = OpLabel + OpSelectionMerge %49 None + OpBranchConditional %5 %30 %40 + %49 = OpLabel + OpBranch %99 + %40 = OpLabel + OpBranch %49 + %30 = OpLabel + OpBranch %49 + %50 = OpLabel + OpSelectionMerge %79 None + OpBranchConditional %5 %60 %70 + %79 = OpLabel + OpBranch %99 + %60 = OpLabel + OpBranch %79 + %70 = OpLabel + OpBranch %79 + OpFunctionEnd +)"; + const std::string expected = + R"( OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Fragment %100 "main" + OpExecutionMode %100 OriginUpperLeft + OpName %1 "var" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpTypeBool + %5 = OpConstantNull %4 + %6 = OpConstantTrue %4 + %7 = OpConstantFalse %4 + %8 = OpTypeInt 32 0 + %9 = OpTypeInt 32 1 + %11 = OpConstant %8 42 + %12 = OpConstant %9 42 + %13 = OpTypeFunction %8 + %14 = OpConstant %8 0 + %15 = OpConstant %8 1 + %16 = OpConstant %8 2 + %17 = OpConstant %8 3 + %18 = OpConstant %8 4 + %19 = OpConstant %8 5 + %21 = OpConstant %8 6 + %22 = OpConstant %8 7 + %23 = OpConstant %8 8 + %24 = OpConstant %8 10 + %25 = OpConstant %8 20 + %26 = OpConstant %8 30 + %27 = OpConstant %8 40 + %28 = OpConstant %8 50 + %29 = OpConstant %8 90 + %31 = OpConstant %8 99 + %32 = OpTypePointer Private %8 + %1 = OpVariable %32 Private + %33 = OpConstant %8 999 + %100 = OpFunction %2 None %3 + %10 = OpLabel + OpSelectionMerge %99 None + OpBranchConditional %5 %20 %50 + %20 = OpLabel + OpSelectionMerge %49 None + OpBranchConditional %5 %30 %40 + %30 = OpLabel + OpBranch %49 + %40 = OpLabel + OpBranch %49 + %49 = OpLabel + OpBranch %99 + %50 = OpLabel + OpSelectionMerge %79 None + OpBranchConditional %5 %60 %70 + %60 = OpLabel + OpBranch %79 + %70 = OpLabel + OpBranch %79 + %79 = OpLabel + OpBranch %99 + %99 = OpLabel + OpReturn + OpFunctionEnd +)"; + EXPECT_THAT(EncodeAndDecodeSuccessfully( + input, + SPV_BINARY_TO_TEXT_OPTION_INDENT | + SPV_BINARY_TO_TEXT_OPTION_REORDER_BLOCKS, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS), + expected); +} + +TEST_F(IndentTest, ReorderedFallThroughInSwitch) { + const std::string input = R"( + OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Fragment %100 "main" + OpExecutionMode %100 OriginUpperLeft + OpName %1 "var" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpTypeBool + %5 = OpConstantNull %4 + %6 = OpConstantTrue %4 + %7 = OpConstantFalse %4 + %8 = OpTypeInt 32 0 + %9 = OpTypeInt 32 1 + %11 = OpConstant %8 42 + %12 = OpConstant %9 42 + %13 = OpTypeFunction %8 + %14 = OpConstant %8 0 + %15 = OpConstant %8 1 + %16 = OpConstant %8 2 + %17 = OpConstant %8 3 + %18 = OpConstant %8 4 + %19 = OpConstant %8 5 + %21 = OpConstant %8 6 + %22 = OpConstant %8 7 + %23 = OpConstant %8 8 + %24 = OpConstant %8 10 + %25 = OpConstant %8 20 + %26 = OpConstant %8 30 + %27 = OpConstant %8 40 + %28 = OpConstant %8 50 + %29 = OpConstant %8 90 + %31 = OpConstant %8 99 + %32 = OpTypePointer Private %8 + %1 = OpVariable %32 Private + %33 = OpConstant %8 999 + %100 = OpFunction %2 None %3 + %10 = OpLabel + OpSelectionMerge %99 None + OpSwitch %11 %50 20 %20 50 %50 + %99 = OpLabel + OpReturn + %20 = OpLabel + OpSelectionMerge %49 None + OpBranchConditional %5 %30 %40 + %49 = OpLabel + OpBranchConditional %5 %99 %50 + %30 = OpLabel + OpBranch %49 + %40 = OpLabel + OpBranch %49 + %50 = OpLabel + OpSelectionMerge %79 None + OpBranchConditional %5 %60 %70 + %79 = OpLabel + OpBranch %99 + %60 = OpLabel + OpBranch %79 + %70 = OpLabel + OpBranch %79 + OpFunctionEnd +)"; + const std::string expected = + R"( OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint Fragment %100 "main" + OpExecutionMode %100 OriginUpperLeft + OpName %1 "var" + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %4 = OpTypeBool + %5 = OpConstantNull %4 + %6 = OpConstantTrue %4 + %7 = OpConstantFalse %4 + %8 = OpTypeInt 32 0 + %9 = OpTypeInt 32 1 + %11 = OpConstant %8 42 + %12 = OpConstant %9 42 + %13 = OpTypeFunction %8 + %14 = OpConstant %8 0 + %15 = OpConstant %8 1 + %16 = OpConstant %8 2 + %17 = OpConstant %8 3 + %18 = OpConstant %8 4 + %19 = OpConstant %8 5 + %21 = OpConstant %8 6 + %22 = OpConstant %8 7 + %23 = OpConstant %8 8 + %24 = OpConstant %8 10 + %25 = OpConstant %8 20 + %26 = OpConstant %8 30 + %27 = OpConstant %8 40 + %28 = OpConstant %8 50 + %29 = OpConstant %8 90 + %31 = OpConstant %8 99 + %32 = OpTypePointer Private %8 + %1 = OpVariable %32 Private + %33 = OpConstant %8 999 + %100 = OpFunction %2 None %3 + %10 = OpLabel + OpSelectionMerge %99 None + OpSwitch %11 %50 20 %20 50 %50 + %20 = OpLabel + OpSelectionMerge %49 None + OpBranchConditional %5 %30 %40 + %30 = OpLabel + OpBranch %49 + %40 = OpLabel + OpBranch %49 + %49 = OpLabel + OpBranchConditional %5 %99 %50 + %50 = OpLabel + OpSelectionMerge %79 None + OpBranchConditional %5 %60 %70 + %60 = OpLabel + OpBranch %79 + %70 = OpLabel + OpBranch %79 + %79 = OpLabel + OpBranch %99 + %99 = OpLabel + OpReturn + OpFunctionEnd +)"; + EXPECT_THAT(EncodeAndDecodeSuccessfully( + input, + SPV_BINARY_TO_TEXT_OPTION_INDENT | + SPV_BINARY_TO_TEXT_OPTION_REORDER_BLOCKS, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS), + expected); +} + +TEST_F(IndentTest, ReorderedNested) { + const std::string input = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %4 "main" %204 +OpExecutionMode %4 OriginUpperLeft +OpSource GLSL 450 +OpName %4 "main" +OpName %16 "ff(vf2;f1;" +OpName %14 "g" +OpName %15 "f" +OpName %19 "vg" +OpName %20 "Block140" +OpMemberName %20 0 "a" +OpMemberName %20 1 "b" +OpName %22 "b140" +OpName %35 "sv" +OpName %39 "s" +OpName %46 "f" +OpName %51 "g" +OpName %57 "x" +OpName %69 "param" +OpName %75 "i" +OpName %80 "vc" +OpName %88 "j" +OpName %95 "size" +OpName %174 "v" +OpName %187 "i" +OpName %204 "o_color" +OpMemberDecorate %20 0 Offset 0 +OpMemberDecorate %20 1 Offset 16 +OpDecorate %20 Block +OpDecorate %22 DescriptorSet 1 +OpDecorate %22 Binding 0 +OpDecorate %39 DescriptorSet 0 +OpDecorate %39 Binding 1 +OpDecorate %95 SpecId 20 +OpDecorate %204 Location 2 +%2 = OpTypeVoid +%3 = OpTypeFunction %2 +%6 = OpTypeFloat 32 +%7 = OpTypeVector %6 2 +%8 = OpTypePointer Function %7 +%9 = OpTypeVector %6 4 +%10 = OpTypeInt 32 0 +%11 = OpConstant %10 2 +%12 = OpTypeArray %9 %11 +%13 = OpTypeFunction %12 %8 %6 +%18 = OpTypePointer Private %9 +%19 = OpVariable %18 Private +%20 = OpTypeStruct %6 %9 +%21 = OpTypePointer Uniform %20 +%22 = OpVariable %21 Uniform +%23 = OpTypeInt 32 1 +%24 = OpConstant %23 1 +%25 = OpTypePointer Uniform %9 +%28 = OpConstant %6 0 +%29 = OpConstantComposite %9 %28 %28 %28 %28 +%34 = OpTypePointer Function %9 +%36 = OpTypeImage %6 2D 0 0 0 1 Unknown +%37 = OpTypeSampledImage %36 +%38 = OpTypePointer UniformConstant %37 +%39 = OpVariable %38 UniformConstant +%41 = OpConstantComposite %7 %28 %28 +%45 = OpTypePointer Function %6 +%47 = OpConstant %23 0 +%48 = OpTypePointer Uniform %6 +%53 = OpConstant %6 1 +%55 = OpTypeBool +%56 = OpTypePointer Function %55 +%58 = OpConstant %10 0 +%59 = OpTypePointer Private %6 +%74 = OpTypePointer Function %23 +%87 = OpTypePointer Function %10 +%95 = OpSpecConstant %10 2 +%100 = OpConstant %10 1 +%109 = OpConstantComposite %9 %53 %53 %53 %53 +%127 = OpConstant %23 10 +%139 = OpConstant %6 2 +%143 = OpConstant %6 3 +%158 = OpConstant %6 4 +%177 = OpConstant %6 0.5 +%195 = OpConstant %23 100 +%202 = OpTypeVector %10 4 +%203 = OpTypePointer Output %202 +%204 = OpVariable %203 Output +%4 = OpFunction %2 None %3 +%5 = OpLabel +%35 = OpVariable %34 Function +%46 = OpVariable %45 Function +%51 = OpVariable %45 Function +%57 = OpVariable %56 Function +%69 = OpVariable %8 Function +%75 = OpVariable %74 Function +%80 = OpVariable %34 Function +%88 = OpVariable %87 Function +%174 = OpVariable %45 Function +%187 = OpVariable %74 Function +%26 = OpAccessChain %25 %22 %24 +%27 = OpLoad %9 %26 +OpStore %19 %27 +%40 = OpLoad %37 %39 +%42 = OpImageSampleImplicitLod %9 %40 %41 +%43 = OpLoad %9 %19 +%44 = OpFAdd %9 %42 %43 +OpStore %35 %44 +%49 = OpAccessChain %48 %22 %47 +%50 = OpLoad %6 %49 +OpStore %46 %50 +%52 = OpLoad %6 %46 +%54 = OpFAdd %6 %52 %53 +OpStore %51 %54 +%60 = OpAccessChain %59 %19 %58 +%61 = OpLoad %6 %60 +%62 = OpFOrdGreaterThan %55 %61 %28 +OpSelectionMerge %64 None +OpBranchConditional %62 %63 %64 +%64 = OpLabel +%73 = OpPhi %55 %62 %5 %72 %63 +OpStore %57 %73 +OpStore %75 %47 +OpBranch %76 +%197 = OpLabel +OpBranch %190 +%63 = OpLabel +%65 = OpLoad %6 %46 +%66 = OpLoad %6 %51 +%67 = OpCompositeConstruct %7 %65 %66 +%68 = OpLoad %6 %51 +OpStore %69 %67 +%70 = OpFunctionCall %12 %16 %69 %68 +%71 = OpCompositeExtract %6 %70 0 0 +%72 = OpFOrdGreaterThan %55 %71 %28 +OpBranch %64 +%77 = OpLabel +%81 = OpLoad %9 %19 +OpStore %80 %81 +%82 = OpAccessChain %45 %80 %58 +%83 = OpLoad %6 %82 +%84 = OpFOrdGreaterThan %55 %83 %28 +OpSelectionMerge %86 None +OpBranchConditional %84 %85 %113 +%85 = OpLabel +OpStore %88 %58 +OpBranch %89 +%89 = OpLabel +OpLoopMerge %91 %92 None +OpBranch %93 +%93 = OpLabel +%94 = OpLoad %10 %88 +%96 = OpULessThan %55 %94 %95 +OpBranchConditional %96 %90 %91 +%105 = OpLabel +OpBranch %92 +%198 = OpLabel +OpBranch %191 +%163 = OpLabel +OpBranch %136 +%104 = OpLabel +OpBranch %91 +%76 = OpLabel +OpLoopMerge %78 %79 None +OpBranch %77 +%92 = OpLabel +%107 = OpLoad %10 %88 +%108 = OpIAdd %10 %107 %24 +OpStore %88 %108 +OpBranch %89 +%91 = OpLabel +%110 = OpLoad %9 %80 +%111 = OpFAdd %9 %110 %109 +OpStore %80 %111 +OpBranch %79 +%113 = OpLabel +%114 = OpLoad %9 %80 +%115 = OpFSub %9 %114 %109 +OpStore %80 %115 +OpBranch %86 +%132 = OpLabel +%137 = OpLoad %6 %51 +%138 = OpFAdd %6 %137 %53 +OpStore %51 %138 +OpBranch %133 +%86 = OpLabel +%116 = OpAccessChain %45 %80 %100 +%117 = OpLoad %6 %116 +%118 = OpFOrdGreaterThan %55 %117 %28 +OpSelectionMerge %120 None +OpBranchConditional %118 %119 %120 +%119 = OpLabel +OpBranch %78 +%120 = OpLabel +%122 = OpAccessChain %45 %80 %11 +%123 = OpLoad %6 %122 +%124 = OpFAdd %6 %123 %53 +%125 = OpAccessChain %45 %80 %11 +OpStore %125 %124 +OpBranch %79 +%79 = OpLabel +%126 = OpLoad %23 %75 +%128 = OpSLessThan %55 %126 %127 +OpBranchConditional %128 %76 %78 +%78 = OpLabel +%129 = OpAccessChain %48 %22 %47 +%130 = OpLoad %6 %129 +%131 = OpConvertFToS %23 %130 +OpSelectionMerge %136 None +OpSwitch %131 %135 0 %132 1 %132 2 %132 3 %133 4 %134 +%90 = OpLabel +%97 = OpLoad %9 %19 +%98 = OpLoad %9 %80 +%99 = OpFAdd %9 %98 %97 +OpStore %80 %99 +%101 = OpAccessChain %45 %80 %100 +%102 = OpLoad %6 %101 +%103 = OpFOrdLessThan %55 %102 %28 +OpSelectionMerge %105 None +OpBranchConditional %103 %104 %105 +%161 = OpLabel +OpLoopMerge %163 %164 None +OpBranch %165 +%165 = OpLabel +%166 = OpLoad %6 %51 +%167 = OpFOrdLessThan %55 %166 %139 +OpBranchConditional %167 %162 %163 +%164 = OpLabel +OpBranch %161 +%162 = OpLabel +%168 = OpLoad %6 %46 +%169 = OpFOrdLessThan %55 %168 %53 +OpSelectionMerge %171 None +OpBranchConditional %169 %170 %171 +%135 = OpLabel +%159 = OpLoad %6 %51 +%160 = OpFAdd %6 %159 %158 +OpStore %51 %160 +OpBranch %161 +%133 = OpLabel +%140 = OpLoad %6 %51 +%141 = OpFAdd %6 %140 %139 +OpStore %51 %141 +OpBranch %136 +%134 = OpLabel +%144 = OpLoad %6 %51 +%145 = OpFAdd %6 %144 %143 +OpStore %51 %145 +OpBranch %146 +%146 = OpLabel +OpLoopMerge %148 %149 None +OpBranch %150 +%150 = OpLabel +%151 = OpLoad %6 %51 +%152 = OpFOrdLessThan %55 %151 %139 +OpBranchConditional %152 %147 %148 +%147 = OpLabel +%153 = OpLoad %6 %46 +%154 = OpFOrdLessThan %55 %153 %53 +OpSelectionMerge %156 None +OpBranchConditional %154 %155 %156 +%155 = OpLabel +OpBranch %148 +%156 = OpLabel +OpBranch %149 +%149 = OpLabel +OpBranch %146 +%148 = OpLabel +OpBranch %135 +%136 = OpLabel +OpStore %174 %53 +%175 = OpAccessChain %45 %35 %58 +%176 = OpLoad %6 %175 +%178 = OpFOrdLessThanEqual %55 %176 %177 +OpSelectionMerge %180 None +OpBranchConditional %178 %179 %181 +%179 = OpLabel +OpStore %174 %28 +OpBranch %180 +%185 = OpLabel +OpStore %174 %139 +OpBranch %186 +%181 = OpLabel +%182 = OpAccessChain %45 %35 %58 +%183 = OpLoad %6 %182 +%184 = OpFOrdGreaterThanEqual %55 %183 %177 +OpSelectionMerge %186 None +OpBranchConditional %184 %185 %186 +%170 = OpLabel +OpBranch %163 +%171 = OpLabel +OpBranch %164 +%186 = OpLabel +OpBranch %180 +%188 = OpLabel +OpLoopMerge %190 %191 None +OpBranch %189 +%189 = OpLabel +%192 = OpLoad %9 %19 +%193 = OpFAdd %9 %192 %109 +OpStore %19 %193 +%194 = OpLoad %23 %187 +%196 = OpSGreaterThan %55 %194 %195 +OpSelectionMerge %198 None +OpBranchConditional %196 %197 %198 +%180 = OpLabel +OpStore %187 %47 +OpBranch %188 +%191 = OpLabel +%200 = OpLoad %23 %187 +%201 = OpIAdd %23 %200 %24 +OpStore %187 %201 +OpBranch %188 +%190 = OpLabel +OpReturn +OpFunctionEnd +%16 = OpFunction %12 None %13 +%14 = OpFunctionParameter %8 +%15 = OpFunctionParameter %6 +%17 = OpLabel +%30 = OpCompositeConstruct %9 %15 %15 %15 %15 +%31 = OpCompositeConstruct %12 %29 %30 +OpReturnValue %31 +OpFunctionEnd +)"; + const std::string expected = + R"( OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %204 + OpExecutionMode %4 OriginUpperLeft + OpSource GLSL 450 + OpName %4 "main" + OpName %16 "ff(vf2;f1;" + OpName %14 "g" + OpName %15 "f" + OpName %19 "vg" + OpName %20 "Block140" + OpMemberName %20 0 "a" + OpMemberName %20 1 "b" + OpName %22 "b140" + OpName %35 "sv" + OpName %39 "s" + OpName %46 "f" + OpName %51 "g" + OpName %57 "x" + OpName %69 "param" + OpName %75 "i" + OpName %80 "vc" + OpName %88 "j" + OpName %95 "size" + OpName %174 "v" + OpName %187 "i" + OpName %204 "o_color" + OpMemberDecorate %20 0 Offset 0 + OpMemberDecorate %20 1 Offset 16 + OpDecorate %20 Block + OpDecorate %22 DescriptorSet 1 + OpDecorate %22 Binding 0 + OpDecorate %39 DescriptorSet 0 + OpDecorate %39 Binding 1 + OpDecorate %95 SpecId 20 + OpDecorate %204 Location 2 + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypeVector %6 2 + %8 = OpTypePointer Function %7 + %9 = OpTypeVector %6 4 + %10 = OpTypeInt 32 0 + %11 = OpConstant %10 2 + %12 = OpTypeArray %9 %11 + %13 = OpTypeFunction %12 %8 %6 + %18 = OpTypePointer Private %9 + %19 = OpVariable %18 Private + %20 = OpTypeStruct %6 %9 + %21 = OpTypePointer Uniform %20 + %22 = OpVariable %21 Uniform + %23 = OpTypeInt 32 1 + %24 = OpConstant %23 1 + %25 = OpTypePointer Uniform %9 + %28 = OpConstant %6 0 + %29 = OpConstantComposite %9 %28 %28 %28 %28 + %34 = OpTypePointer Function %9 + %36 = OpTypeImage %6 2D 0 0 0 1 Unknown + %37 = OpTypeSampledImage %36 + %38 = OpTypePointer UniformConstant %37 + %39 = OpVariable %38 UniformConstant + %41 = OpConstantComposite %7 %28 %28 + %45 = OpTypePointer Function %6 + %47 = OpConstant %23 0 + %48 = OpTypePointer Uniform %6 + %53 = OpConstant %6 1 + %55 = OpTypeBool + %56 = OpTypePointer Function %55 + %58 = OpConstant %10 0 + %59 = OpTypePointer Private %6 + %74 = OpTypePointer Function %23 + %87 = OpTypePointer Function %10 + %95 = OpSpecConstant %10 2 + %100 = OpConstant %10 1 + %109 = OpConstantComposite %9 %53 %53 %53 %53 + %127 = OpConstant %23 10 + %139 = OpConstant %6 2 + %143 = OpConstant %6 3 + %158 = OpConstant %6 4 + %177 = OpConstant %6 0.5 + %195 = OpConstant %23 100 + %202 = OpTypeVector %10 4 + %203 = OpTypePointer Output %202 + %204 = OpVariable %203 Output + %4 = OpFunction %2 None %3 + + %5 = OpLabel + %35 = OpVariable %34 Function + %46 = OpVariable %45 Function + %51 = OpVariable %45 Function + %57 = OpVariable %56 Function + %69 = OpVariable %8 Function + %75 = OpVariable %74 Function + %80 = OpVariable %34 Function + %88 = OpVariable %87 Function + %174 = OpVariable %45 Function + %187 = OpVariable %74 Function + %26 = OpAccessChain %25 %22 %24 + %27 = OpLoad %9 %26 + OpStore %19 %27 + %40 = OpLoad %37 %39 + %42 = OpImageSampleImplicitLod %9 %40 %41 + %43 = OpLoad %9 %19 + %44 = OpFAdd %9 %42 %43 + OpStore %35 %44 + %49 = OpAccessChain %48 %22 %47 + %50 = OpLoad %6 %49 + OpStore %46 %50 + %52 = OpLoad %6 %46 + %54 = OpFAdd %6 %52 %53 + OpStore %51 %54 + %60 = OpAccessChain %59 %19 %58 + %61 = OpLoad %6 %60 + %62 = OpFOrdGreaterThan %55 %61 %28 + OpSelectionMerge %64 None + OpBranchConditional %62 %63 %64 + + %63 = OpLabel + %65 = OpLoad %6 %46 + %66 = OpLoad %6 %51 + %67 = OpCompositeConstruct %7 %65 %66 + %68 = OpLoad %6 %51 + OpStore %69 %67 + %70 = OpFunctionCall %12 %16 %69 %68 + %71 = OpCompositeExtract %6 %70 0 0 + %72 = OpFOrdGreaterThan %55 %71 %28 + OpBranch %64 + + %64 = OpLabel + %73 = OpPhi %55 %62 %5 %72 %63 + OpStore %57 %73 + OpStore %75 %47 + OpBranch %76 + + %76 = OpLabel + OpLoopMerge %78 %79 None + OpBranch %77 + + %77 = OpLabel + %81 = OpLoad %9 %19 + OpStore %80 %81 + %82 = OpAccessChain %45 %80 %58 + %83 = OpLoad %6 %82 + %84 = OpFOrdGreaterThan %55 %83 %28 + OpSelectionMerge %86 None + OpBranchConditional %84 %85 %113 + + %85 = OpLabel + OpStore %88 %58 + OpBranch %89 + + %89 = OpLabel + OpLoopMerge %91 %92 None + OpBranch %93 + + %93 = OpLabel + %94 = OpLoad %10 %88 + %96 = OpULessThan %55 %94 %95 + OpBranchConditional %96 %90 %91 + + %90 = OpLabel + %97 = OpLoad %9 %19 + %98 = OpLoad %9 %80 + %99 = OpFAdd %9 %98 %97 + OpStore %80 %99 + %101 = OpAccessChain %45 %80 %100 + %102 = OpLoad %6 %101 + %103 = OpFOrdLessThan %55 %102 %28 + OpSelectionMerge %105 None + OpBranchConditional %103 %104 %105 + + %104 = OpLabel + OpBranch %91 + + %105 = OpLabel + OpBranch %92 + + %92 = OpLabel + %107 = OpLoad %10 %88 + %108 = OpIAdd %10 %107 %24 + OpStore %88 %108 + OpBranch %89 + + %91 = OpLabel + %110 = OpLoad %9 %80 + %111 = OpFAdd %9 %110 %109 + OpStore %80 %111 + OpBranch %79 + + %113 = OpLabel + %114 = OpLoad %9 %80 + %115 = OpFSub %9 %114 %109 + OpStore %80 %115 + OpBranch %86 + + %86 = OpLabel + %116 = OpAccessChain %45 %80 %100 + %117 = OpLoad %6 %116 + %118 = OpFOrdGreaterThan %55 %117 %28 + OpSelectionMerge %120 None + OpBranchConditional %118 %119 %120 + + %119 = OpLabel + OpBranch %78 + + %120 = OpLabel + %122 = OpAccessChain %45 %80 %11 + %123 = OpLoad %6 %122 + %124 = OpFAdd %6 %123 %53 + %125 = OpAccessChain %45 %80 %11 + OpStore %125 %124 + OpBranch %79 + + %79 = OpLabel + %126 = OpLoad %23 %75 + %128 = OpSLessThan %55 %126 %127 + OpBranchConditional %128 %76 %78 + + %78 = OpLabel + %129 = OpAccessChain %48 %22 %47 + %130 = OpLoad %6 %129 + %131 = OpConvertFToS %23 %130 + OpSelectionMerge %136 None + OpSwitch %131 %135 0 %132 1 %132 2 %132 3 %133 4 %134 + + %132 = OpLabel + %137 = OpLoad %6 %51 + %138 = OpFAdd %6 %137 %53 + OpStore %51 %138 + OpBranch %133 + + %133 = OpLabel + %140 = OpLoad %6 %51 + %141 = OpFAdd %6 %140 %139 + OpStore %51 %141 + OpBranch %136 + + %134 = OpLabel + %144 = OpLoad %6 %51 + %145 = OpFAdd %6 %144 %143 + OpStore %51 %145 + OpBranch %146 + + %146 = OpLabel + OpLoopMerge %148 %149 None + OpBranch %150 + + %150 = OpLabel + %151 = OpLoad %6 %51 + %152 = OpFOrdLessThan %55 %151 %139 + OpBranchConditional %152 %147 %148 + + %147 = OpLabel + %153 = OpLoad %6 %46 + %154 = OpFOrdLessThan %55 %153 %53 + OpSelectionMerge %156 None + OpBranchConditional %154 %155 %156 + + %155 = OpLabel + OpBranch %148 + + %156 = OpLabel + OpBranch %149 + + %149 = OpLabel + OpBranch %146 + + %148 = OpLabel + OpBranch %135 + + %135 = OpLabel + %159 = OpLoad %6 %51 + %160 = OpFAdd %6 %159 %158 + OpStore %51 %160 + OpBranch %161 + + %161 = OpLabel + OpLoopMerge %163 %164 None + OpBranch %165 + + %165 = OpLabel + %166 = OpLoad %6 %51 + %167 = OpFOrdLessThan %55 %166 %139 + OpBranchConditional %167 %162 %163 + + %162 = OpLabel + %168 = OpLoad %6 %46 + %169 = OpFOrdLessThan %55 %168 %53 + OpSelectionMerge %171 None + OpBranchConditional %169 %170 %171 + + %170 = OpLabel + OpBranch %163 + + %171 = OpLabel + OpBranch %164 + + %164 = OpLabel + OpBranch %161 + + %163 = OpLabel + OpBranch %136 + + %136 = OpLabel + OpStore %174 %53 + %175 = OpAccessChain %45 %35 %58 + %176 = OpLoad %6 %175 + %178 = OpFOrdLessThanEqual %55 %176 %177 + OpSelectionMerge %180 None + OpBranchConditional %178 %179 %181 + + %179 = OpLabel + OpStore %174 %28 + OpBranch %180 + + %181 = OpLabel + %182 = OpAccessChain %45 %35 %58 + %183 = OpLoad %6 %182 + %184 = OpFOrdGreaterThanEqual %55 %183 %177 + OpSelectionMerge %186 None + OpBranchConditional %184 %185 %186 + + %185 = OpLabel + OpStore %174 %139 + OpBranch %186 + + %186 = OpLabel + OpBranch %180 + + %180 = OpLabel + OpStore %187 %47 + OpBranch %188 + + %188 = OpLabel + OpLoopMerge %190 %191 None + OpBranch %189 + + %189 = OpLabel + %192 = OpLoad %9 %19 + %193 = OpFAdd %9 %192 %109 + OpStore %19 %193 + %194 = OpLoad %23 %187 + %196 = OpSGreaterThan %55 %194 %195 + OpSelectionMerge %198 None + OpBranchConditional %196 %197 %198 + + %197 = OpLabel + OpBranch %190 + + %198 = OpLabel + OpBranch %191 + + %191 = OpLabel + %200 = OpLoad %23 %187 + %201 = OpIAdd %23 %200 %24 + OpStore %187 %201 + OpBranch %188 + + %190 = OpLabel + OpReturn + OpFunctionEnd + %16 = OpFunction %12 None %13 + %14 = OpFunctionParameter %8 + %15 = OpFunctionParameter %6 + + %17 = OpLabel + %30 = OpCompositeConstruct %9 %15 %15 %15 %15 + %31 = OpCompositeConstruct %12 %29 %30 + OpReturnValue %31 + OpFunctionEnd +)"; + EXPECT_THAT(EncodeAndDecodeSuccessfully( + input, + SPV_BINARY_TO_TEXT_OPTION_INDENT | + SPV_BINARY_TO_TEXT_OPTION_NESTED_INDENT | + SPV_BINARY_TO_TEXT_OPTION_REORDER_BLOCKS, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS), + expected); +} + using FriendlyNameDisassemblyTest = spvtest::TextToBinaryTest; TEST_F(FriendlyNameDisassemblyTest, Sample) { @@ -703,216 +2159,416 @@ OpFunctionEnd )"; const std::string expected = R"( OpCapability Shader OpMemoryModel Logical GLSL450 - OpEntryPoint Fragment %1 "main" %2 %3 - OpExecutionMode %1 OriginUpperLeft + OpEntryPoint Fragment %63 "main" %4 %22 + OpExecutionMode %63 OriginUpperLeft ; Debug Information OpSource GLSL 450 - OpName %2 "_ue" ; id %2 - OpName %4 "_uf" ; id %4 - OpName %5 "_ug" ; id %5 - OpName %6 "_uA" ; id %6 - OpMemberName %6 0 "_ux" - OpName %7 "_uc" ; id %7 - OpName %8 "_uB" ; id %8 - OpMemberName %8 0 "_ux" - OpName %9 "_ud" ; id %9 - OpName %3 "_ucol" ; id %3 - OpName %10 "ANGLEDepthRangeParams" ; id %10 - OpMemberName %10 0 "near" - OpMemberName %10 1 "far" - OpMemberName %10 2 "diff" - OpMemberName %10 3 "reserved" - OpName %11 "ANGLEUniformBlock" ; id %11 - OpMemberName %11 0 "viewport" - OpMemberName %11 1 "clipDistancesEnabled" - OpMemberName %11 2 "xfbActiveUnpaused" - OpMemberName %11 3 "xfbVerticesPerInstance" - OpMemberName %11 4 "numSamples" - OpMemberName %11 5 "xfbBufferOffsets" - OpMemberName %11 6 "acbBufferOffsets" - OpMemberName %11 7 "depthRange" - OpName %12 "ANGLEUniforms" ; id %12 - OpName %13 "_uc" ; id %13 - OpName %14 "_uh" ; id %14 - OpName %15 "_ux" ; id %15 - OpName %16 "_uy" ; id %16 - OpName %17 "_ui" ; id %17 - OpName %1 "main" ; id %1 - OpName %18 "param" ; id %18 - OpName %19 "param" ; id %19 - OpName %20 "param" ; id %20 + OpName %4 "_ue" ; id %4 + OpName %8 "_uf" ; id %8 + OpName %11 "_ug" ; id %11 + OpName %12 "_uA" ; id %12 + OpMemberName %12 0 "_ux" + OpName %14 "_uc" ; id %14 + OpName %15 "_uB" ; id %15 + OpMemberName %15 0 "_ux" + OpName %20 "_ud" ; id %20 + OpName %22 "_ucol" ; id %22 + OpName %26 "ANGLEDepthRangeParams" ; id %26 + OpMemberName %26 0 "near" + OpMemberName %26 1 "far" + OpMemberName %26 2 "diff" + OpMemberName %26 3 "reserved" + OpName %27 "ANGLEUniformBlock" ; id %27 + OpMemberName %27 0 "viewport" + OpMemberName %27 1 "clipDistancesEnabled" + OpMemberName %27 2 "xfbActiveUnpaused" + OpMemberName %27 3 "xfbVerticesPerInstance" + OpMemberName %27 4 "numSamples" + OpMemberName %27 5 "xfbBufferOffsets" + OpMemberName %27 6 "acbBufferOffsets" + OpMemberName %27 7 "depthRange" + OpName %29 "ANGLEUniforms" ; id %29 + OpName %33 "_uc" ; id %33 + OpName %32 "_uh" ; id %32 + OpName %49 "_ux" ; id %49 + OpName %50 "_uy" ; id %50 + OpName %48 "_ui" ; id %48 + OpName %63 "main" ; id %63 + OpName %65 "param" ; id %65 + OpName %68 "param" ; id %68 + OpName %73 "param" ; id %73 ; Annotations - OpDecorate %2 Location 0 - OpDecorate %4 RelaxedPrecision - OpDecorate %4 DescriptorSet 0 - OpDecorate %4 Binding 0 - OpDecorate %5 DescriptorSet 0 - OpDecorate %5 Binding 1 - OpMemberDecorate %6 0 Offset 0 - OpMemberDecorate %6 0 RelaxedPrecision - OpDecorate %6 Block - OpDecorate %7 DescriptorSet 0 - OpDecorate %7 Binding 2 - OpMemberDecorate %8 0 Offset 0 - OpMemberDecorate %8 0 RelaxedPrecision - OpDecorate %8 BufferBlock - OpDecorate %9 DescriptorSet 0 - OpDecorate %9 Binding 3 - OpDecorate %3 RelaxedPrecision - OpDecorate %3 Location 0 - OpMemberDecorate %10 0 Offset 0 - OpMemberDecorate %10 1 Offset 4 - OpMemberDecorate %10 2 Offset 8 - OpMemberDecorate %10 3 Offset 12 - OpMemberDecorate %11 0 Offset 0 - OpMemberDecorate %11 1 Offset 16 - OpMemberDecorate %11 2 Offset 20 - OpMemberDecorate %11 3 Offset 24 - OpMemberDecorate %11 4 Offset 28 - OpMemberDecorate %11 5 Offset 32 - OpMemberDecorate %11 6 Offset 48 - OpMemberDecorate %11 7 Offset 64 - OpMemberDecorate %11 2 RelaxedPrecision - OpMemberDecorate %11 4 RelaxedPrecision - OpDecorate %11 Block - OpDecorate %12 DescriptorSet 0 - OpDecorate %12 Binding 4 - OpDecorate %14 RelaxedPrecision - OpDecorate %13 RelaxedPrecision - OpDecorate %21 RelaxedPrecision + OpDecorate %4 Location 0 + OpDecorate %8 RelaxedPrecision + OpDecorate %8 DescriptorSet 0 + OpDecorate %8 Binding 0 + OpDecorate %11 DescriptorSet 0 + OpDecorate %11 Binding 1 + OpMemberDecorate %12 0 Offset 0 + OpMemberDecorate %12 0 RelaxedPrecision + OpDecorate %12 Block + OpDecorate %14 DescriptorSet 0 + OpDecorate %14 Binding 2 + OpMemberDecorate %15 0 Offset 0 + OpMemberDecorate %15 0 RelaxedPrecision + OpDecorate %15 BufferBlock + OpDecorate %20 DescriptorSet 0 + OpDecorate %20 Binding 3 OpDecorate %22 RelaxedPrecision + OpDecorate %22 Location 0 + OpMemberDecorate %26 0 Offset 0 + OpMemberDecorate %26 1 Offset 4 + OpMemberDecorate %26 2 Offset 8 + OpMemberDecorate %26 3 Offset 12 + OpMemberDecorate %27 0 Offset 0 + OpMemberDecorate %27 1 Offset 16 + OpMemberDecorate %27 2 Offset 20 + OpMemberDecorate %27 3 Offset 24 + OpMemberDecorate %27 4 Offset 28 + OpMemberDecorate %27 5 Offset 32 + OpMemberDecorate %27 6 Offset 48 + OpMemberDecorate %27 7 Offset 64 + OpMemberDecorate %27 2 RelaxedPrecision + OpMemberDecorate %27 4 RelaxedPrecision + OpDecorate %27 Block + OpDecorate %29 DescriptorSet 0 + OpDecorate %29 Binding 4 + OpDecorate %32 RelaxedPrecision + OpDecorate %33 RelaxedPrecision + OpDecorate %36 RelaxedPrecision + OpDecorate %37 RelaxedPrecision + OpDecorate %38 RelaxedPrecision + OpDecorate %39 RelaxedPrecision + OpDecorate %41 RelaxedPrecision + OpDecorate %42 RelaxedPrecision + OpDecorate %43 RelaxedPrecision + OpDecorate %48 RelaxedPrecision + OpDecorate %49 RelaxedPrecision + OpDecorate %50 RelaxedPrecision + OpDecorate %52 RelaxedPrecision + OpDecorate %53 RelaxedPrecision + OpDecorate %54 RelaxedPrecision + OpDecorate %55 RelaxedPrecision + OpDecorate %56 RelaxedPrecision + OpDecorate %57 RelaxedPrecision + OpDecorate %58 RelaxedPrecision + OpDecorate %59 RelaxedPrecision + OpDecorate %60 RelaxedPrecision + OpDecorate %67 RelaxedPrecision + OpDecorate %68 RelaxedPrecision + OpDecorate %72 RelaxedPrecision + OpDecorate %73 RelaxedPrecision + OpDecorate %75 RelaxedPrecision + OpDecorate %76 RelaxedPrecision + OpDecorate %77 RelaxedPrecision + OpDecorate %80 RelaxedPrecision + OpDecorate %81 RelaxedPrecision + + ; Types, variables and constants + %1 = OpTypeFloat 32 + %2 = OpTypeVector %1 4 + %5 = OpTypeImage %1 2D 0 0 0 1 Unknown + %6 = OpTypeSampledImage %5 + %9 = OpTypeImage %1 2D 0 0 0 2 Rgba8 + %12 = OpTypeStruct %2 ; Block + %15 = OpTypeStruct %2 ; BufferBlock + %16 = OpTypeInt 32 0 + %17 = OpConstant %16 2 + %18 = OpTypeArray %15 %17 + %23 = OpTypeInt 32 1 + %24 = OpTypeVector %23 4 + %25 = OpTypeVector %16 4 + %26 = OpTypeStruct %1 %1 %1 %1 + %27 = OpTypeStruct %2 %16 %16 %23 %23 %24 %25 %26 ; Block + %35 = OpTypeVector %1 2 + %40 = OpTypeVector %23 2 + %61 = OpTypeVoid + %69 = OpConstant %16 0 + %78 = OpConstant %16 1 + %3 = OpTypePointer Input %2 + %7 = OpTypePointer UniformConstant %6 + %10 = OpTypePointer UniformConstant %9 + %13 = OpTypePointer Uniform %12 + %19 = OpTypePointer Uniform %18 + %21 = OpTypePointer Output %2 + %28 = OpTypePointer Uniform %27 + %30 = OpTypePointer Function %2 + %70 = OpTypePointer Uniform %2 + %31 = OpTypeFunction %2 %30 + %47 = OpTypeFunction %2 %30 %30 + %62 = OpTypeFunction %61 + %4 = OpVariable %3 Input ; Location 0 + %8 = OpVariable %7 UniformConstant ; RelaxedPrecision, DescriptorSet 0, Binding 0 + %11 = OpVariable %10 UniformConstant ; DescriptorSet 0, Binding 1 + %14 = OpVariable %13 Uniform ; DescriptorSet 0, Binding 2 + %20 = OpVariable %19 Uniform ; DescriptorSet 0, Binding 3 + %22 = OpVariable %21 Output ; RelaxedPrecision, Location 0 + %29 = OpVariable %28 Uniform ; DescriptorSet 0, Binding 4 + + ; Function 32 + %32 = OpFunction %2 None %31 ; RelaxedPrecision + %33 = OpFunctionParameter %30 ; RelaxedPrecision + %34 = OpLabel + %36 = OpLoad %6 %8 ; RelaxedPrecision + %37 = OpLoad %2 %33 ; RelaxedPrecision + %38 = OpVectorShuffle %35 %37 %37 0 1 ; RelaxedPrecision + %39 = OpImageSampleImplicitLod %2 %36 %38 ; RelaxedPrecision + %41 = OpLoad %2 %33 ; RelaxedPrecision + %42 = OpVectorShuffle %35 %41 %41 2 3 ; RelaxedPrecision + %43 = OpConvertFToS %40 %42 ; RelaxedPrecision + %44 = OpLoad %9 %11 + %45 = OpImageRead %2 %44 %43 + %46 = OpFAdd %2 %39 %45 + OpReturnValue %46 + OpFunctionEnd + + ; Function 48 + %48 = OpFunction %2 None %47 ; RelaxedPrecision + %49 = OpFunctionParameter %30 ; RelaxedPrecision + %50 = OpFunctionParameter %30 ; RelaxedPrecision + %51 = OpLabel + %52 = OpLoad %2 %49 ; RelaxedPrecision + %53 = OpVectorShuffle %35 %52 %52 0 1 ; RelaxedPrecision + %54 = OpLoad %2 %50 ; RelaxedPrecision + %55 = OpVectorShuffle %35 %54 %54 2 3 ; RelaxedPrecision + %56 = OpCompositeExtract %1 %53 0 ; RelaxedPrecision + %57 = OpCompositeExtract %1 %53 1 ; RelaxedPrecision + %58 = OpCompositeExtract %1 %55 0 ; RelaxedPrecision + %59 = OpCompositeExtract %1 %55 1 ; RelaxedPrecision + %60 = OpCompositeConstruct %2 %56 %57 %58 %59 ; RelaxedPrecision + OpReturnValue %60 + OpFunctionEnd + + ; Function 63 + %63 = OpFunction %61 None %62 + %64 = OpLabel + %65 = OpVariable %30 Function + %68 = OpVariable %30 Function ; RelaxedPrecision + %73 = OpVariable %30 Function ; RelaxedPrecision + %66 = OpLoad %2 %4 + OpStore %65 %66 + %67 = OpFunctionCall %2 %32 %65 ; RelaxedPrecision + %71 = OpAccessChain %70 %14 %69 + %72 = OpLoad %2 %71 ; RelaxedPrecision + OpStore %68 %72 + %74 = OpAccessChain %70 %20 %69 %69 + %75 = OpLoad %2 %74 ; RelaxedPrecision + OpStore %73 %75 + %76 = OpFunctionCall %2 %48 %68 %73 ; RelaxedPrecision + %77 = OpFAdd %2 %67 %76 ; RelaxedPrecision + %79 = OpAccessChain %70 %20 %78 %69 + %80 = OpLoad %2 %79 ; RelaxedPrecision + %81 = OpFAdd %2 %77 %80 ; RelaxedPrecision + OpStore %22 %81 + OpReturn + OpFunctionEnd +)"; + + EXPECT_THAT( + EncodeAndDecodeSuccessfully( + input, + SPV_BINARY_TO_TEXT_OPTION_COMMENT | SPV_BINARY_TO_TEXT_OPTION_INDENT, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS), + expected); +} + +TEST_F(TextToBinaryTest, NestedWithComments) { + const std::string input = R"(OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %8 %44 + OpExecutionMode %4 OriginUpperLeft + OpSource ESSL 310 + OpName %4 "main" + OpName %8 "v" + OpName %44 "color" + OpDecorate %8 RelaxedPrecision + OpDecorate %8 Location 0 + OpDecorate %9 RelaxedPrecision + OpDecorate %18 RelaxedPrecision + OpDecorate %19 RelaxedPrecision + OpDecorate %20 RelaxedPrecision OpDecorate %23 RelaxedPrecision OpDecorate %24 RelaxedPrecision OpDecorate %25 RelaxedPrecision OpDecorate %26 RelaxedPrecision OpDecorate %27 RelaxedPrecision - OpDecorate %17 RelaxedPrecision - OpDecorate %15 RelaxedPrecision - OpDecorate %16 RelaxedPrecision OpDecorate %28 RelaxedPrecision OpDecorate %29 RelaxedPrecision OpDecorate %30 RelaxedPrecision OpDecorate %31 RelaxedPrecision - OpDecorate %32 RelaxedPrecision OpDecorate %33 RelaxedPrecision OpDecorate %34 RelaxedPrecision OpDecorate %35 RelaxedPrecision OpDecorate %36 RelaxedPrecision OpDecorate %37 RelaxedPrecision + OpDecorate %39 RelaxedPrecision + OpDecorate %40 RelaxedPrecision + OpDecorate %41 RelaxedPrecision + OpDecorate %42 RelaxedPrecision + OpDecorate %44 RelaxedPrecision + OpDecorate %44 Location 0 + OpDecorate %45 RelaxedPrecision + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Input %6 + %8 = OpVariable %7 Input + %10 = OpConstant %6 0 + %11 = OpTypeBool + %15 = OpTypeVector %6 4 + %16 = OpTypePointer Function %15 + %21 = OpConstant %6 -0.5 + %22 = OpConstant %6 -0.300000012 + %38 = OpConstant %6 0.5 + %43 = OpTypePointer Output %15 + %44 = OpVariable %43 Output + %4 = OpFunction %2 None %3 + %5 = OpLabel + %9 = OpLoad %6 %8 + %12 = OpFOrdLessThanEqual %11 %9 %10 + OpSelectionMerge %14 None + OpBranchConditional %12 %13 %32 + %13 = OpLabel + %18 = OpLoad %6 %8 + %19 = OpExtInst %6 %1 Log %18 + %20 = OpLoad %6 %8 + %23 = OpExtInst %6 %1 FClamp %20 %21 %22 + %24 = OpFMul %6 %19 %23 + %25 = OpLoad %6 %8 + %26 = OpExtInst %6 %1 Sin %25 + %27 = OpLoad %6 %8 + %28 = OpExtInst %6 %1 Cos %27 + %29 = OpLoad %6 %8 + %30 = OpExtInst %6 %1 Exp %29 + %31 = OpCompositeConstruct %15 %24 %26 %28 %30 + OpBranch %14 + %32 = OpLabel + %33 = OpLoad %6 %8 + %34 = OpExtInst %6 %1 Sqrt %33 + %35 = OpLoad %6 %8 + %36 = OpExtInst %6 %1 FSign %35 + %37 = OpLoad %6 %8 + %39 = OpExtInst %6 %1 FMax %37 %38 + %40 = OpLoad %6 %8 + %41 = OpExtInst %6 %1 Floor %40 + %42 = OpCompositeConstruct %15 %34 %36 %39 %41 + OpBranch %14 + %14 = OpLabel + %45 = OpPhi %15 %31 %13 %42 %32 + OpStore %44 %45 + OpReturn + OpFunctionEnd +)"; + const std::string expected = R"( OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %4 "main" %8 %44 + OpExecutionMode %4 OriginUpperLeft + + ; Debug Information + OpSource ESSL 310 + OpName %4 "main" ; id %4 + OpName %8 "v" ; id %8 + OpName %44 "color" ; id %44 + + ; Annotations + OpDecorate %8 RelaxedPrecision + OpDecorate %8 Location 0 + OpDecorate %9 RelaxedPrecision + OpDecorate %18 RelaxedPrecision OpDecorate %19 RelaxedPrecision - OpDecorate %38 RelaxedPrecision OpDecorate %20 RelaxedPrecision + OpDecorate %23 RelaxedPrecision + OpDecorate %24 RelaxedPrecision + OpDecorate %25 RelaxedPrecision + OpDecorate %26 RelaxedPrecision + OpDecorate %27 RelaxedPrecision + OpDecorate %28 RelaxedPrecision + OpDecorate %29 RelaxedPrecision + OpDecorate %30 RelaxedPrecision + OpDecorate %31 RelaxedPrecision + OpDecorate %33 RelaxedPrecision + OpDecorate %34 RelaxedPrecision + OpDecorate %35 RelaxedPrecision + OpDecorate %36 RelaxedPrecision + OpDecorate %37 RelaxedPrecision OpDecorate %39 RelaxedPrecision OpDecorate %40 RelaxedPrecision OpDecorate %41 RelaxedPrecision OpDecorate %42 RelaxedPrecision - OpDecorate %43 RelaxedPrecision + OpDecorate %44 RelaxedPrecision + OpDecorate %44 Location 0 + OpDecorate %45 RelaxedPrecision ; Types, variables and constants - %44 = OpTypeFloat 32 - %45 = OpTypeVector %44 4 - %46 = OpTypeImage %44 2D 0 0 0 1 Unknown - %47 = OpTypeSampledImage %46 - %48 = OpTypeImage %44 2D 0 0 0 2 Rgba8 - %6 = OpTypeStruct %45 ; Block - %8 = OpTypeStruct %45 ; BufferBlock - %49 = OpTypeInt 32 0 - %50 = OpConstant %49 2 - %51 = OpTypeArray %8 %50 - %52 = OpTypeInt 32 1 - %53 = OpTypeVector %52 4 - %54 = OpTypeVector %49 4 - %10 = OpTypeStruct %44 %44 %44 %44 - %11 = OpTypeStruct %45 %49 %49 %52 %52 %53 %54 %10 ; Block - %55 = OpTypeVector %44 2 - %56 = OpTypeVector %52 2 - %57 = OpTypeVoid - %58 = OpConstant %49 0 - %59 = OpConstant %49 1 - %60 = OpTypePointer Input %45 - %61 = OpTypePointer UniformConstant %47 - %62 = OpTypePointer UniformConstant %48 - %63 = OpTypePointer Uniform %6 - %64 = OpTypePointer Uniform %51 - %65 = OpTypePointer Output %45 - %66 = OpTypePointer Uniform %11 - %67 = OpTypePointer Function %45 - %68 = OpTypePointer Uniform %45 - %69 = OpTypeFunction %45 %67 - %70 = OpTypeFunction %45 %67 %67 - %71 = OpTypeFunction %57 - %2 = OpVariable %60 Input ; Location 0 - %4 = OpVariable %61 UniformConstant ; RelaxedPrecision, DescriptorSet 0, Binding 0 - %5 = OpVariable %62 UniformConstant ; DescriptorSet 0, Binding 1 - %7 = OpVariable %63 Uniform ; DescriptorSet 0, Binding 2 - %9 = OpVariable %64 Uniform ; DescriptorSet 0, Binding 3 - %3 = OpVariable %65 Output ; RelaxedPrecision, Location 0 - %12 = OpVariable %66 Uniform ; DescriptorSet 0, Binding 4 - - ; Function 14 - %14 = OpFunction %45 None %69 ; RelaxedPrecision - %13 = OpFunctionParameter %67 ; RelaxedPrecision - %72 = OpLabel - %21 = OpLoad %47 %4 ; RelaxedPrecision - %22 = OpLoad %45 %13 ; RelaxedPrecision - %23 = OpVectorShuffle %55 %22 %22 0 1 ; RelaxedPrecision - %24 = OpImageSampleImplicitLod %45 %21 %23 ; RelaxedPrecision - %25 = OpLoad %45 %13 ; RelaxedPrecision - %26 = OpVectorShuffle %55 %25 %25 2 3 ; RelaxedPrecision - %27 = OpConvertFToS %56 %26 ; RelaxedPrecision - %73 = OpLoad %48 %5 - %74 = OpImageRead %45 %73 %27 - %75 = OpFAdd %45 %24 %74 - OpReturnValue %75 - OpFunctionEnd + %2 = OpTypeVoid + %3 = OpTypeFunction %2 + %6 = OpTypeFloat 32 + %7 = OpTypePointer Input %6 + %8 = OpVariable %7 Input ; RelaxedPrecision, Location 0 + %10 = OpConstant %6 0 + %11 = OpTypeBool + %15 = OpTypeVector %6 4 + %16 = OpTypePointer Function %15 + %21 = OpConstant %6 -0.5 + %22 = OpConstant %6 -0.300000012 + %38 = OpConstant %6 0.5 + %43 = OpTypePointer Output %15 + %44 = OpVariable %43 Output ; RelaxedPrecision, Location 0 - ; Function 17 - %17 = OpFunction %45 None %70 ; RelaxedPrecision - %15 = OpFunctionParameter %67 ; RelaxedPrecision - %16 = OpFunctionParameter %67 ; RelaxedPrecision - %76 = OpLabel - %28 = OpLoad %45 %15 ; RelaxedPrecision - %29 = OpVectorShuffle %55 %28 %28 0 1 ; RelaxedPrecision - %30 = OpLoad %45 %16 ; RelaxedPrecision - %31 = OpVectorShuffle %55 %30 %30 2 3 ; RelaxedPrecision - %32 = OpCompositeExtract %44 %29 0 ; RelaxedPrecision - %33 = OpCompositeExtract %44 %29 1 ; RelaxedPrecision - %34 = OpCompositeExtract %44 %31 0 ; RelaxedPrecision - %35 = OpCompositeExtract %44 %31 1 ; RelaxedPrecision - %36 = OpCompositeConstruct %45 %32 %33 %34 %35 ; RelaxedPrecision - OpReturnValue %36 - OpFunctionEnd - ; Function 1 - %1 = OpFunction %57 None %71 - %77 = OpLabel - %18 = OpVariable %67 Function - %19 = OpVariable %67 Function ; RelaxedPrecision - %20 = OpVariable %67 Function ; RelaxedPrecision - %78 = OpLoad %45 %2 - OpStore %18 %78 - %37 = OpFunctionCall %45 %14 %18 ; RelaxedPrecision - %79 = OpAccessChain %68 %7 %58 - %38 = OpLoad %45 %79 ; RelaxedPrecision - OpStore %19 %38 - %80 = OpAccessChain %68 %9 %58 %58 - %39 = OpLoad %45 %80 ; RelaxedPrecision - OpStore %20 %39 - %40 = OpFunctionCall %45 %17 %19 %20 ; RelaxedPrecision - %41 = OpFAdd %45 %37 %40 ; RelaxedPrecision - %81 = OpAccessChain %68 %9 %59 %58 - %42 = OpLoad %45 %81 ; RelaxedPrecision - %43 = OpFAdd %45 %41 %42 ; RelaxedPrecision - OpStore %3 %43 - OpReturn + ; Function 4 + %4 = OpFunction %2 None %3 + + %5 = OpLabel + %9 = OpLoad %6 %8 ; RelaxedPrecision + %12 = OpFOrdLessThanEqual %11 %9 %10 + OpSelectionMerge %14 None + OpBranchConditional %12 %13 %32 + + %13 = OpLabel + %18 = OpLoad %6 %8 ; RelaxedPrecision + %19 = OpExtInst %6 %1 Log %18 ; RelaxedPrecision + %20 = OpLoad %6 %8 ; RelaxedPrecision + %23 = OpExtInst %6 %1 FClamp %20 %21 %22 ; RelaxedPrecision + %24 = OpFMul %6 %19 %23 ; RelaxedPrecision + %25 = OpLoad %6 %8 ; RelaxedPrecision + %26 = OpExtInst %6 %1 Sin %25 ; RelaxedPrecision + %27 = OpLoad %6 %8 ; RelaxedPrecision + %28 = OpExtInst %6 %1 Cos %27 ; RelaxedPrecision + %29 = OpLoad %6 %8 ; RelaxedPrecision + %30 = OpExtInst %6 %1 Exp %29 ; RelaxedPrecision + %31 = OpCompositeConstruct %15 %24 %26 %28 %30 ; RelaxedPrecision + OpBranch %14 + + %32 = OpLabel + %33 = OpLoad %6 %8 ; RelaxedPrecision + %34 = OpExtInst %6 %1 Sqrt %33 ; RelaxedPrecision + %35 = OpLoad %6 %8 ; RelaxedPrecision + %36 = OpExtInst %6 %1 FSign %35 ; RelaxedPrecision + %37 = OpLoad %6 %8 ; RelaxedPrecision + %39 = OpExtInst %6 %1 FMax %37 %38 ; RelaxedPrecision + %40 = OpLoad %6 %8 ; RelaxedPrecision + %41 = OpExtInst %6 %1 Floor %40 ; RelaxedPrecision + %42 = OpCompositeConstruct %15 %34 %36 %39 %41 ; RelaxedPrecision + OpBranch %14 + + %14 = OpLabel + %45 = OpPhi %15 %31 %13 %42 %32 ; RelaxedPrecision + OpStore %44 %45 + OpReturn OpFunctionEnd )"; EXPECT_THAT( - EncodeAndDecodeSuccessfully(input, SPV_BINARY_TO_TEXT_OPTION_COMMENT | - SPV_BINARY_TO_TEXT_OPTION_INDENT), + EncodeAndDecodeSuccessfully( + input, + SPV_BINARY_TO_TEXT_OPTION_COMMENT | SPV_BINARY_TO_TEXT_OPTION_INDENT | + SPV_BINARY_TO_TEXT_OPTION_NESTED_INDENT, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS), expected); } diff --git a/test/ext_inst.non_semantic_test.cpp b/test/ext_inst.non_semantic_test.cpp index 870684e9bf..506218933e 100644 --- a/test/ext_inst.non_semantic_test.cpp +++ b/test/ext_inst.non_semantic_test.cpp @@ -41,8 +41,7 @@ TEST_F(NonSemanticRoundTripTest, NonSemanticInsts) { %8 = OpExtInstImport "NonSemantic.Testing.AnotherUnknownExtInstSet" %9 = OpExtInst %4 %8 613874321 %7 %5 %6 )"; - std::string disassembly = EncodeAndDecodeSuccessfully( - spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_ENV_UNIVERSAL_1_0); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } diff --git a/test/test_fixture.h b/test/test_fixture.h index 029fc8543b..424f5eebe6 100644 --- a/test/test_fixture.h +++ b/test/test_fixture.h @@ -111,13 +111,15 @@ class TextToBinaryTestBase : public T { std::string EncodeAndDecodeSuccessfully( const std::string& txt, uint32_t disassemble_options = SPV_BINARY_TO_TEXT_OPTION_NONE, + uint32_t assemble_options = SPV_TEXT_TO_BINARY_OPTION_NONE, spv_target_env env = SPV_ENV_UNIVERSAL_1_0, bool flip_words = false) { DestroyBinary(); DestroyDiagnostic(); ScopedContext context(env); disassemble_options |= SPV_BINARY_TO_TEXT_OPTION_NO_HEADER; - spv_result_t error = spvTextToBinary(context.context, txt.c_str(), - txt.size(), &binary, &diagnostic); + spv_result_t error = + spvTextToBinaryWithOptions(context.context, txt.c_str(), txt.size(), + assemble_options, &binary, &diagnostic); if (error) { spvDiagnosticPrint(diagnostic); spvDiagnosticDestroy(diagnostic); diff --git a/test/text_to_binary.annotation_test.cpp b/test/text_to_binary.annotation_test.cpp index 826812bf24..edf886f6c3 100644 --- a/test/text_to_binary.annotation_test.cpp +++ b/test/text_to_binary.annotation_test.cpp @@ -55,10 +55,10 @@ TEST_P(OpDecorateSimpleTest, AnySimpleDecoration) { {1, uint32_t(std::get<1>(GetParam()).value())}, std::get<1>(GetParam()).operands()))); // Also check disassembly. - EXPECT_THAT( - EncodeAndDecodeSuccessfully(input.str(), SPV_BINARY_TO_TEXT_OPTION_NONE, - std::get<0>(GetParam())), - Eq(input.str())); + EXPECT_THAT(EncodeAndDecodeSuccessfully( + input.str(), SPV_BINARY_TO_TEXT_OPTION_NONE, + SPV_TEXT_TO_BINARY_OPTION_NONE, std::get<0>(GetParam())), + Eq(input.str())); } // Like above, but parameters to the decoration are IDs. @@ -78,10 +78,10 @@ TEST_P(OpDecorateSimpleIdTest, AnySimpleDecoration) { {1, uint32_t(std::get<1>(GetParam()).value())}, std::get<1>(GetParam()).operands()))); // Also check disassembly. - EXPECT_THAT( - EncodeAndDecodeSuccessfully(input.str(), SPV_BINARY_TO_TEXT_OPTION_NONE, - std::get<0>(GetParam())), - Eq(input.str())); + EXPECT_THAT(EncodeAndDecodeSuccessfully( + input.str(), SPV_BINARY_TO_TEXT_OPTION_NONE, + SPV_TEXT_TO_BINARY_OPTION_NONE, std::get<0>(GetParam())), + Eq(input.str())); } #define CASE(NAME) spv::Decoration::NAME, #NAME @@ -460,10 +460,10 @@ TEST_P(OpMemberDecorateSimpleTest, AnySimpleDecoration) { {1, 42, uint32_t(std::get<1>(GetParam()).value())}, std::get<1>(GetParam()).operands()))); // Also check disassembly. - EXPECT_THAT( - EncodeAndDecodeSuccessfully(input.str(), SPV_BINARY_TO_TEXT_OPTION_NONE, - std::get<0>(GetParam())), - Eq(input.str())); + EXPECT_THAT(EncodeAndDecodeSuccessfully( + input.str(), SPV_BINARY_TO_TEXT_OPTION_NONE, + SPV_TEXT_TO_BINARY_OPTION_NONE, std::get<0>(GetParam())), + Eq(input.str())); } #define CASE(NAME) spv::Decoration::NAME, #NAME diff --git a/test/text_to_binary.composite_test.cpp b/test/text_to_binary.composite_test.cpp index 6ae1cd35d6..2f255ac46e 100644 --- a/test/text_to_binary.composite_test.cpp +++ b/test/text_to_binary.composite_test.cpp @@ -35,7 +35,8 @@ using CompositeRoundTripTest = RoundTripTest; TEST_F(CompositeRoundTripTest, Good) { std::string spirv = "%2 = OpCopyLogical %1 %3\n"; std::string disassembly = EncodeAndDecodeSuccessfully( - spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_ENV_UNIVERSAL_1_4); + spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_TEXT_TO_BINARY_OPTION_NONE, + SPV_ENV_UNIVERSAL_1_4); EXPECT_THAT(disassembly, Eq(spirv)); } diff --git a/test/text_to_binary.extension_test.cpp b/test/text_to_binary.extension_test.cpp index 1d58c02ba2..2efd27b49a 100644 --- a/test/text_to_binary.extension_test.cpp +++ b/test/text_to_binary.extension_test.cpp @@ -130,9 +130,10 @@ TEST_P(ExtensionRoundTripTest, Samples) { EXPECT_THAT(CompiledInstructions(ac.input, env), Eq(ac.expected)); // Check round trip through the disassembler. - EXPECT_THAT(EncodeAndDecodeSuccessfully(ac.input, - SPV_BINARY_TO_TEXT_OPTION_NONE, env), - Eq(ac.input)) + EXPECT_THAT( + EncodeAndDecodeSuccessfully(ac.input, SPV_BINARY_TO_TEXT_OPTION_NONE, + SPV_TEXT_TO_BINARY_OPTION_NONE, env), + Eq(ac.input)) << "target env: " << spvTargetEnvDescription(env) << "\n"; } diff --git a/test/text_to_binary.memory_test.cpp b/test/text_to_binary.memory_test.cpp index 629ab661bf..43523d18a5 100644 --- a/test/text_to_binary.memory_test.cpp +++ b/test/text_to_binary.memory_test.cpp @@ -107,7 +107,8 @@ TEST_F(MemoryRoundTripTest, OpPtrEqualGood) { EXPECT_THAT(CompiledInstructions(spirv, SPV_ENV_UNIVERSAL_1_4), Eq(MakeInstruction(spv::Op::OpPtrEqual, {1, 2, 3, 4}))); std::string disassembly = EncodeAndDecodeSuccessfully( - spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_ENV_UNIVERSAL_1_4); + spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_TEXT_TO_BINARY_OPTION_NONE, + SPV_ENV_UNIVERSAL_1_4); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -124,7 +125,8 @@ TEST_F(MemoryRoundTripTest, OpPtrNotEqualGood) { EXPECT_THAT(CompiledInstructions(spirv, SPV_ENV_UNIVERSAL_1_4), Eq(MakeInstruction(spv::Op::OpPtrNotEqual, {1, 2, 3, 4}))); std::string disassembly = EncodeAndDecodeSuccessfully( - spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_ENV_UNIVERSAL_1_4); + spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_TEXT_TO_BINARY_OPTION_NONE, + SPV_ENV_UNIVERSAL_1_4); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -141,7 +143,8 @@ TEST_F(MemoryRoundTripTest, OpPtrDiffGood) { EXPECT_THAT(CompiledInstructions(spirv, SPV_ENV_UNIVERSAL_1_4), Eq(MakeInstruction(spv::Op::OpPtrDiff, {1, 2, 3, 4}))); std::string disassembly = EncodeAndDecodeSuccessfully( - spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_ENV_UNIVERSAL_1_4); + spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_TEXT_TO_BINARY_OPTION_NONE, + SPV_ENV_UNIVERSAL_1_4); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -151,7 +154,8 @@ TEST_F(MemoryRoundTripTest, OpPtrDiffV13Good) { // write tests. std::string spirv = "%2 = OpPtrDiff %1 %3 %4\n"; std::string disassembly = EncodeAndDecodeSuccessfully( - spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_ENV_UNIVERSAL_1_4); + spirv, SPV_BINARY_TO_TEXT_OPTION_NONE, SPV_TEXT_TO_BINARY_OPTION_NONE, + SPV_ENV_UNIVERSAL_1_4); } // OpCopyMemory @@ -160,8 +164,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemoryNoMemAccessGood) { std::string spirv = "OpCopyMemory %1 %2\n"; EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemory, {1, 2}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -182,8 +185,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessNoneGood) { std::string spirv = "OpCopyMemory %1 %2 None\n"; EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemory, {1, 2, 0}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -191,8 +193,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessVolatileGood) { std::string spirv = "OpCopyMemory %1 %2 Volatile\n"; EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemory, {1, 2, 1}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -200,8 +201,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessAligned8Good) { std::string spirv = "OpCopyMemory %1 %2 Aligned 8\n"; EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemory, {1, 2, 2, 8}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -209,8 +209,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessNontemporalGood) { std::string spirv = "OpCopyMemory %1 %2 Nontemporal\n"; EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemory, {1, 2, 4}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -218,8 +217,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessAvGood) { std::string spirv = "OpCopyMemory %1 %2 MakePointerAvailable %3\n"; EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemory, {1, 2, 8, 3}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -227,8 +225,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessVisGood) { std::string spirv = "OpCopyMemory %1 %2 MakePointerVisible %3\n"; EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemory, {1, 2, 16, 3}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -236,8 +233,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessNonPrivateGood) { std::string spirv = "OpCopyMemory %1 %2 NonPrivatePointer\n"; EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemory, {1, 2, 32}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -248,8 +244,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemoryAccessMixedGood) { "MakePointerVisible|NonPrivatePointer 16 %3 %4\n"; EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemory, {1, 2, 63, 16, 3, 4}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -258,8 +253,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemoryTwoAccessV13Good) { // Note: This will assemble but should not validate for SPIR-V 1.3 EXPECT_THAT(CompiledInstructions(spirv, SPV_ENV_UNIVERSAL_1_3), Eq(MakeInstruction(spv::Op::OpCopyMemory, {1, 2, 1, 1}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -267,8 +261,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemoryTwoAccessV14Good) { std::string spirv = "OpCopyMemory %1 %2 Volatile Volatile\n"; EXPECT_THAT(CompiledInstructions(spirv, SPV_ENV_UNIVERSAL_1_4), Eq(MakeInstruction(spv::Op::OpCopyMemory, {1, 2, 1, 1}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -280,8 +273,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemoryTwoAccessMixedV14Good) { EXPECT_THAT( CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemory, {1, 2, 21, 3, 42, 16, 4}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -291,8 +283,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemorySizedNoMemAccessGood) { std::string spirv = "OpCopyMemorySized %1 %2 %3\n"; EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemorySized, {1, 2, 3}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -313,8 +304,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessNoneGood) { std::string spirv = "OpCopyMemorySized %1 %2 %3 None\n"; EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemorySized, {1, 2, 3, 0}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -322,8 +312,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessVolatileGood) { std::string spirv = "OpCopyMemorySized %1 %2 %3 Volatile\n"; EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemorySized, {1, 2, 3, 1}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -331,8 +320,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessAligned8Good) { std::string spirv = "OpCopyMemorySized %1 %2 %3 Aligned 8\n"; EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemorySized, {1, 2, 3, 2, 8}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -340,8 +328,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessNontemporalGood) { std::string spirv = "OpCopyMemorySized %1 %2 %3 Nontemporal\n"; EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemorySized, {1, 2, 3, 4}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -349,8 +336,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessAvGood) { std::string spirv = "OpCopyMemorySized %1 %2 %3 MakePointerAvailable %4\n"; EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemorySized, {1, 2, 3, 8, 4}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -359,8 +345,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessVisGood) { EXPECT_THAT( CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemorySized, {1, 2, 3, 16, 4}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -368,8 +353,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessNonPrivateGood) { std::string spirv = "OpCopyMemorySized %1 %2 %3 NonPrivatePointer\n"; EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemorySized, {1, 2, 3, 32}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -381,8 +365,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemorySizedAccessMixedGood) { EXPECT_THAT( CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemorySized, {1, 2, 3, 63, 16, 4, 5}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -391,8 +374,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemorySizedTwoAccessV13Good) { // Note: This will assemble but should not validate for SPIR-V 1.3 EXPECT_THAT(CompiledInstructions(spirv, SPV_ENV_UNIVERSAL_1_3), Eq(MakeInstruction(spv::Op::OpCopyMemorySized, {1, 2, 3, 1, 1}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -400,8 +382,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemorySizedTwoAccessV14Good) { std::string spirv = "OpCopyMemorySized %1 %2 %3 Volatile Volatile\n"; EXPECT_THAT(CompiledInstructions(spirv, SPV_ENV_UNIVERSAL_1_4), Eq(MakeInstruction(spv::Op::OpCopyMemorySized, {1, 2, 3, 1, 1}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } @@ -413,8 +394,7 @@ TEST_F(MemoryRoundTripTest, OpCopyMemorySizedTwoAccessMixedV14Good) { EXPECT_THAT(CompiledInstructions(spirv), Eq(MakeInstruction(spv::Op::OpCopyMemorySized, {1, 2, 3, 21, 4, 42, 16, 5}))); - std::string disassembly = - EncodeAndDecodeSuccessfully(spirv, SPV_BINARY_TO_TEXT_OPTION_NONE); + std::string disassembly = EncodeAndDecodeSuccessfully(spirv); EXPECT_THAT(disassembly, Eq(spirv)); } diff --git a/tools/dis/dis.cpp b/tools/dis/dis.cpp index aacd37f079..b8ce3e36ec 100644 --- a/tools/dis/dis.cpp +++ b/tools/dis/dis.cpp @@ -35,42 +35,51 @@ or if the filename is "-", then the binary is read from standard input. Options: - -h, --help Print this help. - --version Display disassembler version information. + -h, --help Print this help. + --version Display disassembler version information. - -o Set the output filename. - Output goes to standard output if this option is - not specified, or if the filename is "-". + -o Set the output filename. + Output goes to standard output if this option is + not specified, or if the filename is "-". - --color Force color output. The default when printing to a terminal. - Overrides a previous --no-color option. - --no-color Don't print in color. Overrides a previous --color option. - The default when output goes to something other than a - terminal (e.g. a file, a pipe, or a shell redirection). + --color Force color output. The default when printing to a terminal. + Overrides a previous --no-color option. + --no-color Don't print in color. Overrides a previous --color option. + The default when output goes to something other than a + terminal (e.g. a file, a pipe, or a shell redirection). - --no-indent Don't indent instructions. + --no-indent Don't indent instructions. - --no-header Don't output the header as leading comments. + --no-header Don't output the header as leading comments. - --raw-id Show raw Id values instead of friendly names. + --raw-id Show raw Id values instead of friendly names. - --offsets Show byte offsets for each instruction. + --nested-indent Indentation is adjusted to indicate nesting in structured + control flow. - --comment Add comments to make reading easier + --reorder-blocks Reorder blocks to match the structured control flow of SPIR-V. + With this option, the order of instructions will no longer + match the input binary, but the result will be more readable. + + --offsets Show byte offsets for each instruction. + + --comment Add comments to make reading easier )"; // clang-format off -FLAG_SHORT_bool (h, /* default_value= */ false, /* required= */ false); -FLAG_SHORT_string(o, /* default_value= */ "-", /* required= */ false); -FLAG_LONG_bool (help, /* default_value= */ false, /* required= */false); -FLAG_LONG_bool (version, /* default_value= */ false, /* required= */ false); -FLAG_LONG_bool (color, /* default_value= */ false, /* required= */ false); -FLAG_LONG_bool (no_color, /* default_value= */ false, /* required= */ false); -FLAG_LONG_bool (no_indent, /* default_value= */ false, /* required= */ false); -FLAG_LONG_bool (no_header, /* default_value= */ false, /* required= */ false); -FLAG_LONG_bool (raw_id, /* default_value= */ false, /* required= */ false); -FLAG_LONG_bool (offsets, /* default_value= */ false, /* required= */ false); -FLAG_LONG_bool (comment, /* default_value= */ false, /* required= */ false); +FLAG_SHORT_bool (h, /* default_value= */ false, /* required= */ false); +FLAG_SHORT_string(o, /* default_value= */ "-", /* required= */ false); +FLAG_LONG_bool (help, /* default_value= */ false, /* required= */false); +FLAG_LONG_bool (version, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool (color, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool (no_color, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool (no_indent, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool (no_header, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool (raw_id, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool (nested_indent, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool (reorder_blocks, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool (offsets, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool (comment, /* default_value= */ false, /* required= */ false); // clang-format on static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5; @@ -120,6 +129,12 @@ int main(int, const char** argv) { if (!flags::raw_id.value()) options |= SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES; + if (flags::nested_indent.value()) + options |= SPV_BINARY_TO_TEXT_OPTION_NESTED_INDENT; + + if (flags::reorder_blocks.value()) + options |= SPV_BINARY_TO_TEXT_OPTION_REORDER_BLOCKS; + if (flags::comment.value()) options |= SPV_BINARY_TO_TEXT_OPTION_COMMENT; if (flags::o.value() == "-") { From 6c8b460eb1945b4d6361b930385b8510c3262686 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 17 Jun 2024 16:08:55 +0200 Subject: [PATCH 458/523] misc: remove encoding parameter (#5710) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Those scripts are running on Python2.7 if build with the NDK tools. Under python2.7, io.open will load as "utf-8" since we give the encoding option, and return a "unicode" string. Under Python3, the open() function will return a UTF-8 string. This means the XMLParser needs to have a different 'encoding' option depending on the python version. For some reason I don't know, the XMLParser still fails if we use 'unicode' under Python2.7. But converting the unicode string to utf-8 does work. Signed-off-by: Nathan Gauër --- utils/generate_registry_tables.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/utils/generate_registry_tables.py b/utils/generate_registry_tables.py index 69628faada..2564f357bf 100755 --- a/utils/generate_registry_tables.py +++ b/utils/generate_registry_tables.py @@ -17,6 +17,7 @@ import errno import io import os.path +import platform from xml.etree.ElementTree import XML, XMLParser, TreeBuilder @@ -80,8 +81,15 @@ def main(): args = parser.parse_args() with io.open(args.xml, encoding='utf-8') as xml_in: + # Python3 default str to UTF-8. But Python2.7 (in case of NDK build, + # don't be fooled by the shebang) is returning a unicode string. + # So depending of the version, we need to make sure the correct + # encoding is used. + content = xml_in.read() + if platform.python_version_tuple()[0] == '2': + content = content.encode('utf-8') parser = XMLParser(target=TreeBuilder(), encoding='utf-8') - registry = XML(xml_in.read(), parser=parser) + registry = XML(content, parser=parser) mkdir_p(os.path.dirname(args.generator_output)) with open(args.generator_output, 'w') as f: From 7bf2d0275e480852abfccc5ff9a4cabd388286b2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 11:18:20 -0400 Subject: [PATCH 459/523] roll deps (#5685) * Roll external/re2/ 917047f36..4a8cee3dd (27 commits) https://github.com/google/re2/compare/917047f3606d...4a8cee3dd3c3 Created with: roll-dep external/re2 * Roll external/googletest/ 9b4993ca7..1d17ea141 (3 commits) https://github.com/google/googletest/compare/9b4993ca7d12...1d17ea141d2c Created with: roll-dep external/googletest * Roll external/abseil_cpp/ 1a31b81c0..1315c900e (91 commits) https://github.com/abseil/abseil-cpp/compare/1a31b81c0a46...1315c900e1dd Created with: roll-dep external/abseil_cpp * Roll external/spirv-headers/ eb49bb7b1..2acb319af (1 commit) https://github.com/KhronosGroup/SPIRV-Headers/compare/eb49bb7b1136...2acb319af38d Created with: roll-dep external/spirv-headers * Roll external/effcee/ 19b4aa87a..d74d33d93 (4 commits) https://github.com/google/effcee/compare/19b4aa87af25...d74d33d93043 Created with: roll-dep external/effcee * Update module.bazel to find re2 --------- Co-authored-by: GitHub Actions[bot] <> Co-authored-by: Steven Perron --- DEPS | 10 +++++----- MODULE.bazel | 7 +++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/DEPS b/DEPS index 5c5b2ee26c..6d7234404d 100644 --- a/DEPS +++ b/DEPS @@ -3,18 +3,18 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': '1a31b81c0a467c1c8e229b9fc172a4eb0db5bd85', + 'abseil_revision': '1315c900e1ddbb08a23e06eeb9a06450052ccb5e', - 'effcee_revision': '19b4aa87af25cb4ee779a071409732f34bfc305c', + 'effcee_revision': 'd74d33d93043952a99ae7cd7458baf6bc8df1da0', - 'googletest_revision': '9b4993ca7d1279dec5c5d41ba327cb11a77bdc00', + 'googletest_revision': '1d17ea141d2c11b8917d2c7d029f1c4e2b9769b2', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '917047f3606d3ba9e2de0d383c3cd80c94ed732c', + 're2_revision': '4a8cee3dd3c3d81b6fe8b867811e193d5819df07', - 'spirv_headers_revision': 'eb49bb7b1136298b77945c52b4bbbc433f7885de', + 'spirv_headers_revision': '2acb319af38d43be3ea76bfabf3998e5281d8d12', } deps = { diff --git a/MODULE.bazel b/MODULE.bazel index c36fe456fd..86db79fbc5 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -5,3 +5,10 @@ local_path_override( module_name = "googletest", path = "external/googletest", ) + +bazel_dep(name = "re2", dev_dependency = True) +local_path_override( + module_name = "re2", + path = "external/re2", +) + From 80a1aed219af368c348d27a8084c7e58867c80c5 Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Tue, 18 Jun 2024 10:52:50 -0700 Subject: [PATCH 460/523] Use bzlmod for effcee (#5707) --- BUILD.bazel | 9 ++++----- MODULE.bazel | 7 +++---- WORKSPACE | 10 ---------- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index 48a688e7cd..a1b21d17e1 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -498,8 +498,7 @@ cc_library( ":spirv_tools_internal", ":spirv_tools_link", ":test_lib", - "@com_google_effcee//:effcee", - "@com_googlesource_code_re2//:re2", + "@effcee//:effcee", ], ) @@ -552,7 +551,7 @@ cc_library( deps = [ ":spirv_tools_internal", ":spirv_tools_opt_internal", - "@com_google_effcee//:effcee", + "@effcee//:effcee", "@googletest//:gtest", ], ) @@ -568,7 +567,7 @@ cc_library( ":spirv_tools_internal", ":spirv_tools_opt_internal", ":test_lib", - "@com_google_effcee//:effcee", + "@effcee//:effcee", "@googletest//:gtest", "@googletest//:gtest_main", ], @@ -601,7 +600,7 @@ cc_library( ":opt_test_lib", ":spirv_tools", ":spirv_tools_opt_internal", - "@com_google_effcee//:effcee", + "@effcee//:effcee", "@googletest//:gtest", "@googletest//:gtest_main", ], diff --git a/MODULE.bazel b/MODULE.bazel index 86db79fbc5..4e3b54f0cb 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -6,9 +6,8 @@ local_path_override( path = "external/googletest", ) -bazel_dep(name = "re2", dev_dependency = True) +bazel_dep(name = "effcee", dev_dependency = True) local_path_override( - module_name = "re2", - path = "external/re2", + module_name = "effcee", + path = "external/effcee", ) - diff --git a/WORKSPACE b/WORKSPACE index 6e780594c3..054960aa06 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -3,16 +3,6 @@ local_repository( path = "external/spirv-headers", ) -local_repository( - name = "com_googlesource_code_re2", - path = "external/re2", -) - -local_repository( - name = "com_google_effcee", - path = "external/effcee", -) - local_repository( name = "abseil-cpp", path = "external/abseil_cpp", From 581279dedd59d8353322fc2d61be07ccdcad0f13 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 19 Jun 2024 13:17:05 -0400 Subject: [PATCH 461/523] [OPT] Zero-extend unsigned 16-bit integers when bitcasting (#5714) The folding rule `BitCastScalarOrVector` was incorrectly handling bitcasting to unsigned integers smaller than 32-bits. It was simply copying the entire 32-bit word containing the integer. This conflicts with the requirement in section 2.2.1 of the SPIR-V spec which states that unsigned numeric types with a bit width less than 32-bits must have the high-order bits set to 0. This change include a refactor of the bit extension code to be able to test it better, and to use it in multiple files. Fixes https://github.com/microsoft/DirectXShaderCompiler/issues/6319. --- source/opt/const_folding_rules.cpp | 61 ++----------------- source/opt/constants.cpp | 22 +++++++ source/opt/constants.h | 5 ++ ...ld_spec_constant_op_and_composite_pass.cpp | 13 +--- source/opt/folding_rules.cpp | 10 ++- source/util/bitutils.h | 25 ++++++++ test/opt/fold_test.cpp | 6 +- test/util/bitutils_test.cpp | 40 ++++++++++++ 8 files changed, 108 insertions(+), 74 deletions(-) diff --git a/source/opt/const_folding_rules.cpp b/source/opt/const_folding_rules.cpp index 17900af245..a5d4cbe755 100644 --- a/source/opt/const_folding_rules.cpp +++ b/source/opt/const_folding_rules.cpp @@ -21,59 +21,6 @@ namespace opt { namespace { constexpr uint32_t kExtractCompositeIdInIdx = 0; -// Returns the value obtained by extracting the |number_of_bits| least -// significant bits from |value|, and sign-extending it to 64-bits. -uint64_t SignExtendValue(uint64_t value, uint32_t number_of_bits) { - if (number_of_bits == 64) return value; - - uint64_t mask_for_sign_bit = 1ull << (number_of_bits - 1); - uint64_t mask_for_significant_bits = (mask_for_sign_bit << 1) - 1ull; - if (value & mask_for_sign_bit) { - // Set upper bits to 1 - value |= ~mask_for_significant_bits; - } else { - // Clear the upper bits - value &= mask_for_significant_bits; - } - return value; -} - -// Returns the value obtained by extracting the |number_of_bits| least -// significant bits from |value|, and zero-extending it to 64-bits. -uint64_t ZeroExtendValue(uint64_t value, uint32_t number_of_bits) { - if (number_of_bits == 64) return value; - - uint64_t mask_for_first_bit_to_clear = 1ull << (number_of_bits); - uint64_t mask_for_bits_to_keep = mask_for_first_bit_to_clear - 1; - value &= mask_for_bits_to_keep; - return value; -} - -// Returns a constant whose value is `value` and type is `type`. This constant -// will be generated by `const_mgr`. The type must be a scalar integer type. -const analysis::Constant* GenerateIntegerConstant( - const analysis::Integer* integer_type, uint64_t result, - analysis::ConstantManager* const_mgr) { - assert(integer_type != nullptr); - - std::vector words; - if (integer_type->width() == 64) { - // In the 64-bit case, two words are needed to represent the value. - words = {static_cast(result), - static_cast(result >> 32)}; - } else { - // In all other cases, only a single word is needed. - assert(integer_type->width() <= 32); - if (integer_type->IsSigned()) { - result = SignExtendValue(result, integer_type->width()); - } else { - result = ZeroExtendValue(result, integer_type->width()); - } - words = {static_cast(result)}; - } - return const_mgr->GetConstant(integer_type, words); -} - // Returns a constants with the value NaN of the given type. Only works for // 32-bit and 64-bit float point types. Returns |nullptr| if an error occurs. const analysis::Constant* GetNan(const analysis::Type* type, @@ -1730,7 +1677,7 @@ BinaryScalarFoldingRule FoldBinaryIntegerOperation(uint64_t (*op)(uint64_t, uint64_t result = op(ia, ib); const analysis::Constant* result_constant = - GenerateIntegerConstant(integer_type, result, const_mgr); + const_mgr->GenerateIntegerConstant(integer_type, result); return result_constant; }; } @@ -1745,7 +1692,7 @@ const analysis::Constant* FoldScalarSConvert( const analysis::Integer* integer_type = result_type->AsInteger(); assert(integer_type && "The result type of an SConvert"); int64_t value = a->GetSignExtendedValue(); - return GenerateIntegerConstant(integer_type, value, const_mgr); + return const_mgr->GenerateIntegerConstant(integer_type, value); } // A scalar folding rule that folds OpUConvert. @@ -1762,8 +1709,8 @@ const analysis::Constant* FoldScalarUConvert( // If the operand was an unsigned value with less than 32-bit, it would have // been sign extended earlier, and we need to clear those bits. auto* operand_type = a->type()->AsInteger(); - value = ZeroExtendValue(value, operand_type->width()); - return GenerateIntegerConstant(integer_type, value, const_mgr); + value = utils::ClearHighBits(value, 64 - operand_type->width()); + return const_mgr->GenerateIntegerConstant(integer_type, value); } } // namespace diff --git a/source/opt/constants.cpp b/source/opt/constants.cpp index 6eebbb572a..7dc02deaa4 100644 --- a/source/opt/constants.cpp +++ b/source/opt/constants.cpp @@ -525,6 +525,28 @@ uint32_t ConstantManager::GetNullConstId(const Type* type) { return GetDefiningInstruction(c)->result_id(); } +const Constant* ConstantManager::GenerateIntegerConstant( + const analysis::Integer* integer_type, uint64_t result) { + assert(integer_type != nullptr); + + std::vector words; + if (integer_type->width() == 64) { + // In the 64-bit case, two words are needed to represent the value. + words = {static_cast(result), + static_cast(result >> 32)}; + } else { + // In all other cases, only a single word is needed. + assert(integer_type->width() <= 32); + if (integer_type->IsSigned()) { + result = utils::SignExtendValue(result, integer_type->width()); + } else { + result = utils::ZeroExtendValue(result, integer_type->width()); + } + words = {static_cast(result)}; + } + return GetConstant(integer_type, words); +} + std::vector Constant::GetVectorComponents( analysis::ConstantManager* const_mgr) const { std::vector components; diff --git a/source/opt/constants.h b/source/opt/constants.h index ae8dc6259d..534afa6f53 100644 --- a/source/opt/constants.h +++ b/source/opt/constants.h @@ -671,6 +671,11 @@ class ConstantManager { // Returns the id of a OpConstantNull with type of |type|. uint32_t GetNullConstId(const Type* type); + // Returns a constant whose value is `value` and type is `type`. This constant + // will be generated by `const_mgr`. The type must be a scalar integer type. + const Constant* GenerateIntegerConstant(const analysis::Integer* integer_type, + uint64_t result); + private: // Creates a Constant instance with the given type and a vector of constant // defining words. Returns a unique pointer to the created Constant instance 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 c568027d2a..ddfe59f752 100644 --- a/source/opt/fold_spec_constant_op_and_composite_pass.cpp +++ b/source/opt/fold_spec_constant_op_and_composite_pass.cpp @@ -247,18 +247,7 @@ utils::SmallVector EncodeIntegerAsWords(const analysis::Type& type, // Truncate first_word if the |type| has width less than uint32. if (bit_width < bits_per_word) { - const uint32_t num_high_bits_to_mask = bits_per_word - bit_width; - const bool is_negative_after_truncation = - result_type_signed && - utils::IsBitAtPositionSet(first_word, bit_width - 1); - - if (is_negative_after_truncation) { - // Truncate and sign-extend |first_word|. No padding words will be - // added and |pad_value| can be left as-is. - first_word = utils::SetHighBits(first_word, num_high_bits_to_mask); - } else { - first_word = utils::ClearHighBits(first_word, num_high_bits_to_mask); - } + first_word = utils::SignExtendValue(first_word, bit_width); } utils::SmallVector words = {first_word}; diff --git a/source/opt/folding_rules.cpp b/source/opt/folding_rules.cpp index 24979671f2..6def9c47fb 100644 --- a/source/opt/folding_rules.cpp +++ b/source/opt/folding_rules.cpp @@ -180,8 +180,14 @@ std::vector GetWordsFromNumericScalarOrVectorConstant( const analysis::Constant* ConvertWordsToNumericScalarOrVectorConstant( analysis::ConstantManager* const_mgr, const std::vector& words, const analysis::Type* type) { - if (type->AsInteger() || type->AsFloat()) - return const_mgr->GetConstant(type, words); + const spvtools::opt::analysis::Integer* int_type = type->AsInteger(); + + if (int_type && int_type->width() <= 32) { + assert(words.size() == 1); + return const_mgr->GenerateIntegerConstant(int_type, words[0]); + } + + if (int_type || type->AsFloat()) return const_mgr->GetConstant(type, words); if (const auto* vec_type = type->AsVector()) return const_mgr->GetNumericVectorConstantWithWords(vec_type, words); return nullptr; diff --git a/source/util/bitutils.h b/source/util/bitutils.h index 9ced2f9621..a121dc356b 100644 --- a/source/util/bitutils.h +++ b/source/util/bitutils.h @@ -181,6 +181,31 @@ T ClearHighBits(T word, size_t num_bits_to_set) { false); } +// Returns the value obtained by extracting the |number_of_bits| least +// significant bits from |value|, and sign-extending it to 64-bits. +template +T SignExtendValue(T value, uint32_t number_of_bits) { + const uint32_t bit_width = sizeof(value) * 8; + if (number_of_bits == bit_width) return value; + + bool is_negative = utils::IsBitAtPositionSet(value, number_of_bits - 1); + if (is_negative) { + value = utils::SetHighBits(value, bit_width - number_of_bits); + } else { + value = utils::ClearHighBits(value, bit_width - number_of_bits); + } + return value; +} + +// Returns the value obtained by extracting the |number_of_bits| least +// significant bits from |value|, and zero-extending it to 64-bits. +template +T ZeroExtendValue(T value, uint32_t number_of_bits) { + const uint32_t bit_width = sizeof(value) * 8; + if (number_of_bits == bit_width) return value; + return utils::ClearHighBits(value, bit_width - number_of_bits); +} + } // namespace utils } // namespace spvtools diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index 35828ab22f..cb14b94fce 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -924,7 +924,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "%2 = OpBitcast %ushort %short_0xBC00\n" + "OpReturn\n" + "OpFunctionEnd", - 2, 0xFFFFBC00), + 2, 0xBC00), // Test case 53: Bit-cast half 1 to ushort InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + @@ -940,7 +940,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "%2 = OpBitcast %short %ushort_0xBC00\n" + "OpReturn\n" + "OpFunctionEnd", - 2, 0xBC00), + 2, 0xFFFFBC00), // Test case 55: Bit-cast short 0xBC00 to short InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + @@ -996,7 +996,7 @@ INSTANTIATE_TEST_SUITE_P(TestCase, IntegerInstructionFoldingTest, "%2 = OpBitcast %ubyte %byte_n1\n" + "OpReturn\n" + "OpFunctionEnd", - 2, 0xFFFFFFFF), + 2, 0xFF), // Test case 62: Negate 2. InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + diff --git a/test/util/bitutils_test.cpp b/test/util/bitutils_test.cpp index 3be7ed2691..aea789766a 100644 --- a/test/util/bitutils_test.cpp +++ b/test/util/bitutils_test.cpp @@ -188,6 +188,46 @@ TEST(BitUtilsTest, IsBitSetAtPositionAll) { EXPECT_TRUE(IsBitAtPositionSet(max_u64, i)); } } + +struct ExtendedValueTestCase { + uint32_t input; + uint32_t bit_width; + uint32_t expected_result; +}; + +using SignExtendedValueTest = ::testing::TestWithParam; + +TEST_P(SignExtendedValueTest, SignExtendValue) { + const auto& tc = GetParam(); + auto result = SignExtendValue(tc.input, tc.bit_width); + EXPECT_EQ(result, tc.expected_result); +} +INSTANTIATE_TEST_SUITE_P( + SignExtendValue, SignExtendedValueTest, + ::testing::Values(ExtendedValueTestCase{1, 1, 0xFFFFFFFF}, + ExtendedValueTestCase{1, 2, 0x1}, + ExtendedValueTestCase{2, 1, 0x0}, + ExtendedValueTestCase{0x8, 4, 0xFFFFFFF8}, + ExtendedValueTestCase{0x8765, 16, 0xFFFF8765}, + ExtendedValueTestCase{0x7765, 16, 0x7765}, + ExtendedValueTestCase{0xDEADBEEF, 32, 0xDEADBEEF})); + +using ZeroExtendedValueTest = ::testing::TestWithParam; + +TEST_P(ZeroExtendedValueTest, ZeroExtendValue) { + const auto& tc = GetParam(); + auto result = ZeroExtendValue(tc.input, tc.bit_width); + EXPECT_EQ(result, tc.expected_result); +} + +INSTANTIATE_TEST_SUITE_P( + ZeroExtendValue, ZeroExtendedValueTest, + ::testing::Values(ExtendedValueTestCase{1, 1, 0x1}, + ExtendedValueTestCase{1, 2, 0x1}, + ExtendedValueTestCase{2, 1, 0x0}, + ExtendedValueTestCase{0x8, 4, 0x8}, + ExtendedValueTestCase{0xFF8765, 16, 0x8765}, + ExtendedValueTestCase{0xDEADBEEF, 32, 0xDEADBEEF})); } // namespace } // namespace utils } // namespace spvtools From 0cfe9e7219148716dfd30b37f4d21753f098707a Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Thu, 20 Jun 2024 10:29:42 -0400 Subject: [PATCH 462/523] Prepare release v2024.3 (#5719) --- CHANGES | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGES b/CHANGES index 102703a87e..36a2290939 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,19 @@ Revision history for SPIRV-Tools +v2024.3 2024-06-20 + - General + - Optimizer + - Do not fold mul and adds to generate fmas (#5682) + - add OpExtInst forward ref fixup pass (#5708) + - Validator + - Separate Location check for tess patch (#5654) + - Validate MemoryAccessMask of OpCooperativeMatrixStoreKHR (#5668) + - OpSampledImage extra validation (#5695) + - add support for OpExtInstWithForwardRefs (#5698)A + - Disassembler + - add decorations to comments (#5675) + - Add --nested-indent and --reorder-blocks (#5671) + v2024.2 2024-04-22 - General - Add SPIRV_TOOLS_EXPORT to public C++ API (#5591) From b9d8114695de81ae3ea6f93e391156a2f5c13f4c Mon Sep 17 00:00:00 2001 From: Natalie Chouinard Date: Mon, 24 Jun 2024 14:17:34 -0400 Subject: [PATCH 463/523] Add re2 dep back to Bazel build (#5721) This explicit dep was removed in #5707 but it is still used by the test library. Not sure why the Bazel build didn't catch the indirect dependence on another module but it is causing build failures downstream. --- BUILD.bazel | 1 + MODULE.bazel | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/BUILD.bazel b/BUILD.bazel index a1b21d17e1..4becf281ec 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -499,6 +499,7 @@ cc_library( ":spirv_tools_link", ":test_lib", "@effcee//:effcee", + "@re2//:re2", ], ) diff --git a/MODULE.bazel b/MODULE.bazel index 4e3b54f0cb..e11286f345 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -6,6 +6,12 @@ local_path_override( path = "external/googletest", ) +bazel_dep(name = "re2", dev_dependency = True) +local_path_override( + module_name = "re2", + path = "external/re2", +) + bazel_dep(name = "effcee", dev_dependency = True) local_path_override( module_name = "effcee", From 64d37e2811a794f614bc569338afa47dbdfefa0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Tue, 25 Jun 2024 12:08:28 +0200 Subject: [PATCH 464/523] [NFC] Fix potential buffer overflow (#5715) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixing a clusterfuzz finding. If the given binary has debug instruction which contained a badly formatted ANSI escape sequence, the iteration could go beyond the string length. Signed-off-by: Nathan Gauër --- source/disassemble.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/disassemble.cpp b/source/disassemble.cpp index aa20fab65e..0add260091 100644 --- a/source/disassemble.cpp +++ b/source/disassemble.cpp @@ -605,7 +605,7 @@ uint32_t GetLineLengthWithoutColor(const std::string line) { if (line[i] == '\x1b') { do { ++i; - } while (line[i] != 'm'); + } while (i < line.size() && line[i] != 'm'); continue; } From ca004da9f9c7fa7ed536709823bd604fab3cd7da Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 26 Jun 2024 08:00:29 -0400 Subject: [PATCH 465/523] Add knowledge of cooperative matrices (#5720) * Add knowledge of cooperative matrices Some optimizations are not aware of cooperative matrices, and either do nothing or assert. This commits fixes that up. * Add int tests, and a handle a couple more cases. * Add float tests, and a handle a couple more cases. * Add NV coop matrix as well. --- source/opt/aggressive_dead_code_elim_pass.cpp | 4 +- source/opt/folding_rules.cpp | 76 ++++++++++++ .../opt/local_access_chain_convert_pass.cpp | 4 +- source/opt/local_single_block_elim_pass.cpp | 4 +- source/opt/local_single_store_elim_pass.cpp | 4 +- source/opt/mem_pass.cpp | 2 + test/opt/fold_test.cpp | 112 ++++++++++++++++++ 7 files changed, 201 insertions(+), 5 deletions(-) diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp index 4737da5f9c..44432399ca 100644 --- a/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/source/opt/aggressive_dead_code_elim_pass.cpp @@ -1004,7 +1004,9 @@ void AggressiveDCEPass::InitExtensions() { "SPV_NV_bindless_texture", "SPV_EXT_shader_atomic_float_add", "SPV_EXT_fragment_shader_interlock", - "SPV_NV_compute_shader_derivatives" + "SPV_NV_compute_shader_derivatives", + "SPV_NV_cooperative_matrix", + "SPV_KHR_cooperative_matrix" }); // clang-format on } diff --git a/source/opt/folding_rules.cpp b/source/opt/folding_rules.cpp index 6def9c47fb..2ebc385cb4 100644 --- a/source/opt/folding_rules.cpp +++ b/source/opt/folding_rules.cpp @@ -112,6 +112,12 @@ bool IsValidResult(T val) { } } +// Returns true if `type` is a cooperative matrix. +bool IsCooperativeMatrix(const analysis::Type* type) { + return type->kind() == analysis::Type::kCooperativeMatrixKHR || + type->kind() == analysis::Type::kCooperativeMatrixNV; +} + const analysis::Constant* ConstInput( const std::vector& constants) { return constants[0] ? constants[0] : constants[1]; @@ -313,6 +319,11 @@ FoldingRule ReciprocalFDiv() { analysis::ConstantManager* const_mgr = context->get_constant_mgr(); const analysis::Type* type = context->get_type_mgr()->GetType(inst->type_id()); + + if (IsCooperativeMatrix(type)) { + return false; + } + if (!inst->IsFloatingPointFoldingAllowed()) return false; uint32_t width = ElementWidth(type); @@ -394,6 +405,11 @@ FoldingRule MergeNegateMulDivArithmetic() { analysis::ConstantManager* const_mgr = context->get_constant_mgr(); const analysis::Type* type = context->get_type_mgr()->GetType(inst->type_id()); + + if (IsCooperativeMatrix(type)) { + return false; + } + if (HasFloatingPoint(type) && !inst->IsFloatingPointFoldingAllowed()) return false; @@ -455,6 +471,11 @@ FoldingRule MergeNegateAddSubArithmetic() { analysis::ConstantManager* const_mgr = context->get_constant_mgr(); const analysis::Type* type = context->get_type_mgr()->GetType(inst->type_id()); + + if (IsCooperativeMatrix(type)) { + return false; + } + if (HasFloatingPoint(type) && !inst->IsFloatingPointFoldingAllowed()) return false; @@ -686,6 +707,11 @@ FoldingRule MergeMulMulArithmetic() { analysis::ConstantManager* const_mgr = context->get_constant_mgr(); const analysis::Type* type = context->get_type_mgr()->GetType(inst->type_id()); + + if (IsCooperativeMatrix(type)) { + return false; + } + if (HasFloatingPoint(type) && !inst->IsFloatingPointFoldingAllowed()) return false; @@ -740,6 +766,11 @@ FoldingRule MergeMulDivArithmetic() { const analysis::Type* type = context->get_type_mgr()->GetType(inst->type_id()); + + if (IsCooperativeMatrix(type)) { + return false; + } + if (!inst->IsFloatingPointFoldingAllowed()) return false; uint32_t width = ElementWidth(type); @@ -813,6 +844,11 @@ FoldingRule MergeMulNegateArithmetic() { analysis::ConstantManager* const_mgr = context->get_constant_mgr(); const analysis::Type* type = context->get_type_mgr()->GetType(inst->type_id()); + + if (IsCooperativeMatrix(type)) { + return false; + } + bool uses_float = HasFloatingPoint(type); if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; @@ -853,6 +889,11 @@ FoldingRule MergeDivDivArithmetic() { analysis::ConstantManager* const_mgr = context->get_constant_mgr(); const analysis::Type* type = context->get_type_mgr()->GetType(inst->type_id()); + + if (IsCooperativeMatrix(type)) { + return false; + } + if (!inst->IsFloatingPointFoldingAllowed()) return false; uint32_t width = ElementWidth(type); @@ -926,6 +967,11 @@ FoldingRule MergeDivMulArithmetic() { const analysis::Type* type = context->get_type_mgr()->GetType(inst->type_id()); + + if (IsCooperativeMatrix(type)) { + return false; + } + if (!inst->IsFloatingPointFoldingAllowed()) return false; uint32_t width = ElementWidth(type); @@ -1068,6 +1114,11 @@ FoldingRule MergeSubNegateArithmetic() { analysis::ConstantManager* const_mgr = context->get_constant_mgr(); const analysis::Type* type = context->get_type_mgr()->GetType(inst->type_id()); + + if (IsCooperativeMatrix(type)) { + return false; + } + bool uses_float = HasFloatingPoint(type); if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; @@ -1116,6 +1167,11 @@ FoldingRule MergeAddAddArithmetic() { inst->opcode() == spv::Op::OpIAdd); const analysis::Type* type = context->get_type_mgr()->GetType(inst->type_id()); + + if (IsCooperativeMatrix(type)) { + return false; + } + analysis::ConstantManager* const_mgr = context->get_constant_mgr(); bool uses_float = HasFloatingPoint(type); if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; @@ -1164,6 +1220,11 @@ FoldingRule MergeAddSubArithmetic() { inst->opcode() == spv::Op::OpIAdd); const analysis::Type* type = context->get_type_mgr()->GetType(inst->type_id()); + + if (IsCooperativeMatrix(type)) { + return false; + } + analysis::ConstantManager* const_mgr = context->get_constant_mgr(); bool uses_float = HasFloatingPoint(type); if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; @@ -1224,6 +1285,11 @@ FoldingRule MergeSubAddArithmetic() { inst->opcode() == spv::Op::OpISub); const analysis::Type* type = context->get_type_mgr()->GetType(inst->type_id()); + + if (IsCooperativeMatrix(type)) { + return false; + } + analysis::ConstantManager* const_mgr = context->get_constant_mgr(); bool uses_float = HasFloatingPoint(type); if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; @@ -1290,6 +1356,11 @@ FoldingRule MergeSubSubArithmetic() { inst->opcode() == spv::Op::OpISub); const analysis::Type* type = context->get_type_mgr()->GetType(inst->type_id()); + + if (IsCooperativeMatrix(type)) { + return false; + } + analysis::ConstantManager* const_mgr = context->get_constant_mgr(); bool uses_float = HasFloatingPoint(type); if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; @@ -1383,6 +1454,11 @@ FoldingRule MergeGenericAddSubArithmetic() { inst->opcode() == spv::Op::OpIAdd); const analysis::Type* type = context->get_type_mgr()->GetType(inst->type_id()); + + if (IsCooperativeMatrix(type)) { + return false; + } + bool uses_float = HasFloatingPoint(type); if (uses_float && !inst->IsFloatingPointFoldingAllowed()) return false; diff --git a/source/opt/local_access_chain_convert_pass.cpp b/source/opt/local_access_chain_convert_pass.cpp index 7ba75cb7a4..174e7d86da 100644 --- a/source/opt/local_access_chain_convert_pass.cpp +++ b/source/opt/local_access_chain_convert_pass.cpp @@ -428,8 +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_NV_compute_shader_derivatives"}); + "SPV_EXT_fragment_shader_interlock", "SPV_NV_compute_shader_derivatives", + "SPV_NV_cooperative_matrix", "SPV_KHR_cooperative_matrix"}); } bool LocalAccessChainConvertPass::AnyIndexIsOutOfBounds( diff --git a/source/opt/local_single_block_elim_pass.cpp b/source/opt/local_single_block_elim_pass.cpp index d7a9295e84..3a7d25a4ba 100644 --- a/source/opt/local_single_block_elim_pass.cpp +++ b/source/opt/local_single_block_elim_pass.cpp @@ -291,7 +291,9 @@ void LocalSingleBlockLoadStoreElimPass::InitExtensions() { "SPV_NV_bindless_texture", "SPV_EXT_shader_atomic_float_add", "SPV_EXT_fragment_shader_interlock", - "SPV_NV_compute_shader_derivatives"}); + "SPV_NV_compute_shader_derivatives", + "SPV_NV_cooperative_matrix", + "SPV_KHR_cooperative_matrix"}); } } // namespace opt diff --git a/source/opt/local_single_store_elim_pass.cpp b/source/opt/local_single_store_elim_pass.cpp index 7cd6b0eb47..7dfc4adfc8 100644 --- a/source/opt/local_single_store_elim_pass.cpp +++ b/source/opt/local_single_store_elim_pass.cpp @@ -141,7 +141,9 @@ void LocalSingleStoreElimPass::InitExtensionAllowList() { "SPV_NV_bindless_texture", "SPV_EXT_shader_atomic_float_add", "SPV_EXT_fragment_shader_interlock", - "SPV_NV_compute_shader_derivatives"}); + "SPV_NV_compute_shader_derivatives", + "SPV_NV_cooperative_matrix", + "SPV_KHR_cooperative_matrix"}); } bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) { std::vector users; diff --git a/source/opt/mem_pass.cpp b/source/opt/mem_pass.cpp index 9972c4f75f..80ec8da18e 100644 --- a/source/opt/mem_pass.cpp +++ b/source/opt/mem_pass.cpp @@ -43,6 +43,8 @@ bool MemPass::IsBaseTargetType(const Instruction* typeInst) const { case spv::Op::OpTypeSampler: case spv::Op::OpTypeSampledImage: case spv::Op::OpTypePointer: + case spv::Op::OpTypeCooperativeMatrixNV: + case spv::Op::OpTypeCooperativeMatrixKHR: return true; default: break; diff --git a/test/opt/fold_test.cpp b/test/opt/fold_test.cpp index cb14b94fce..e2d9d7cc18 100644 --- a/test/opt/fold_test.cpp +++ b/test/opt/fold_test.cpp @@ -215,6 +215,8 @@ OpCapability Float64 OpCapability Int8 OpCapability Int16 OpCapability Int64 +OpCapability CooperativeMatrixKHR +OpExtension "SPV_KHR_cooperative_matrix" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" @@ -434,6 +436,12 @@ OpName %main "main" %ushort_0xBC00 = OpConstant %ushort 0xBC00 %short_0xBC00 = OpConstant %short 0xBC00 %int_arr_2_undef = OpUndef %int_arr_2 +%int_coop_matrix = OpTypeCooperativeMatrixKHR %int %uint_3 %uint_3 %uint_32 %uint_0 +%undef_int_coop_matrix = OpUndef %int_coop_matrix +%uint_coop_matrix = OpTypeCooperativeMatrixKHR %uint %uint_3 %uint_3 %uint_32 %uint_0 +%undef_uint_coop_matrix = OpUndef %uint_coop_matrix +%float_coop_matrix = OpTypeCooperativeMatrixKHR %float %uint_3 %uint_3 %uint_32 %uint_0 +%undef_float_coop_matrix = OpUndef %float_coop_matrix )"; return header; @@ -4148,6 +4156,62 @@ INSTANTIATE_TEST_SUITE_P(IntegerArithmeticTestCases, GeneralInstructionFoldingTe "%2 = OpSLessThan %bool %long_0 %long_2\n" + "OpReturn\n" + "OpFunctionEnd", + 2, 0), + // Test case 41: Don't fold OpSNegate for cooperative matrices. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSNegate %int_coop_matrix %undef_int_coop_matrix\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 42: Don't fold OpIAdd for cooperative matrices. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpIAdd %int_coop_matrix %undef_int_coop_matrix %undef_int_coop_matrix\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 43: Don't fold OpISub for cooperative matrices. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpISub %int_coop_matrix %undef_int_coop_matrix %undef_int_coop_matrix\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 44: Don't fold OpIMul for cooperative matrices. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpIMul %int_coop_matrix %undef_int_coop_matrix %undef_int_coop_matrix\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 45: Don't fold OpSDiv for cooperative matrices. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpSDiv %int_coop_matrix %undef_int_coop_matrix %undef_int_coop_matrix\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 46: Don't fold OpUDiv for cooperative matrices. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpUDiv %uint_coop_matrix %undef_uint_coop_matrix %undef_uint_coop_matrix\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 47: Don't fold OpMatrixTimesScalar for cooperative matrices. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpMatrixTimesScalar %uint_coop_matrix %undef_uint_coop_matrix %uint_3\n" + + "OpReturn\n" + + "OpFunctionEnd", 2, 0) )); @@ -4689,6 +4753,54 @@ INSTANTIATE_TEST_SUITE_P(FloatRedundantFoldingTest, GeneralInstructionFoldingTes "%2 = OpFDiv %half %half_1 %half_2\n" + "OpReturn\n" + "OpFunctionEnd", + 2, 0), + // Test case 24: Don't fold OpFNegate for cooperative matrices. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpFNegate %float_coop_matrix %undef_float_coop_matrix\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 25: Don't fold OpIAdd for cooperative matrices. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpFAdd %float_coop_matrix %undef_float_coop_matrix %undef_float_coop_matrix\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 26: Don't fold OpISub for cooperative matrices. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpFSub %float_coop_matrix %undef_float_coop_matrix %undef_float_coop_matrix\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 27: Don't fold OpIMul for cooperative matrices. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpFMul %float_coop_matrix %undef_float_coop_matrix %undef_float_coop_matrix\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 28: Don't fold OpSDiv for cooperative matrices. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpFDiv %float_coop_matrix %undef_float_coop_matrix %undef_float_coop_matrix\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 29: Don't fold OpMatrixTimesScalar for cooperative matrices. + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpMatrixTimesScalar %float_coop_matrix %undef_float_coop_matrix %float_3\n" + + "OpReturn\n" + + "OpFunctionEnd", 2, 0) )); From c91d9ec1580dce89b10b0ca6a368800e2deaf1cb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 27 Jun 2024 06:52:47 -0400 Subject: [PATCH 466/523] Roll external/abseil_cpp/ 1315c900e..b4e4b6259 (1 commit) (#5716) * Roll external/re2/ 4a8cee3dd..6144b62be (5 commits) https://github.com/google/re2/compare/4a8cee3dd3c3...6144b62bece5 Created with: roll-dep external/re2 * Roll external/abseil_cpp/ 1315c900e..16452e141 (19 commits) https://github.com/abseil/abseil-cpp/compare/1315c900e1dd...16452e1418c1 Created with: roll-dep external/abseil_cpp --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 6d7234404d..fe5fb57a22 100644 --- a/DEPS +++ b/DEPS @@ -3,7 +3,7 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': '1315c900e1ddbb08a23e06eeb9a06450052ccb5e', + 'abseil_revision': '16452e1418c1c2a8bcf4a99238e190ba901a20a6', 'effcee_revision': 'd74d33d93043952a99ae7cd7458baf6bc8df1da0', @@ -12,7 +12,7 @@ vars = { # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '4a8cee3dd3c3d81b6fe8b867811e193d5819df07', + 're2_revision': '6144b62bece50a4af8bcdb166f04f6ec5af3d6d8', 'spirv_headers_revision': '2acb319af38d43be3ea76bfabf3998e5281d8d12', } From 973e791a9ac122f903c2796349a538b278cbe29b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 13:14:18 +0000 Subject: [PATCH 467/523] Roll external/abseil_cpp/ 16452e141..a7c5f985f (5 commits) (#5722) * Roll external/re2/ 6144b62be..6dcd83d60 (4 commits) https://github.com/google/re2/compare/6144b62bece5...6dcd83d60f79 Created with: roll-dep external/re2 * Roll external/googletest/ 1d17ea141..34ad51b3d (1 commit) https://github.com/google/googletest/compare/1d17ea141d2c...34ad51b3dc4f Created with: roll-dep external/googletest * Roll external/abseil_cpp/ 16452e141..1278ee9bd (11 commits) https://github.com/abseil/abseil-cpp/compare/16452e1418c1...1278ee9bd9bd Created with: roll-dep external/abseil_cpp --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index fe5fb57a22..44c099ce37 100644 --- a/DEPS +++ b/DEPS @@ -3,16 +3,16 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': '16452e1418c1c2a8bcf4a99238e190ba901a20a6', + 'abseil_revision': '1278ee9bd9bd4916181521fac96d6fa1100e38e6', 'effcee_revision': 'd74d33d93043952a99ae7cd7458baf6bc8df1da0', - 'googletest_revision': '1d17ea141d2c11b8917d2c7d029f1c4e2b9769b2', + 'googletest_revision': '34ad51b3dc4f922d8ab622491dd44fc2c39afee9', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', - 're2_revision': '6144b62bece50a4af8bcdb166f04f6ec5af3d6d8', + 're2_revision': '6dcd83d60f7944926bfd308cc13979fc53dd69ca', 'spirv_headers_revision': '2acb319af38d43be3ea76bfabf3998e5281d8d12', } From 3bc9744d0ab9d504971667ae6f4c2889260fcd2e Mon Sep 17 00:00:00 2001 From: Victor Lomuller Date: Wed, 3 Jul 2024 18:18:40 +0100 Subject: [PATCH 468/523] Add FPEncoding operand type. (#5726) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds the optional FPEncoding operand that can be added to OpTypeFloat. At the moment there is no usable operand, so support is limited to adding the entry. Co-authored-by: Kévin Petit Co-authored-by: David Neto --- include/spirv-tools/libspirv.h | 3 +++ source/binary.cpp | 4 ++++ source/disassemble.cpp | 1 + source/name_mapper.cpp | 1 + source/operand.cpp | 5 +++++ source/opt/type_manager.cpp | 1 + source/text_handler.cpp | 3 ++- test/immediate_int_test.cpp | 34 +++++++++++++++++++------------- utils/generate_grammar_tables.py | 2 +- 9 files changed, 38 insertions(+), 16 deletions(-) diff --git a/include/spirv-tools/libspirv.h b/include/spirv-tools/libspirv.h index 162553d891..1a21ccef0f 100644 --- a/include/spirv-tools/libspirv.h +++ b/include/spirv-tools/libspirv.h @@ -175,6 +175,7 @@ typedef enum spv_operand_type_t { SPV_OPERAND_TYPE_KERNEL_ENQ_FLAGS, // SPIR-V Sec 3.29 SPV_OPERAND_TYPE_KERNEL_PROFILING_INFO, // SPIR-V Sec 3.30 SPV_OPERAND_TYPE_CAPABILITY, // SPIR-V Sec 3.31 + SPV_OPERAND_TYPE_FPENCODING, // SPIR-V Sec 3.51 // NOTE: New concrete enum values should be added at the end. @@ -236,6 +237,8 @@ typedef enum spv_operand_type_t { // assemble regardless of where they occur -- literals, IDs, immediate // integers, etc. SPV_OPERAND_TYPE_OPTIONAL_CIV, + // An optional floating point encoding enum + SPV_OPERAND_TYPE_OPTIONAL_FPENCODING, // A variable operand represents zero or more logical operands. // In an instruction definition, this may only appear at the end of the diff --git a/source/binary.cpp b/source/binary.cpp index a39bcf06b3..f0dd070b16 100644 --- a/source/binary.cpp +++ b/source/binary.cpp @@ -671,6 +671,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset, case SPV_OPERAND_TYPE_OVERFLOW_MODES: case SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT: case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT: + case SPV_OPERAND_TYPE_FPENCODING: + case SPV_OPERAND_TYPE_OPTIONAL_FPENCODING: case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS: { // A single word that is a plain enum value. @@ -679,6 +681,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset, parsed_operand.type = SPV_OPERAND_TYPE_ACCESS_QUALIFIER; if (type == SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT) parsed_operand.type = SPV_OPERAND_TYPE_PACKED_VECTOR_FORMAT; + if (type == SPV_OPERAND_TYPE_OPTIONAL_FPENCODING) + parsed_operand.type = SPV_OPERAND_TYPE_FPENCODING; spv_operand_desc entry; if (grammar_.lookupOperand(type, word, &entry)) { diff --git a/source/disassemble.cpp b/source/disassemble.cpp index 0add260091..db99151a90 100644 --- a/source/disassemble.cpp +++ b/source/disassemble.cpp @@ -944,6 +944,7 @@ void InstructionDisassembler::EmitOperand(std::ostream& stream, case SPV_OPERAND_TYPE_FPDENORM_MODE: case SPV_OPERAND_TYPE_FPOPERATION_MODE: case SPV_OPERAND_TYPE_QUANTIZATION_MODES: + case SPV_OPERAND_TYPE_FPENCODING: case SPV_OPERAND_TYPE_OVERFLOW_MODES: { spv_operand_desc entry; if (grammar_.lookupOperand(operand.type, word, &entry)) diff --git a/source/name_mapper.cpp b/source/name_mapper.cpp index b2d0f44525..bc18b7f1b4 100644 --- a/source/name_mapper.cpp +++ b/source/name_mapper.cpp @@ -218,6 +218,7 @@ spv_result_t FriendlyNameMapper::ParseInstruction( } break; case spv::Op::OpTypeFloat: { const auto bit_width = inst.words[2]; + // TODO: Handle optional fpencoding enum once actually used. switch (bit_width) { case 16: SaveName(result_id, "half"); diff --git a/source/operand.cpp b/source/operand.cpp index e15004541b..508a5d1d01 100644 --- a/source/operand.cpp +++ b/source/operand.cpp @@ -252,6 +252,9 @@ const char* spvOperandTypeStr(spv_operand_type_t type) { return "OpenCL.DebugInfo.100 debug operation"; case SPV_OPERAND_TYPE_CLDEBUG100_DEBUG_IMPORTED_ENTITY: return "OpenCL.DebugInfo.100 debug imported entity"; + case SPV_OPERAND_TYPE_FPENCODING: + case SPV_OPERAND_TYPE_OPTIONAL_FPENCODING: + return "FP encoding"; // The next values are for values returned from an instruction, not actually // an operand. So the specific strings don't matter. But let's add them @@ -366,6 +369,7 @@ bool spvOperandIsConcrete(spv_operand_type_t type) { case SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL: case SPV_OPERAND_TYPE_STORE_CACHE_CONTROL: case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS: + case SPV_OPERAND_TYPE_FPENCODING: return true; default: break; @@ -407,6 +411,7 @@ bool spvOperandIsOptional(spv_operand_type_t type) { case SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS: case SPV_OPERAND_TYPE_OPTIONAL_CIV: case SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS: + case SPV_OPERAND_TYPE_OPTIONAL_FPENCODING: return true; default: break; diff --git a/source/opt/type_manager.cpp b/source/opt/type_manager.cpp index 62f93698ff..79648ad497 100644 --- a/source/opt/type_manager.cpp +++ b/source/opt/type_manager.cpp @@ -245,6 +245,7 @@ uint32_t TypeManager::GetTypeInstruction(const Type* type) { {(type->AsInteger()->IsSigned() ? 1u : 0u)}}}); break; case Type::kFloat: + // TODO: Handle FP encoding enums once actually used. typeInst = MakeUnique( context(), spv::Op::OpTypeFloat, 0, id, std::initializer_list{ diff --git a/source/text_handler.cpp b/source/text_handler.cpp index 35c4b83c10..a778c2c143 100644 --- a/source/text_handler.cpp +++ b/source/text_handler.cpp @@ -329,8 +329,9 @@ spv_result_t AssemblyContext::recordTypeDefinition( types_[value] = {pInst->words[2], pInst->words[3] != 0, IdTypeClass::kScalarIntegerType}; } else if (pInst->opcode == spv::Op::OpTypeFloat) { - if (pInst->words.size() != 3) + if ((pInst->words.size() != 3) && (pInst->words.size() != 4)) return diagnostic() << "Invalid OpTypeFloat instruction"; + // TODO(kpet) Do we need to record the FP Encoding here? types_[value] = {pInst->words[2], false, IdTypeClass::kScalarFloatType}; } else { types_[value] = {0, false, IdTypeClass::kOtherType}; diff --git a/test/immediate_int_test.cpp b/test/immediate_int_test.cpp index 8e7a8fd304..44f96e21a4 100644 --- a/test/immediate_int_test.cpp +++ b/test/immediate_int_test.cpp @@ -136,19 +136,25 @@ TEST_F(ImmediateIntTest, IntegerFollowingImmediate) { } // Literal floats after ! are handled correctly. +// Insert OpNop to avoid reading the immediate value as the extra FP encoding +// operand to OpTypeFloat. TEST_F(ImmediateIntTest, FloatFollowingImmediate) { - EXPECT_EQ( - CompiledInstructions("%1 = OpTypeFloat 32\n%2 = OpConstant %1 0.123"), - CompiledInstructions("%1 = OpTypeFloat 32\n!0x0004002b %1 !2 0.123")); - EXPECT_EQ( - CompiledInstructions("%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0.5"), - CompiledInstructions("%1 = OpTypeFloat 32\n!0x0004002b %1 !2 -0.5")); - EXPECT_EQ( - CompiledInstructions("%1 = OpTypeFloat 32\n%2 = OpConstant %1 0.123"), - CompiledInstructions("%1 = OpTypeFloat 32\n!0x0004002b %1 %2 0.123")); - EXPECT_EQ( - CompiledInstructions("%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0.5"), - CompiledInstructions("%1 = OpTypeFloat 32\n!0x0004002b %1 %2 -0.5")); + EXPECT_EQ(CompiledInstructions( + "%1 = OpTypeFloat 32\nOpNop %2 = OpConstant %1 0.123"), + CompiledInstructions( + "%1 = OpTypeFloat 32\nOpNop !0x0004002b %1 !2 0.123")); + EXPECT_EQ(CompiledInstructions( + "%1 = OpTypeFloat 32\nOpNop %2 = OpConstant %1 -0.5"), + CompiledInstructions( + "%1 = OpTypeFloat 32\nOpNop !0x0004002b %1 !2 -0.5")); + EXPECT_EQ(CompiledInstructions( + "%1 = OpTypeFloat 32\nOpNop %2 = OpConstant %1 0.123"), + CompiledInstructions( + "%1 = OpTypeFloat 32\nOpNop !0x0004002b %1 %2 0.123")); + EXPECT_EQ(CompiledInstructions( + "%1 = OpTypeFloat 32\nOpNop %2 = OpConstant %1 -0.5"), + CompiledInstructions( + "%1 = OpTypeFloat 32\nOpNop !0x0004002b %1 %2 -0.5")); EXPECT_EQ(Concatenate({ MakeInstruction(spv::Op::OpTypeInt, {1, 64, 0}), @@ -203,9 +209,9 @@ TEST_F(ImmediateIntTest, InvalidStatement) { TEST_F(ImmediateIntTest, InvalidStatementBetweenValidOnes) { EXPECT_THAT(Subvector(CompileSuccessfully( - "%10 = OpTypeFloat 32 !5 !6 !7 OpEmitVertex"), + "%10 = OpTypeInt 32 0 !5 !6 !7 OpEmitVertex"), kFirstInstruction), - ElementsAre(spvOpcodeMake(3, spv::Op::OpTypeFloat), 1, 32, 5, 6, + ElementsAre(spvOpcodeMake(4, spv::Op::OpTypeInt), 1, 32, 0, 5, 6, 7, spvOpcodeMake(1, spv::Op::OpEmitVertex))); } diff --git a/utils/generate_grammar_tables.py b/utils/generate_grammar_tables.py index 88534ffed4..cb168b6dba 100755 --- a/utils/generate_grammar_tables.py +++ b/utils/generate_grammar_tables.py @@ -540,7 +540,7 @@ def generate_operand_kind_table(enums): # We have a few operand kinds that require their optional counterpart to # exist in the operand info table. - optional_enums = ['ImageOperands', 'AccessQualifier', 'MemoryAccess', 'PackedVectorFormat', 'CooperativeMatrixOperands', 'RawAccessChainOperands'] + optional_enums = ['ImageOperands', 'AccessQualifier', 'MemoryAccess', 'PackedVectorFormat', 'CooperativeMatrixOperands', 'RawAccessChainOperands', 'FPEncoding'] optional_enums = [e for e in enums if e[0] in optional_enums] enums.extend(optional_enums) From 216574bedb80d439c2533d161e7ea7897504bbb6 Mon Sep 17 00:00:00 2001 From: David Neto Date: Thu, 4 Jul 2024 10:28:38 -0400 Subject: [PATCH 469/523] Allow for empty list of enums for an operand (#5727) Insert a placeholder enum that is never valid. This allows compilation to pass on MSVC, which doesn't like creating an array with explicit type elem[] but which has an empty initializer. Bug: crbug.com/351140758 --- utils/generate_grammar_tables.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/utils/generate_grammar_tables.py b/utils/generate_grammar_tables.py index cb168b6dba..ec22087214 100755 --- a/utils/generate_grammar_tables.py +++ b/utils/generate_grammar_tables.py @@ -512,6 +512,10 @@ def functor(k): return (int(k['value'], 16)) name = '{}_{}Entries'.format(PYGEN_VARIABLE_PREFIX, kind) entries = [' {}'.format(generate_enum_operand_kind_entry(e, extension_map)) for e in entries] + if len(entries) == 0: + # Insert a dummy entry. Otherwise the array is empty and compilation + # will fail in MSVC. + entries = [' {"place holder", 0, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(999,0), 0}'] template = ['static const spv_operand_desc_t {name}[] = {{', '{entries}', '}};'] From beabd8b7f4f20b7a25574cce1ee1735d46225f17 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:31:32 +0000 Subject: [PATCH 470/523] Roll external/abseil_cpp/ 1278ee9bd..0d9c2fc76 (2 commits) (#5724) * Roll external/abseil_cpp/ 1278ee9bd..074a32af6 (5 commits) https://github.com/abseil/abseil-cpp/compare/1278ee9bd9bd...074a32af6664 Created with: roll-dep external/abseil_cpp * Roll external/spirv-headers/ 2acb319af..41a8eb27f (1 commit) https://github.com/KhronosGroup/SPIRV-Headers/compare/2acb319af38d...41a8eb27f1a7 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 44c099ce37..d8fba6c64a 100644 --- a/DEPS +++ b/DEPS @@ -3,7 +3,7 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': '1278ee9bd9bd4916181521fac96d6fa1100e38e6', + 'abseil_revision': '074a32af66648c74dd0104e251e44ace5b59f7fa', 'effcee_revision': 'd74d33d93043952a99ae7cd7458baf6bc8df1da0', @@ -14,7 +14,7 @@ vars = { 're2_revision': '6dcd83d60f7944926bfd308cc13979fc53dd69ca', - 'spirv_headers_revision': '2acb319af38d43be3ea76bfabf3998e5281d8d12', + 'spirv_headers_revision': '41a8eb27f1a7554dadfcdd45819954eaa94935e6', } deps = { From 9f2ccaef5f70c32bcd6c911a2b09dbb26106b437 Mon Sep 17 00:00:00 2001 From: David Neto Date: Fri, 5 Jul 2024 18:18:59 -0400 Subject: [PATCH 471/523] kokoro: use Python 3.12 in Linux builds (#5730) Bug: crbug.com/350048185 --- kokoro/scripts/linux/build-docker.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kokoro/scripts/linux/build-docker.sh b/kokoro/scripts/linux/build-docker.sh index e47037d54b..b2c034d6eb 100755 --- a/kokoro/scripts/linux/build-docker.sh +++ b/kokoro/scripts/linux/build-docker.sh @@ -27,6 +27,8 @@ git config --global --add safe.directory $ROOT_DIR . /bin/using.sh # Declare the bash `using` function for configuring toolchains. +using python-3.12 + if [ $COMPILER = "clang" ]; then using clang-10.0.0 elif [ $COMPILER = "gcc" ]; then From 6a5fa5f70a7e0d332850a6ca5e8d0e99a1b40877 Mon Sep 17 00:00:00 2001 From: Sven van Haastregt Date: Tue, 16 Jul 2024 02:10:06 +0200 Subject: [PATCH 472/523] Fix SPRIV -> SPIRV typos (#5735) Fix all occurrences of "spriv" typos (irrespective of case). Signed-off-by: Sven van Haastregt --- source/binary.cpp | 2 +- test/binary_parse_test.cpp | 2 +- test/val/val_misc_test.cpp | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/source/binary.cpp b/source/binary.cpp index f0dd070b16..b9bd7568ad 100644 --- a/source/binary.cpp +++ b/source/binary.cpp @@ -703,7 +703,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset, << ", if you are creating a new source language please use " "value 0 " "(Unknown) and when ready, add your source language to " - "SPRIV-Headers"; + "SPIRV-Headers"; } // Prepare to accept operands to this operand, if needed. spvPushOperandTypes(entry->operandTypes, expected_operands); diff --git a/test/binary_parse_test.cpp b/test/binary_parse_test.cpp index 1a868dbae6..1b8d72ec4a 100644 --- a/test/binary_parse_test.cpp +++ b/test/binary_parse_test.cpp @@ -1157,7 +1157,7 @@ INSTANTIATE_TEST_SUITE_P( {"OpSource !9999 100", "Invalid source language operand: 9999, if you are creating a new " "source language please use value 0 (Unknown) and when ready, add " - "your source language to SPRIV-Headers"}, + "your source language to SPIRV-Headers"}, {"OpEntryPoint !9999", "Invalid execution model operand: 9999"}, {"OpMemoryModel !9999", "Invalid addressing model operand: 9999"}, {"OpMemoryModel Logical !9999", "Invalid memory model operand: 9999"}, diff --git a/test/val/val_misc_test.cpp b/test/val/val_misc_test.cpp index 8c1f11dfe6..6d5897c123 100644 --- a/test/val/val_misc_test.cpp +++ b/test/val/val_misc_test.cpp @@ -84,7 +84,7 @@ OpMemoryModel Logical GLSL450 HasSubstr("Cannot create undefined values with 8- or 16-bit types")); } -const std::string ShaderClockSpriv = R"( +const std::string ShaderClockSpirv = R"( OpCapability Shader OpCapability Int64 OpCapability ShaderClockKHR @@ -103,7 +103,7 @@ OpName %time1 "time1" )"; TEST_F(ValidateMisc, ShaderClockInt64) { - const std::string spirv = ShaderClockSpriv + R"( + const std::string spirv = ShaderClockSpirv + R"( %3 = OpTypeFunction %void %uint = OpTypeInt 32 0 %_ptr_Function_uint = OpTypePointer Function %uint @@ -123,7 +123,7 @@ OpFunctionEnd)"; } TEST_F(ValidateMisc, ShaderClockVec2) { - const std::string spirv = ShaderClockSpriv + R"( + const std::string spirv = ShaderClockSpirv + R"( %3 = OpTypeFunction %void %ulong = OpTypeInt 64 0 %_ptr_Function_ulong = OpTypePointer Function %ulong @@ -145,7 +145,7 @@ OpFunctionEnd)"; } TEST_F(ValidateMisc, ShaderClockInvalidScopeValue) { - const std::string spirv = ShaderClockSpriv + R"( + const std::string spirv = ShaderClockSpirv + R"( %3 = OpTypeFunction %void %ulong = OpTypeInt 64 0 %uint = OpTypeInt 32 0 @@ -166,7 +166,7 @@ OpFunctionEnd)"; } TEST_F(ValidateMisc, ShaderClockSubgroupScope) { - const std::string spirv = ShaderClockSpriv + R"( + const std::string spirv = ShaderClockSpirv + R"( %3 = OpTypeFunction %void %ulong = OpTypeInt 64 0 %uint = OpTypeInt 32 0 @@ -186,7 +186,7 @@ OpFunctionEnd)"; } TEST_F(ValidateMisc, ShaderClockDeviceScope) { - const std::string spirv = ShaderClockSpriv + R"( + const std::string spirv = ShaderClockSpirv + R"( %3 = OpTypeFunction %void %ulong = OpTypeInt 64 0 %uint = OpTypeInt 32 0 @@ -206,7 +206,7 @@ OpFunctionEnd)"; } TEST_F(ValidateMisc, ShaderClockWorkgroupScope) { - const std::string spirv = ShaderClockSpriv + R"( + const std::string spirv = ShaderClockSpirv + R"( %3 = OpTypeFunction %void %ulong = OpTypeInt 64 0 %uint = OpTypeInt 32 0 @@ -228,7 +228,7 @@ OpFunctionEnd)"; } TEST_F(ValidateMisc, VulkanShaderClockWorkgroupScope) { - const std::string spirv = ShaderClockSpriv + R"( + const std::string spirv = ShaderClockSpirv + R"( %3 = OpTypeFunction %void %ulong = OpTypeInt 64 0 %uint = OpTypeInt 32 0 From 257cacfb3e44bf26b1867840d29116e78affdb32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jul 2024 20:48:59 -0400 Subject: [PATCH 473/523] build(deps): bump the github-actions group across 1 directory with 4 updates (#5734) Bumps the github-actions group with 4 updates in the / directory: [actions/checkout](https://github.com/actions/checkout), [lukka/get-cmake](https://github.com/lukka/get-cmake), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [github/codeql-action](https://github.com/github/codeql-action). Updates `actions/checkout` from 4.1.6 to 4.1.7 - [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/a5ac7e51b41094c92402da3b24376905380afc29...692973e3d937129bcbf40652eb9f2f61becf3332) Updates `lukka/get-cmake` from 3.29.4 to 3.30.0 - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/85652a37b177d946c9f4fad0f696b2927ee7754d...983956e4a5edce90f0dfcc38c1543077e668402b) Updates `actions/upload-artifact` from 4.3.3 to 4.3.4 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/65462800fd760344b1a7b4382951275a0abb4808...0b2256b8c012f0828dc542b3febcab082c67f72b) Updates `github/codeql-action` from 3.25.8 to 3.25.12 - [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/2e230e8fe0ad3a14a340ad0815ddb96d599d2aff...4fa2a7953630fd2f3fb380f21be14ede0169dd4f) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: lukka/get-cmake 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-patch 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/ios.yml | 4 ++-- .github/workflows/release.yml | 2 +- .github/workflows/scorecard.yml | 6 +++--- .github/workflows/wasm.yml | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/autoroll.yml b/.github/workflows/autoroll.yml index c5be7f1147..fd255b5cb6 100644 --- a/.github/workflows/autoroll.yml +++ b/.github/workflows/autoroll.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 # 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 b83d3324fd..a8db6addb1 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -18,7 +18,7 @@ jobs: runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: '0' - name: Download dependencies diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 2deead54e7..64f0459878 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -11,8 +11,8 @@ jobs: matrix: os: [ macos-12, macos-13 ] steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - - uses: lukka/get-cmake@85652a37b177d946c9f4fad0f696b2927ee7754d # v3.29.4 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: lukka/get-cmake@983956e4a5edce90f0dfcc38c1543077e668402b # v3.30.0 - name: Download dependencies run: python3 utils/git-sync-deps # NOTE: The MacOS SDK ships universal binaries. CI should reflect this. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 36fdf11eb9..5d327a00f0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: prepare-release-job: runs-on: ubuntu-latest steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - 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 3aa30b6856..f52dcbb068 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -23,7 +23,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: persist-credentials: false @@ -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@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 + uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 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@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # v3.25.8 + uses: github/codeql-action/upload-sarif@4fa2a7953630fd2f3fb380f21be14ede0169dd4f # v3.25.12 with: sarif_file: results.sarif diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 5f0818ca3d..8a81140afd 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: '0' - name: Build web From 7c778973e5eb56ef735bf1a3ad96865eb261997d Mon Sep 17 00:00:00 2001 From: LU-JOHN Date: Tue, 16 Jul 2024 08:20:04 -0500 Subject: [PATCH 474/523] Allow fmt arg to printf to be an array of i8 in non-constant space (#5677) * In spirv-val allow format arg to printf to be an array of i8 in Generic space Signed-off-by: Lu, John * Allow more addr spaces for printf format string Signed-off-by: Lu, John * Update printf format arg testcase Signed-off-by: Lu, John * Apply clang-format Signed-off-by: Lu, John * Reorder code for clarity Signed-off-by: Lu, John * Only allow other addr spaces if extension is seen Signed-off-by: Lu, John * Add test to check printf format with extension Signed-off-by: Lu, John * Add extension correctly Signed-off-by: Lu, John --------- Signed-off-by: Lu, John --- source/val/validate_extensions.cpp | 34 ++++++++++++++++++++++++++---- source/val/validation_state.cpp | 16 ++++++++++++++ source/val/validation_state.h | 1 + test/val/val_ext_inst_test.cpp | 21 ++++++++++++++++++ utils/generate_grammar_tables.py | 1 + 5 files changed, 69 insertions(+), 4 deletions(-) diff --git a/source/val/validate_extensions.cpp b/source/val/validate_extensions.cpp index 05f8ca8b99..49ba236fcb 100644 --- a/source/val/validate_extensions.cpp +++ b/source/val/validate_extensions.cpp @@ -2962,12 +2962,38 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { << "expected operand Format to be a pointer"; } - if (format_storage_class != spv::StorageClass::UniformConstant) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << ext_inst_name() << ": " - << "expected Format storage class to be UniformConstant"; + if (_.HasExtension( + Extension::kSPV_EXT_relaxed_printf_string_address_space)) { + if (format_storage_class != spv::StorageClass::UniformConstant && + // Extension SPV_EXT_relaxed_printf_string_address_space allows + // format strings in Global, Local, Private and Generic address + // spaces + + // Global + format_storage_class != spv::StorageClass::CrossWorkgroup && + // Local + format_storage_class != spv::StorageClass::Workgroup && + // Private + format_storage_class != spv::StorageClass::Function && + // Generic + format_storage_class != spv::StorageClass::Generic) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": " + << "expected Format storage class to be UniformConstant, " + "Crossworkgroup, Workgroup, Function, or Generic"; + } + } else { + if (format_storage_class != spv::StorageClass::UniformConstant) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << ext_inst_name() << ": " + << "expected Format storage class to be UniformConstant"; + } } + // If pointer points to an array, get the type of an element + if (_.IsIntArrayType(format_data_type)) + format_data_type = _.GetComponentType(format_data_type); + if (!_.IsIntScalarType(format_data_type) || _.GetBitWidth(format_data_type) != 8) { return _.diag(SPV_ERROR_INVALID_DATA, inst) diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index b5ed65fc25..1b5954ac54 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -869,6 +869,9 @@ uint32_t ValidationState_t::GetComponentType(uint32_t id) const { case spv::Op::OpTypeBool: return id; + case spv::Op::OpTypeArray: + return inst->word(2); + case spv::Op::OpTypeVector: return inst->word(2); @@ -992,6 +995,19 @@ bool ValidationState_t::IsIntScalarType(uint32_t id) const { return inst && inst->opcode() == spv::Op::OpTypeInt; } +bool ValidationState_t::IsIntArrayType(uint32_t id) const { + const Instruction* inst = FindDef(id); + if (!inst) { + return false; + } + + if (inst->opcode() == spv::Op::OpTypeArray) { + return IsIntScalarType(GetComponentType(id)); + } + + return false; +} + bool ValidationState_t::IsIntVectorType(uint32_t id) const { const Instruction* inst = FindDef(id); if (!inst) { diff --git a/source/val/validation_state.h b/source/val/validation_state.h index 27acdcc2f2..2864755891 100644 --- a/source/val/validation_state.h +++ b/source/val/validation_state.h @@ -606,6 +606,7 @@ class ValidationState_t { bool IsFloatScalarOrVectorType(uint32_t id) const; bool IsFloatMatrixType(uint32_t id) const; bool IsIntScalarType(uint32_t id) const; + bool IsIntArrayType(uint32_t id) const; bool IsIntVectorType(uint32_t id) const; bool IsIntScalarOrVectorType(uint32_t id) const; bool IsUnsignedIntScalarType(uint32_t id) const; diff --git a/test/val/val_ext_inst_test.cpp b/test/val/val_ext_inst_test.cpp index 996b9dabc4..23fd3aacf4 100644 --- a/test/val/val_ext_inst_test.cpp +++ b/test/val/val_ext_inst_test.cpp @@ -447,6 +447,7 @@ OpCapability Matrix %u8arr_uniform_constant = OpVariable %u8arr_ptr_uniform_constant UniformConstant %u8_ptr_uniform_constant = OpTypePointer UniformConstant %u8 %u8_ptr_generic = OpTypePointer Generic %u8 +%u8_ptr_input = OpTypePointer Input %u8 %main = OpFunction %void None %func %main_entry = OpLabel @@ -5269,6 +5270,26 @@ TEST_F(ValidateExtInst, OpenCLStdPrintfFormatNotUniformConstStorageClass) { "be UniformConstant")); } +TEST_F(ValidateExtInst, + OpenCLStdPrintfFormatWithExtensionNotAllowedStorageClass) { + const std::string body = R"( +%format_const = OpAccessChain %u8_ptr_uniform_constant %u8arr_uniform_constant %u32_0 +%format = OpBitcast %u8_ptr_input %format_const +%val1 = OpExtInst %u32 %extinst printf %format %u32_0 %u32_1 +)"; + + const std::string extension = R"( +OpExtension "SPV_EXT_relaxed_printf_string_address_space" +)"; + + CompileSuccessfully(GenerateKernelCode(body, extension)); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpenCL.std printf: expected Format storage class to " + "be UniformConstant, Crossworkgroup, Workgroup, " + "Function, or Generic")); +} + TEST_F(ValidateExtInst, OpenCLStdPrintfFormatNotU8Pointer) { const std::string body = R"( %format = OpAccessChain %u32_ptr_uniform_constant %u32vec8_uniform_constant %u32_0 diff --git a/utils/generate_grammar_tables.py b/utils/generate_grammar_tables.py index ec22087214..fd0bcabba8 100755 --- a/utils/generate_grammar_tables.py +++ b/utils/generate_grammar_tables.py @@ -31,6 +31,7 @@ SPV_AMD_gpu_shader_int16 SPV_AMD_shader_trinary_minmax SPV_KHR_non_semantic_info +SPV_EXT_relaxed_printf_string_address_space """ OUTPUT_LANGUAGE = 'c' From 6248fda376664fd92be5ee04c21d6f2da80eb03f Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 17 Jul 2024 09:22:32 -0400 Subject: [PATCH 475/523] Handle coop matrix in fix storage class (#5729) --- source/opt/fix_storage_class.cpp | 1 + test/opt/fix_storage_class_test.cpp | 37 +++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/source/opt/fix_storage_class.cpp b/source/opt/fix_storage_class.cpp index 564cd1b8a3..6345667f88 100644 --- a/source/opt/fix_storage_class.cpp +++ b/source/opt/fix_storage_class.cpp @@ -312,6 +312,7 @@ uint32_t FixStorageClass::WalkAccessChainType(Instruction* inst, uint32_t id) { case spv::Op::OpTypeRuntimeArray: case spv::Op::OpTypeMatrix: case spv::Op::OpTypeVector: + case spv::Op::OpTypeCooperativeMatrixKHR: id = type_inst->GetSingleWordInOperand(0); break; case spv::Op::OpTypeStruct: { diff --git a/test/opt/fix_storage_class_test.cpp b/test/opt/fix_storage_class_test.cpp index 684e006eca..18afccbe72 100644 --- a/test/opt/fix_storage_class_test.cpp +++ b/test/opt/fix_storage_class_test.cpp @@ -916,6 +916,43 @@ TEST_F(FixStorageClassTest, SupportsU64Index) { SinglePassRunAndMatch(text, false); } +TEST_F(FixStorageClassTest, CorrectlyProcessAccessChainOnCoopMatrix) { + const std::string text = R"(OpCapability CooperativeMatrixKHR +OpCapability Shader +OpExtension "SPV_KHR_cooperative_matrix" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %1 "main" +OpExecutionMode %1 LocalSize 64 1 1 +OpSource HLSL 600 +%int = OpTypeInt 32 1 +%int_0 = OpConstant %int 0 +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_3 = OpConstant %uint 3 +%uint_16 = OpConstant %uint 16 +%uint_4 = OpConstant %uint 4 +%9 = OpTypeCooperativeMatrixKHR %int %uint_3 %uint_16 %uint_4 %uint_0 +%void = OpTypeVoid +%11 = OpTypeFunction %void +%_struct_12 = OpTypeStruct %9 +%_ptr_Function__struct_12 = OpTypePointer Function %_struct_12 +%_ptr_Function_9 = OpTypePointer Function %9 +%_ptr_Function_int = OpTypePointer Function %int +%_ptr_Function__ptr_Function_int = OpTypePointer Function %_ptr_Function_int +%1 = OpFunction %void None %11 +%17 = OpLabel +%18 = OpVariable %_ptr_Function__ptr_Function_int Function +%19 = OpVariable %_ptr_Function__struct_12 Function +%20 = OpAccessChain %_ptr_Function_9 %19 %int_0 +%21 = OpAccessChain %_ptr_Function_int %20 %uint_4 +OpStore %18 %21 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, false, false); +} + } // namespace } // namespace opt } // namespace spvtools From 3ab0d22608fba1a2106326f8f9f4ed7546cc0655 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Wed, 17 Jul 2024 14:51:37 -0400 Subject: [PATCH 476/523] Support SPV_KHR_untyped_pointers (#5736) * Support SPV_KHR_untyped_pointers Covers: - assembler - disassembler - validator fix copyright Validate OpTypeUntypedPointerKHR * Disallow an untyped pointer in a typed pointer * Validate capability requirements for untyped pointer * Allow duplicate untyped pointer declarations Add round trip tests Validate OpUntypedVariableKHR Validate untyped access chains * Add a test for opcodes that generate untyped pointers * simplify some checks for operands needing types * validate OpUnypedAccessChainKHR, OpUntypedInBoundsAccessChainKHR, OpUntypedPtrAccessChainKHR, OpUntypedInBoundsPtrAccessChainKHR Unify variable validation Validate OpCopyMemorySized * Fix some opcode tests to accound for untyped pointers * Add validation for OpCopyMemorySized for shaders and untyped pointers * fix up tests Validate pointer comparisons and bitcast * Update more helpers * Fix entry validation to allow OpUntypedVariableKHR * Validate OpPtrEqual, OpPtrNotEqual and OpPtrDiff * Validate OpBitcast Validate atomics and untyped pointers Make interface variable validation aware of untyped pointers * Check OpUntypedVariableKHR in interface validation More untyped pointer validation * Validate interfaces more thoroughly * Validate layouts for untyped pointer uses * Improve capability checks for vulkan with OpTypeUntypedPointerKHR * workgroup member explicit layout validation updates More validation * validate function arguments and parameters * handle untyped pointer and variable in more places Add a friendly assembly name for untyped pointers Update OpCopyMemory validation and tests Fix test for token update Fixes for validation * Allow typed pointers to contain untyped pointers * Fix decoration validation * add untyped pointer as a case for size and alignments Fix interface validation * Grabbed the wrong storage class operand for untyped variables * Add ability to specify assembler options in validation tests Add passthrough validation for OpUntypedArrayLengthKHR More validation of untyped pointers * Validate OpUntypedArrayLengthKHR * Validate layout for OpLoad, OpStore, and OpUntypedArrayLengthKHR Validation support for cooperative matrix and untyped pointers * Allow untyped pointers for cooperative matrix KHR load and store Updates to match spec * Remove extra capability references * Swap untyped variable data type and storage class operands * update validation of variables * update deps --------- Co-authored-by: David Neto --- DEPS | 2 +- source/name_mapper.cpp | 5 + source/opcode.cpp | 21 + source/opcode.h | 3 + source/val/validate_adjacency.cpp | 9 + source/val/validate_annotation.cpp | 10 +- source/val/validate_atomics.cpp | 39 +- source/val/validate_builtins.cpp | 4 + source/val/validate_cfg.cpp | 3 +- source/val/validate_constants.cpp | 1 + source/val/validate_decorations.cpp | 379 ++-- source/val/validate_function.cpp | 15 +- source/val/validate_id.cpp | 4 + source/val/validate_image.cpp | 30 +- source/val/validate_interfaces.cpp | 15 +- source/val/validate_logicals.cpp | 4 +- source/val/validate_memory.cpp | 514 ++++-- source/val/validate_type.cpp | 31 + source/val/validation_state.cpp | 44 +- source/val/validation_state.h | 3 + test/opcode_require_capabilities_test.cpp | 29 +- test/text_to_binary.extension_test.cpp | 49 + test/val/val_annotation_test.cpp | 27 + test/val/val_atomics_test.cpp | 128 +- test/val/val_conversion_test.cpp | 58 + test/val/val_decoration_test.cpp | 397 ++++ ..._spv_khr_subgroup_uniform_control_flow.cpp | 110 ++ test/val/val_fixtures.h | 8 +- test/val/val_function_test.cpp | 107 ++ test/val/val_id_test.cpp | 185 +- test/val/val_interfaces_test.cpp | 116 ++ test/val/val_memory_test.cpp | 1614 ++++++++++++++++- test/val/val_storage_test.cpp | 4 +- test/val/val_type_unique_test.cpp | 18 + 34 files changed, 3657 insertions(+), 329 deletions(-) create mode 100644 test/val/val_extension_spv_khr_subgroup_uniform_control_flow.cpp diff --git a/DEPS b/DEPS index d8fba6c64a..7ed619a487 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 're2_revision': '6dcd83d60f7944926bfd308cc13979fc53dd69ca', - 'spirv_headers_revision': '41a8eb27f1a7554dadfcdd45819954eaa94935e6', + 'spirv_headers_revision': 'db5a00f8cebe81146cafabf89019674a3c4bf03d', } deps = { diff --git a/source/name_mapper.cpp b/source/name_mapper.cpp index bc18b7f1b4..b0debde9d2 100644 --- a/source/name_mapper.cpp +++ b/source/name_mapper.cpp @@ -256,6 +256,11 @@ spv_result_t FriendlyNameMapper::ParseInstruction( inst.words[2]) + "_" + NameForId(inst.words[3])); break; + case spv::Op::OpTypeUntypedPointerKHR: + SaveName(result_id, std::string("_ptr_") + + NameForEnumOperand(SPV_OPERAND_TYPE_STORAGE_CLASS, + inst.words[2])); + break; case spv::Op::OpTypePipe: SaveName(result_id, std::string("Pipe") + diff --git a/source/opcode.cpp b/source/opcode.cpp index 5076bbddc2..c4ec94e4b1 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -287,8 +287,11 @@ int32_t spvOpcodeIsComposite(const spv::Op opcode) { bool spvOpcodeReturnsLogicalVariablePointer(const spv::Op opcode) { switch (opcode) { case spv::Op::OpVariable: + case spv::Op::OpUntypedVariableKHR: case spv::Op::OpAccessChain: case spv::Op::OpInBoundsAccessChain: + case spv::Op::OpUntypedAccessChainKHR: + case spv::Op::OpUntypedInBoundsAccessChainKHR: case spv::Op::OpFunctionParameter: case spv::Op::OpImageTexelPointer: case spv::Op::OpCopyObject: @@ -296,6 +299,7 @@ bool spvOpcodeReturnsLogicalVariablePointer(const spv::Op opcode) { case spv::Op::OpPhi: case spv::Op::OpFunctionCall: case spv::Op::OpPtrAccessChain: + case spv::Op::OpUntypedPtrAccessChainKHR: case spv::Op::OpLoad: case spv::Op::OpConstantNull: case spv::Op::OpRawAccessChainNV: @@ -308,8 +312,11 @@ bool spvOpcodeReturnsLogicalVariablePointer(const spv::Op opcode) { int32_t spvOpcodeReturnsLogicalPointer(const spv::Op opcode) { switch (opcode) { case spv::Op::OpVariable: + case spv::Op::OpUntypedVariableKHR: case spv::Op::OpAccessChain: case spv::Op::OpInBoundsAccessChain: + case spv::Op::OpUntypedAccessChainKHR: + case spv::Op::OpUntypedInBoundsAccessChainKHR: case spv::Op::OpFunctionParameter: case spv::Op::OpImageTexelPointer: case spv::Op::OpCopyObject: @@ -351,6 +358,7 @@ int32_t spvOpcodeGeneratesType(spv::Op op) { // spv::Op::OpTypeAccelerationStructureNV case spv::Op::OpTypeRayQueryKHR: case spv::Op::OpTypeHitObjectNV: + case spv::Op::OpTypeUntypedPointerKHR: return true; default: // In particular, OpTypeForwardPointer does not generate a type, @@ -792,3 +800,16 @@ bool spvOpcodeIsBit(spv::Op opcode) { return false; } } + +bool spvOpcodeGeneratesUntypedPointer(spv::Op opcode) { + switch (opcode) { + case spv::Op::OpUntypedVariableKHR: + case spv::Op::OpUntypedAccessChainKHR: + case spv::Op::OpUntypedInBoundsAccessChainKHR: + case spv::Op::OpUntypedPtrAccessChainKHR: + case spv::Op::OpUntypedInBoundsPtrAccessChainKHR: + return true; + default: + return false; + } +} diff --git a/source/opcode.h b/source/opcode.h index cecd566330..08fc56d8a0 100644 --- a/source/opcode.h +++ b/source/opcode.h @@ -162,4 +162,7 @@ bool spvOpcodeIsBit(spv::Op opcode); // Gets the name of an instruction, without the "Op" prefix. const char* spvOpcodeString(const spv::Op opcode); +// Returns true for opcodes that generate an untyped pointer result. +bool spvOpcodeGeneratesUntypedPointer(spv::Op opcode); + #endif // SOURCE_OPCODE_H_ diff --git a/source/val/validate_adjacency.cpp b/source/val/validate_adjacency.cpp index e6b00424d4..52519bfa9f 100644 --- a/source/val/validate_adjacency.cpp +++ b/source/val/validate_adjacency.cpp @@ -117,6 +117,15 @@ spv_result_t ValidateAdjacency(ValidationState_t& _) { "first instructions in the first block."; } break; + case spv::Op::OpUntypedVariableKHR: + if (inst.GetOperandAs(2) == + spv::StorageClass::Function && + adjacency_status != IN_ENTRY_BLOCK) { + return _.diag(SPV_ERROR_INVALID_DATA, &inst) + << "All OpUntypedVariableKHR instructions in a function must " + "be the first instructions in the first block."; + } + break; default: adjacency_status = PHI_AND_VAR_INVALID; break; diff --git a/source/val/validate_annotation.cpp b/source/val/validate_annotation.cpp index dac3585788..dfafaaa855 100644 --- a/source/val/validate_annotation.cpp +++ b/source/val/validate_annotation.cpp @@ -129,6 +129,7 @@ spv_result_t ValidateDecorationTarget(ValidationState_t& _, spv::Decoration dec, break; case spv::Decoration::BuiltIn: if (target->opcode() != spv::Op::OpVariable && + target->opcode() != spv::Op::OpUntypedVariableKHR && !spvOpcodeIsConstant(target->opcode())) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "BuiltIns can only target variables, structure members or " @@ -139,7 +140,8 @@ spv_result_t ValidateDecorationTarget(ValidationState_t& _, spv::Decoration dec, if (!spvOpcodeIsConstant(target->opcode())) { return fail(0) << "must be a constant for WorkgroupSize"; } - } else if (target->opcode() != spv::Op::OpVariable) { + } else if (target->opcode() != spv::Op::OpVariable && + target->opcode() != spv::Op::OpUntypedVariableKHR) { return fail(0) << "must be a variable"; } break; @@ -161,11 +163,12 @@ spv_result_t ValidateDecorationTarget(ValidationState_t& _, spv::Decoration dec, case spv::Decoration::RestrictPointer: case spv::Decoration::AliasedPointer: if (target->opcode() != spv::Op::OpVariable && + target->opcode() != spv::Op::OpUntypedVariableKHR && target->opcode() != spv::Op::OpFunctionParameter && target->opcode() != spv::Op::OpRawAccessChainNV) { return fail(0) << "must be a memory object declaration"; } - if (_.GetIdOpcode(target->type_id()) != spv::Op::OpTypePointer) { + if (!_.IsPointerType(target->type_id())) { return fail(0) << "must be a pointer type"; } break; @@ -176,7 +179,8 @@ spv_result_t ValidateDecorationTarget(ValidationState_t& _, spv::Decoration dec, case spv::Decoration::Binding: case spv::Decoration::DescriptorSet: case spv::Decoration::InputAttachmentIndex: - if (target->opcode() != spv::Op::OpVariable) { + if (target->opcode() != spv::Op::OpVariable && + target->opcode() != spv::Op::OpUntypedVariableKHR) { return fail(0) << "must be a variable"; } break; diff --git a/source/val/validate_atomics.cpp b/source/val/validate_atomics.cpp index 8ddef17896..990ed31518 100644 --- a/source/val/validate_atomics.cpp +++ b/source/val/validate_atomics.cpp @@ -183,7 +183,44 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { if (!_.GetPointerTypeInfo(pointer_type, &data_type, &storage_class)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << spvOpcodeString(opcode) - << ": expected Pointer to be of type OpTypePointer"; + << ": expected Pointer to be a pointer type"; + } + + // If the pointer is an untyped pointer, get the data type elsewhere. + if (data_type == 0) { + switch (opcode) { + case spv::Op::OpAtomicLoad: + case spv::Op::OpAtomicExchange: + case spv::Op::OpAtomicFAddEXT: + case spv::Op::OpAtomicCompareExchange: + case spv::Op::OpAtomicCompareExchangeWeak: + case spv::Op::OpAtomicIIncrement: + case spv::Op::OpAtomicIDecrement: + case spv::Op::OpAtomicIAdd: + case spv::Op::OpAtomicISub: + case spv::Op::OpAtomicSMin: + case spv::Op::OpAtomicUMin: + case spv::Op::OpAtomicFMinEXT: + case spv::Op::OpAtomicSMax: + case spv::Op::OpAtomicUMax: + case spv::Op::OpAtomicFMaxEXT: + case spv::Op::OpAtomicAnd: + case spv::Op::OpAtomicOr: + case spv::Op::OpAtomicXor: + data_type = inst->type_id(); + break; + case spv::Op::OpAtomicFlagTestAndSet: + case spv::Op::OpAtomicFlagClear: + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Untyped pointers are not supported by atomic flag " + "instructions"; + break; + case spv::Op::OpAtomicStore: + data_type = _.FindDef(inst->GetOperandAs(3))->type_id(); + break; + default: + break; + } } // Can't use result_type because OpAtomicStore doesn't have a result diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp index 9e307fcb14..1305dc1f84 100644 --- a/source/val/validate_builtins.cpp +++ b/source/val/validate_builtins.cpp @@ -97,12 +97,16 @@ spv_result_t GetUnderlyingType(ValidationState_t& _, spv::StorageClass GetStorageClass(const Instruction& inst) { switch (inst.opcode()) { case spv::Op::OpTypePointer: + case spv::Op::OpTypeUntypedPointerKHR: case spv::Op::OpTypeForwardPointer: { return spv::StorageClass(inst.word(2)); } case spv::Op::OpVariable: { return spv::StorageClass(inst.word(3)); } + case spv::Op::OpUntypedVariableKHR: { + return spv::StorageClass(inst.word(4)); + } case spv::Op::OpGenericCastToPtrExplicit: { return spv::StorageClass(inst.word(4)); } diff --git a/source/val/validate_cfg.cpp b/source/val/validate_cfg.cpp index 9b7161fc44..d401a2e7b7 100644 --- a/source/val/validate_cfg.cpp +++ b/source/val/validate_cfg.cpp @@ -250,7 +250,8 @@ spv_result_t ValidateReturnValue(ValidationState_t& _, } if (_.addressing_model() == spv::AddressingModel::Logical && - spv::Op::OpTypePointer == value_type->opcode() && + (spv::Op::OpTypePointer == value_type->opcode() || + spv::Op::OpTypeUntypedPointerKHR == value_type->opcode()) && !_.features().variable_pointers && !_.options()->relax_logical_pointer) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpReturnValue value's type " diff --git a/source/val/validate_constants.cpp b/source/val/validate_constants.cpp index 4deaa49688..1d40eedf91 100644 --- a/source/val/validate_constants.cpp +++ b/source/val/validate_constants.cpp @@ -324,6 +324,7 @@ bool IsTypeNullable(const std::vector& instruction, } return true; } + case spv::Op::OpTypeUntypedPointerKHR: case spv::Op::OpTypePointer: if (spv::StorageClass(instruction[2]) == spv::StorageClass::PhysicalStorageBuffer) { diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp index 7364cab7ae..e0fc098820 100644 --- a/source/val/validate_decorations.cpp +++ b/source/val/validate_decorations.cpp @@ -224,6 +224,7 @@ uint32_t getBaseAlignment(uint32_t member_id, bool roundUp, break; } case spv::Op::OpTypePointer: + case spv::Op::OpTypeUntypedPointerKHR: baseAlignment = vstate.pointer_size_and_alignment(); break; default: @@ -270,6 +271,7 @@ uint32_t getScalarAlignment(uint32_t type_id, ValidationState_t& vstate) { return max_member_alignment; } break; case spv::Op::OpTypePointer: + case spv::Op::OpTypeUntypedPointerKHR: return vstate.pointer_size_and_alignment(); default: assert(0); @@ -359,6 +361,7 @@ uint32_t getSize(uint32_t member_id, const LayoutConstraints& inherited, return offset + getSize(lastMember, constraint, constraints, vstate); } case spv::Op::OpTypePointer: + case spv::Op::OpTypeUntypedPointerKHR: return vstate.pointer_size_and_alignment(); default: assert(0); @@ -432,9 +435,9 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, return ds; }; - // If we are checking physical storage buffer pointers, we may not actually - // have a struct here. Instead, pretend we have a struct with a single member - // at offset 0. + // If we are checking the layout of untyped pointers or physical storage + // buffer pointers, we may not actually have a struct here. Instead, pretend + // we have a struct with a single member at offset 0. const auto& struct_type = vstate.FindDef(struct_id); std::vector members; if (struct_type->opcode() == spv::Op::OpTypeStruct) { @@ -451,8 +454,8 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, }; std::vector member_offsets; - // With physical storage buffers, we might be checking layouts that do not - // originate from a structure. + // With untyped pointers or physical storage buffers, we might be checking + // layouts that do not originate from a structure. if (struct_type->opcode() == spv::Op::OpTypeStruct) { member_offsets.reserve(members.size()); for (uint32_t memberIdx = 0, numMembers = uint32_t(members.size()); @@ -770,14 +773,19 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { std::unordered_set output_var_builtin; for (auto interface : desc.interfaces) { Instruction* var_instr = vstate.FindDef(interface); - if (!var_instr || spv::Op::OpVariable != var_instr->opcode()) { + if (!var_instr || + (spv::Op::OpVariable != var_instr->opcode() && + spv::Op::OpUntypedVariableKHR != var_instr->opcode())) { return vstate.diag(SPV_ERROR_INVALID_ID, var_instr) - << "Interfaces passed to OpEntryPoint must be of type " - "OpTypeVariable. Found Op" + << "Interfaces passed to OpEntryPoint must be variables. " + "Found Op" << spvOpcodeString(var_instr->opcode()) << "."; } + const bool untyped_pointers = + var_instr->opcode() == spv::Op::OpUntypedVariableKHR; + const auto sc_index = 2u; const spv::StorageClass storage_class = - var_instr->GetOperandAs(2); + var_instr->GetOperandAs(sc_index); if (vstate.version() >= SPV_SPIRV_VERSION_WORD(1, 4)) { // Starting in 1.4, OpEntryPoint must list all global variables // it statically uses and those interfaces must be unique. @@ -804,12 +812,13 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { } } - const uint32_t ptr_id = var_instr->word(1); - Instruction* ptr_instr = vstate.FindDef(ptr_id); // It is guaranteed (by validator ID checks) that ptr_instr is // OpTypePointer. Word 3 of this instruction is the type being pointed - // to. - const uint32_t type_id = ptr_instr->word(3); + // to. For untyped variables, the pointee type comes from the data type + // operand. + const uint32_t type_id = + untyped_pointers ? var_instr->word(4) + : vstate.FindDef(var_instr->word(1))->word(3); Instruction* type_instr = vstate.FindDef(type_id); const bool is_struct = type_instr && spv::Op::OpTypeStruct == type_instr->opcode(); @@ -874,12 +883,25 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { if (storage_class == spv::StorageClass::Workgroup) { ++num_workgroup_variables; - if (is_struct) { - if (hasDecoration(type_id, spv::Decoration::Block, vstate)) - ++num_workgroup_variables_with_block; - if (hasDecoration(var_instr->id(), spv::Decoration::Aliased, - vstate)) - ++num_workgroup_variables_with_aliased; + if (type_instr) { + if (spv::Op::OpTypeStruct == type_instr->opcode()) { + if (hasDecoration(type_id, spv::Decoration::Block, vstate)) { + ++num_workgroup_variables_with_block; + } else if (untyped_pointers && + vstate.HasCapability(spv::Capability::Shader)) { + return vstate.diag(SPV_ERROR_INVALID_ID, var_instr) + << "Untyped workgroup variables in shaders must be " + "block decorated"; + } + if (hasDecoration(var_instr->id(), spv::Decoration::Aliased, + vstate)) + ++num_workgroup_variables_with_aliased; + } else if (untyped_pointers && + vstate.HasCapability(spv::Capability::Shader)) { + return vstate.diag(SPV_ERROR_INVALID_ID, var_instr) + << "Untyped workgroup variables in shaders must be block " + "decorated structs"; + } } } @@ -960,25 +982,33 @@ spv_result_t CheckDecorationsOfEntryPoints(ValidationState_t& vstate) { const bool workgroup_blocks_allowed = vstate.HasCapability( spv::Capability::WorkgroupMemoryExplicitLayoutKHR); - if (workgroup_blocks_allowed && num_workgroup_variables > 0 && + if (workgroup_blocks_allowed && + !vstate.HasCapability(spv::Capability::UntypedPointersKHR) && + 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)) + return vstate.diag(SPV_ERROR_INVALID_BINARY, + vstate.FindDef(entry_point)) << "When declaring WorkgroupMemoryExplicitLayoutKHR, " - "either all or none of the Workgroup Storage Class variables " + "either all or none of the Workgroup Storage Class " + "variables " "in the entry point interface must point to struct types " - "decorated with Block. Entry point id " + "decorated with Block (unless the " + "UntypedPointersKHR capability is declared). " + "Entry point id " << entry_point << " does not meet this requirement."; } if (num_workgroup_variables_with_block > 1 && num_workgroup_variables_with_block != num_workgroup_variables_with_aliased) { - return vstate.diag(SPV_ERROR_INVALID_BINARY, vstate.FindDef(entry_point)) + return vstate.diag(SPV_ERROR_INVALID_BINARY, + vstate.FindDef(entry_point)) << "When declaring WorkgroupMemoryExplicitLayoutKHR, " "if more than one Workgroup Storage Class variable in " "the entry point interface point to a type decorated " - "with Block, all of them must be decorated with Aliased. " - "Entry point id " + "with Block, all of them must be decorated with Aliased " + "(unless the UntypedPointerWorkgroupKHR capability is " + "declared). Entry point id " << entry_point << " does not meet this requirement."; } } else if (!workgroup_blocks_allowed && @@ -1084,11 +1114,17 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { const auto& words = inst.words(); auto type_id = inst.type_id(); const Instruction* type_inst = vstate.FindDef(type_id); - if (spv::Op::OpVariable == inst.opcode()) { + bool scalar_block_layout = false; + MemberConstraints constraints; + if (spv::Op::OpVariable == inst.opcode() || + spv::Op::OpUntypedVariableKHR == inst.opcode()) { + const bool untyped_pointer = + inst.opcode() == spv::Op::OpUntypedVariableKHR; const auto var_id = inst.id(); // For storage class / decoration combinations, see Vulkan 14.5.4 "Offset // and Stride Assignment". - const auto storageClass = inst.GetOperandAs(2); + const auto storageClassVal = words[3]; + const auto storageClass = spv::StorageClass(storageClassVal); const bool uniform = storageClass == spv::StorageClass::Uniform; const bool uniform_constant = storageClass == spv::StorageClass::UniformConstant; @@ -1167,20 +1203,24 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { if (uniform || push_constant || storage_buffer || phys_storage_buffer || workgroup) { const auto ptrInst = vstate.FindDef(words[1]); - assert(spv::Op::OpTypePointer == ptrInst->opcode()); - auto id = ptrInst->words()[3]; - auto id_inst = vstate.FindDef(id); - // Jump through one level of arraying. - if (!workgroup && (id_inst->opcode() == spv::Op::OpTypeArray || - id_inst->opcode() == spv::Op::OpTypeRuntimeArray)) { - id = id_inst->GetOperandAs(1u); - id_inst = vstate.FindDef(id); + assert(spv::Op::OpTypePointer == ptrInst->opcode() || + spv::Op::OpTypeUntypedPointerKHR == ptrInst->opcode()); + auto id = untyped_pointer ? (words.size() > 4 ? words[4] : 0) + : ptrInst->words()[3]; + if (id != 0) { + auto id_inst = vstate.FindDef(id); + // Jump through one level of arraying. + if (!workgroup && + (id_inst->opcode() == spv::Op::OpTypeArray || + id_inst->opcode() == spv::Op::OpTypeRuntimeArray)) { + id = id_inst->GetOperandAs(1u); + id_inst = vstate.FindDef(id); + } + // Struct requirement is checked on variables so just move on here. + if (spv::Op::OpTypeStruct != id_inst->opcode()) continue; + ComputeMemberConstraintsForStruct(&constraints, id, + LayoutConstraints(), vstate); } - // Struct requirement is checked on variables so just move on here. - if (spv::Op::OpTypeStruct != id_inst->opcode()) continue; - MemberConstraints constraints; - ComputeMemberConstraintsForStruct(&constraints, id, LayoutConstraints(), - vstate); // Prepare for messages const char* sc_str = uniform ? "Uniform" @@ -1250,88 +1290,91 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { } } - for (const auto& dec : vstate.id_decorations(id)) { - const bool blockDeco = spv::Decoration::Block == dec.dec_type(); - const bool bufferDeco = - spv::Decoration::BufferBlock == dec.dec_type(); - const bool blockRules = uniform && blockDeco; - const bool bufferRules = - (uniform && bufferDeco) || - ((push_constant || storage_buffer || - phys_storage_buffer || workgroup) && blockDeco); - if (uniform && blockDeco) { - vstate.RegisterPointerToUniformBlock(ptrInst->id()); - vstate.RegisterStructForUniformBlock(id); - } - if ((uniform && bufferDeco) || - ((storage_buffer || phys_storage_buffer) && blockDeco)) { - vstate.RegisterPointerToStorageBuffer(ptrInst->id()); - vstate.RegisterStructForStorageBuffer(id); - } - - if (blockRules || bufferRules) { - const char* deco_str = blockDeco ? "Block" : "BufferBlock"; - spv_result_t recursive_status = SPV_SUCCESS; - const bool scalar_block_layout = workgroup ? - vstate.options()->workgroup_scalar_block_layout : - vstate.options()->scalar_block_layout; - - if (isMissingOffsetInStruct(id, vstate)) { - return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) - << "Structure id " << id << " decorated as " << deco_str - << " must be explicitly laid out with Offset " - "decorations."; + if (id != 0) { + for (const auto& dec : vstate.id_decorations(id)) { + const bool blockDeco = spv::Decoration::Block == dec.dec_type(); + const bool bufferDeco = + spv::Decoration::BufferBlock == dec.dec_type(); + const bool blockRules = uniform && blockDeco; + const bool bufferRules = (uniform && bufferDeco) || + ((push_constant || storage_buffer || + phys_storage_buffer || workgroup) && + blockDeco); + if (uniform && blockDeco) { + vstate.RegisterPointerToUniformBlock(ptrInst->id()); + vstate.RegisterStructForUniformBlock(id); } - - if (!checkForRequiredDecoration( - id, - [](spv::Decoration d) { - return d == spv::Decoration::ArrayStride; - }, - spv::Op::OpTypeArray, vstate)) { - return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) - << "Structure id " << id << " decorated as " << deco_str - << " must be explicitly laid out with ArrayStride " - "decorations."; + if ((uniform && bufferDeco) || + ((storage_buffer || phys_storage_buffer) && blockDeco)) { + vstate.RegisterPointerToStorageBuffer(ptrInst->id()); + vstate.RegisterStructForStorageBuffer(id); } - if (!checkForRequiredDecoration( - id, - [](spv::Decoration d) { - return d == spv::Decoration::MatrixStride; - }, - spv::Op::OpTypeMatrix, vstate)) { - return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) - << "Structure id " << id << " decorated as " << deco_str - << " must be explicitly laid out with MatrixStride " - "decorations."; - } + if (blockRules || bufferRules) { + const char* deco_str = blockDeco ? "Block" : "BufferBlock"; + spv_result_t recursive_status = SPV_SUCCESS; + scalar_block_layout = + workgroup ? vstate.options()->workgroup_scalar_block_layout + : vstate.options()->scalar_block_layout; + + if (isMissingOffsetInStruct(id, vstate)) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) + << "Structure id " << id << " decorated as " << deco_str + << " must be explicitly laid out with Offset " + "decorations."; + } - if (!checkForRequiredDecoration( - id, - [](spv::Decoration d) { - return d == spv::Decoration::RowMajor || - d == spv::Decoration::ColMajor; - }, - spv::Op::OpTypeMatrix, vstate)) { - return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) - << "Structure id " << id << " decorated as " << deco_str - << " must be explicitly laid out with RowMajor or " - "ColMajor decorations."; - } + if (!checkForRequiredDecoration( + id, + [](spv::Decoration d) { + return d == spv::Decoration::ArrayStride; + }, + spv::Op::OpTypeArray, vstate)) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) + << "Structure id " << id << " decorated as " << deco_str + << " must be explicitly laid out with ArrayStride " + "decorations."; + } + + if (!checkForRequiredDecoration( + id, + [](spv::Decoration d) { + return d == spv::Decoration::MatrixStride; + }, + spv::Op::OpTypeMatrix, vstate)) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) + << "Structure id " << id << " decorated as " << deco_str + << " must be explicitly laid out with MatrixStride " + "decorations."; + } + + if (!checkForRequiredDecoration( + id, + [](spv::Decoration d) { + return d == spv::Decoration::RowMajor || + d == spv::Decoration::ColMajor; + }, + spv::Op::OpTypeMatrix, vstate)) { + return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id)) + << "Structure id " << id << " decorated as " << deco_str + << " must be explicitly laid out with RowMajor or " + "ColMajor decorations."; + } - if (spvIsVulkanEnv(vstate.context()->target_env)) { - if (blockRules && (SPV_SUCCESS != (recursive_status = checkLayout( - id, sc_str, deco_str, true, + if (spvIsVulkanEnv(vstate.context()->target_env)) { + if (blockRules && + (SPV_SUCCESS != + (recursive_status = checkLayout(id, sc_str, deco_str, true, scalar_block_layout, 0, constraints, vstate)))) { - return recursive_status; - } else if (bufferRules && - (SPV_SUCCESS != - (recursive_status = checkLayout( - id, sc_str, deco_str, false, scalar_block_layout, - 0, constraints, vstate)))) { - return recursive_status; + return recursive_status; + } else if (bufferRules && + (SPV_SUCCESS != (recursive_status = checkLayout( + id, sc_str, deco_str, false, + scalar_block_layout, 0, + constraints, vstate)))) { + return recursive_status; + } } } } @@ -1340,20 +1383,98 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { } else if (type_inst && type_inst->opcode() == spv::Op::OpTypePointer && type_inst->GetOperandAs(1u) == spv::StorageClass::PhysicalStorageBuffer) { - const bool scalar_block_layout = vstate.options()->scalar_block_layout; - MemberConstraints constraints; const bool buffer = true; - const auto data_type_id = type_inst->GetOperandAs(2u); - const auto* data_type_inst = vstate.FindDef(data_type_id); + const auto pointee_type_id = type_inst->GetOperandAs(2u); + const auto* data_type_inst = vstate.FindDef(pointee_type_id); + scalar_block_layout = vstate.options()->scalar_block_layout; if (data_type_inst->opcode() == spv::Op::OpTypeStruct) { - ComputeMemberConstraintsForStruct(&constraints, data_type_id, + ComputeMemberConstraintsForStruct(&constraints, pointee_type_id, LayoutConstraints(), vstate); } - if (auto res = checkLayout(data_type_id, "PhysicalStorageBuffer", "Block", - !buffer, scalar_block_layout, 0, constraints, - vstate)) { + if (auto res = checkLayout(pointee_type_id, "PhysicalStorageBuffer", + "Block", !buffer, scalar_block_layout, 0, + constraints, vstate)) { return res; } + } else if (vstate.HasCapability(spv::Capability::UntypedPointersKHR) && + spvIsVulkanEnv(vstate.context()->target_env)) { + // Untyped variables are checked above. Here we check that instructions + // using an untyped pointer have a valid layout. + uint32_t ptr_ty_id = 0; + uint32_t data_type_id = 0; + switch (inst.opcode()) { + case spv::Op::OpUntypedAccessChainKHR: + case spv::Op::OpUntypedInBoundsAccessChainKHR: + case spv::Op::OpUntypedPtrAccessChainKHR: + case spv::Op::OpUntypedInBoundsPtrAccessChainKHR: + ptr_ty_id = inst.type_id(); + data_type_id = inst.GetOperandAs(2); + break; + case spv::Op::OpLoad: + if (vstate.GetIdOpcode(vstate.GetOperandTypeId(&inst, 2)) == + spv::Op::OpTypeUntypedPointerKHR) { + const auto ptr_id = inst.GetOperandAs(2); + ptr_ty_id = vstate.FindDef(ptr_id)->type_id(); + data_type_id = inst.type_id(); + } + break; + case spv::Op::OpStore: + if (vstate.GetIdOpcode(vstate.GetOperandTypeId(&inst, 0)) == + spv::Op::OpTypeUntypedPointerKHR) { + const auto ptr_id = inst.GetOperandAs(0); + ptr_ty_id = vstate.FindDef(ptr_id)->type_id(); + data_type_id = vstate.GetOperandTypeId(&inst, 1); + } + break; + case spv::Op::OpUntypedArrayLengthKHR: + ptr_ty_id = vstate.FindDef(inst.GetOperandAs(3))->type_id(); + data_type_id = inst.GetOperandAs(2); + break; + default: + break; + } + + if (ptr_ty_id == 0 || data_type_id == 0) { + // Not an untyped pointer. + continue; + } + + const auto sc = + vstate.FindDef(ptr_ty_id)->GetOperandAs(1); + + const char* sc_str = + sc == spv::StorageClass::Uniform + ? "Uniform" + : (sc == spv::StorageClass::PushConstant + ? "PushConstant" + : (sc == spv::StorageClass::Workgroup ? "Workgroup" + : "StorageBuffer")); + + const auto data_type = vstate.FindDef(data_type_id); + scalar_block_layout = + sc == spv::StorageClass::Workgroup + ? vstate.options()->workgroup_scalar_block_layout + : vstate.options()->scalar_block_layout; + // Assume uniform storage class uses block rules unless we see a + // BufferBlock decorated struct in the data type. + bool bufferRules = sc == spv::StorageClass::Uniform ? false : true; + if (data_type->opcode() == spv::Op::OpTypeStruct) { + if (sc == spv::StorageClass::Uniform) { + bufferRules = + vstate.HasDecoration(data_type_id, spv::Decoration::BufferBlock); + } + ComputeMemberConstraintsForStruct(&constraints, data_type_id, + LayoutConstraints(), vstate); + } + const char* deco_str = + bufferRules + ? (sc == spv::StorageClass::Uniform ? "BufferBlock" : "Block") + : "Block"; + if (auto result = + checkLayout(data_type_id, sc_str, deco_str, !bufferRules, + scalar_block_layout, 0, constraints, vstate)) { + return result; + } } } return SPV_SUCCESS; @@ -1585,15 +1706,19 @@ spv_result_t CheckNonWritableDecoration(ValidationState_t& vstate, const auto opcode = inst.opcode(); const auto type_id = inst.type_id(); if (opcode != spv::Op::OpVariable && + opcode != spv::Op::OpUntypedVariableKHR && opcode != spv::Op::OpFunctionParameter && opcode != spv::Op::OpRawAccessChainNV) { return vstate.diag(SPV_ERROR_INVALID_ID, &inst) << "Target of NonWritable decoration must be a memory object " "declaration (a variable or a function parameter)"; } - const auto var_storage_class = opcode == spv::Op::OpVariable - ? inst.GetOperandAs(2) - : spv::StorageClass::Max; + const auto var_storage_class = + opcode == spv::Op::OpVariable + ? inst.GetOperandAs(2) + : opcode == spv::Op::OpUntypedVariableKHR + ? inst.GetOperandAs(3) + : spv::StorageClass::Max; if ((var_storage_class == spv::StorageClass::Function || var_storage_class == spv::StorageClass::Private) && vstate.features().nonwritable_var_in_function_or_private) { diff --git a/source/val/validate_function.cpp b/source/val/validate_function.cpp index 639817fef4..26b3668282 100644 --- a/source/val/validate_function.cpp +++ b/source/val/validate_function.cpp @@ -156,7 +156,9 @@ spv_result_t ValidateFunctionParameter(ValidationState_t& _, param_nonarray_type_id = _.FindDef(param_nonarray_type_id)->GetOperandAs(1u); } - if (_.GetIdOpcode(param_nonarray_type_id) == spv::Op::OpTypePointer) { + if (_.GetIdOpcode(param_nonarray_type_id) == spv::Op::OpTypePointer || + _.GetIdOpcode(param_nonarray_type_id) == + spv::Op::OpTypeUntypedPointerKHR) { auto param_nonarray_type = _.FindDef(param_nonarray_type_id); if (param_nonarray_type->GetOperandAs(1u) == spv::StorageClass::PhysicalStorageBuffer) { @@ -185,7 +187,7 @@ spv_result_t ValidateFunctionParameter(ValidationState_t& _, << ": can't specify both Aliased and Restrict for " "PhysicalStorageBuffer pointer."; } - } else { + } else if (param_nonarray_type->opcode() == spv::Op::OpTypePointer) { const auto pointee_type_id = param_nonarray_type->GetOperandAs(2); const auto pointee_type = _.FindDef(pointee_type_id); @@ -288,7 +290,8 @@ spv_result_t ValidateFunctionCall(ValidationState_t& _, } if (_.addressing_model() == spv::AddressingModel::Logical) { - if (parameter_type->opcode() == spv::Op::OpTypePointer && + if ((parameter_type->opcode() == spv::Op::OpTypePointer || + parameter_type->opcode() == spv::Op::OpTypeUntypedPointerKHR) && !_.options()->relax_logical_pointer) { spv::StorageClass sc = parameter_type->GetOperandAs(1u); @@ -317,9 +320,11 @@ spv_result_t ValidateFunctionCall(ValidationState_t& _, // Validate memory object declaration requirements. if (argument->opcode() != spv::Op::OpVariable && + argument->opcode() != spv::Op::OpUntypedVariableKHR && argument->opcode() != spv::Op::OpFunctionParameter) { - const bool ssbo_vptr = _.features().variable_pointers && - sc == spv::StorageClass::StorageBuffer; + const bool ssbo_vptr = + _.HasCapability(spv::Capability::VariablePointersStorageBuffer) && + sc == spv::StorageClass::StorageBuffer; const bool wg_vptr = _.HasCapability(spv::Capability::VariablePointers) && sc == spv::StorageClass::Workgroup; diff --git a/source/val/validate_id.cpp b/source/val/validate_id.cpp index 23512125d0..0d1e84123e 100644 --- a/source/val/validate_id.cpp +++ b/source/val/validate_id.cpp @@ -165,6 +165,8 @@ spv_result_t IdPass(ValidationState_t& _, Instruction* inst) { !spvOpcodeIsDecoration(opcode) && opcode != spv::Op::OpFunction && opcode != spv::Op::OpCooperativeMatrixLengthNV && opcode != spv::Op::OpCooperativeMatrixLengthKHR && + !spvOpcodeGeneratesUntypedPointer(opcode) && + opcode != spv::Op::OpUntypedArrayLengthKHR && !(opcode == spv::Op::OpSpecConstantOp && (spv::Op(inst->word(3)) == spv::Op::OpCooperativeMatrixLengthNV || @@ -185,6 +187,8 @@ spv_result_t IdPass(ValidationState_t& _, Instruction* inst) { opcode != spv::Op::OpFunction && opcode != spv::Op::OpCooperativeMatrixLengthNV && opcode != spv::Op::OpCooperativeMatrixLengthKHR && + !spvOpcodeGeneratesUntypedPointer(opcode) && + opcode != spv::Op::OpUntypedArrayLengthKHR && !(opcode == spv::Op::OpSpecConstantOp && (spv::Op(inst->word(3)) == spv::Op::OpCooperativeMatrixLengthNV || diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index 9af97b79b7..aadc264e02 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -1121,7 +1121,8 @@ spv_result_t ValidateSampledImage(ValidationState_t& _, spv_result_t ValidateImageTexelPointer(ValidationState_t& _, const Instruction* inst) { const auto result_type = _.FindDef(inst->type_id()); - if (result_type->opcode() != spv::Op::OpTypePointer) { + if (result_type->opcode() != spv::Op::OpTypePointer && + result_type->opcode() == spv::Op::OpTypeUntypedPointerKHR) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Result Type to be OpTypePointer"; } @@ -1133,16 +1134,20 @@ spv_result_t ValidateImageTexelPointer(ValidationState_t& _, "operand is Image"; } - const auto ptr_type = result_type->GetOperandAs(2); - const auto ptr_opcode = _.GetIdOpcode(ptr_type); - if (ptr_opcode != spv::Op::OpTypeInt && ptr_opcode != spv::Op::OpTypeFloat && - ptr_opcode != spv::Op::OpTypeVoid && - !(ptr_opcode == spv::Op::OpTypeVector && - _.HasCapability(spv::Capability::AtomicFloat16VectorNV) && - _.IsFloat16Vector2Or4Type(ptr_type))) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected Result Type to be OpTypePointer whose Type operand " - "must be a scalar numerical type or OpTypeVoid"; + uint32_t ptr_type = 0; + if (result_type->opcode() == spv::Op::OpTypePointer) { + ptr_type = result_type->GetOperandAs(2); + const auto ptr_opcode = _.GetIdOpcode(ptr_type); + if (ptr_opcode != spv::Op::OpTypeInt && + ptr_opcode != spv::Op::OpTypeFloat && + ptr_opcode != spv::Op::OpTypeVoid && + !(ptr_opcode == spv::Op::OpTypeVector && + _.HasCapability(spv::Capability::AtomicFloat16VectorNV) && + _.IsFloat16Vector2Or4Type(ptr_type))) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Expected Result Type to be OpTypePointer whose Type operand " + "must be a scalar numerical type or OpTypeVoid"; + } } const auto image_ptr = _.FindDef(_.GetOperandTypeId(inst, 2)); @@ -1163,7 +1168,8 @@ spv_result_t ValidateImageTexelPointer(ValidationState_t& _, << "Corrupt image type definition"; } - if (info.sampled_type != ptr_type && + if (result_type->opcode() == spv::Op::OpTypePointer && + info.sampled_type != ptr_type && !(_.HasCapability(spv::Capability::AtomicFloat16VectorNV) && _.IsFloat16Vector2Or4Type(ptr_type) && _.GetIdOpcode(info.sampled_type) == spv::Op::OpTypeFloat && diff --git a/source/val/validate_interfaces.cpp b/source/val/validate_interfaces.cpp index 8f10b9d07f..8b96dc8248 100644 --- a/source/val/validate_interfaces.cpp +++ b/source/val/validate_interfaces.cpp @@ -34,11 +34,13 @@ const uint32_t kMaxLocations = 4096 * 4; bool is_interface_variable(const Instruction* inst, bool is_spv_1_4) { if (is_spv_1_4) { // Starting in SPIR-V 1.4, all global variables are interface variables. - return inst->opcode() == spv::Op::OpVariable && + return (inst->opcode() == spv::Op::OpVariable || + inst->opcode() == spv::Op::OpUntypedVariableKHR) && inst->GetOperandAs(2u) != spv::StorageClass::Function; } else { - return inst->opcode() == spv::Op::OpVariable && + return (inst->opcode() == spv::Op::OpVariable || + inst->opcode() == spv::Op::OpUntypedVariableKHR) && (inst->GetOperandAs(2u) == spv::StorageClass::Input || inst->GetOperandAs(2u) == @@ -242,8 +244,9 @@ spv_result_t GetLocationsForVariable( std::unordered_set* output_index1_locations) { const bool is_fragment = entry_point->GetOperandAs(0) == spv::ExecutionModel::Fragment; - const bool is_output = - variable->GetOperandAs(2) == spv::StorageClass::Output; + const auto sc_index = 2u; + const bool is_output = variable->GetOperandAs(sc_index) == + spv::StorageClass::Output; auto ptr_type_id = variable->GetOperandAs(0); auto ptr_type = _.FindDef(ptr_type_id); auto type_id = ptr_type->GetOperandAs(2); @@ -525,7 +528,9 @@ spv_result_t ValidateLocations(ValidationState_t& _, for (uint32_t i = 3; i < entry_point->operands().size(); ++i) { auto interface_id = entry_point->GetOperandAs(i); auto interface_var = _.FindDef(interface_id); - auto storage_class = interface_var->GetOperandAs(2); + const auto sc_index = 2u; + auto storage_class = + interface_var->GetOperandAs(sc_index); if (storage_class != spv::StorageClass::Input && storage_class != spv::StorageClass::Output) { continue; diff --git a/source/val/validate_logicals.cpp b/source/val/validate_logicals.cpp index 4479e43958..8a2e5d8c42 100644 --- a/source/val/validate_logicals.cpp +++ b/source/val/validate_logicals.cpp @@ -159,9 +159,11 @@ spv_result_t LogicalsPass(ValidationState_t& _, const Instruction* inst) { const spv::Op type_opcode = type_inst->opcode(); switch (type_opcode) { + case spv::Op::OpTypeUntypedPointerKHR: case spv::Op::OpTypePointer: { if (_.addressing_model() == spv::AddressingModel::Logical && - !_.features().variable_pointers) + !_.HasCapability( + spv::Capability::VariablePointersStorageBuffer)) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Using pointers with OpSelect requires capability " << "VariablePointers or VariablePointersStorageBuffer"; diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index ef6676fb7b..beaa79c28e 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -407,19 +407,58 @@ spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst, } spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { + const bool untyped_pointer = inst->opcode() == spv::Op::OpUntypedVariableKHR; + auto result_type = _.FindDef(inst->type_id()); - if (!result_type || result_type->opcode() != spv::Op::OpTypePointer) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpVariable Result Type " << _.getIdName(inst->type_id()) - << " is not a pointer type."; + if (untyped_pointer) { + if (!result_type || + result_type->opcode() != spv::Op::OpTypeUntypedPointerKHR) + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Result type must be an untyped pointer"; + } else { + if (!result_type || result_type->opcode() != spv::Op::OpTypePointer) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpVariable Result Type " << _.getIdName(inst->type_id()) + << " is not a pointer type."; + } + } + + const auto storage_class_index = 2u; + auto storage_class = + inst->GetOperandAs(storage_class_index); + uint32_t value_id = 0; + if (untyped_pointer) { + const auto has_data_type = 3u < inst->operands().size(); + if (has_data_type) { + value_id = inst->GetOperandAs(3u); + auto data_type = _.FindDef(value_id); + if (!data_type || !spvOpcodeGeneratesType(data_type->opcode())) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Data type must be a type instruction"; + } + } else { + if (storage_class == spv::StorageClass::Function || + storage_class == spv::StorageClass::Private || + storage_class == spv::StorageClass::Workgroup) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Data type must be specified for Function, Private, and " + "Workgroup storage classes"; + } + if (spvIsVulkanEnv(_.context()->target_env)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Vulkan requires that data type be specified"; + } + } } - const auto type_index = 2; - const auto value_id = result_type->GetOperandAs(type_index); - auto value_type = _.FindDef(value_id); + // For OpVariable the data type comes from pointee type of the result type, + // while for OpUntypedVariableKHR the data type comes from the operand. + if (!untyped_pointer) { + value_id = result_type->GetOperandAs(2); + } + auto value_type = value_id == 0 ? nullptr : _.FindDef(value_id); - const auto initializer_index = 3; - const auto storage_class_index = 2; + const auto initializer_index = untyped_pointer ? 4u : 3u; if (initializer_index < inst->operands().size()) { const auto initializer_id = inst->GetOperandAs(initializer_index); const auto initializer = _.FindDef(initializer_id); @@ -431,18 +470,15 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { initializer && spvOpcodeIsConstant(initializer->opcode()); if (!initializer || !(is_constant || is_module_scope_var)) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpVariable Initializer " << _.getIdName(initializer_id) + << "Variable Initializer " << _.getIdName(initializer_id) << " is not a constant or module-scope variable."; } if (initializer->type_id() != value_id) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "Initializer type must match the type pointed to by the Result " - "Type"; + << "Initializer type must match the data type"; } } - auto storage_class = - inst->GetOperandAs(storage_class_index); if (storage_class != spv::StorageClass::Workgroup && storage_class != spv::StorageClass::CrossWorkgroup && storage_class != spv::StorageClass::Private && @@ -466,7 +502,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } } } - if (!builtin && + if (!builtin && value_type && ContainsInvalidBool(_, value_type, storage_input_or_output)) { if (storage_input_or_output) { return _.diag(SPV_ERROR_INVALID_ID, inst) @@ -495,7 +531,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { if (storage_class == spv::StorageClass::Generic) { return _.diag(SPV_ERROR_INVALID_BINARY, inst) - << "OpVariable storage class cannot be Generic"; + << "Variable storage class cannot be Generic"; } if (inst->function() && storage_class != spv::StorageClass::Function) { @@ -517,17 +553,17 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { result_type->GetOperandAs(result_storage_class_index); if (storage_class != result_storage_class) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "From SPIR-V spec, section 3.32.8 on OpVariable:\n" - << "Its Storage Class operand must be the same as the Storage Class " - << "operand of the result type."; + << "Storage class must match result type storage class"; } // Variable pointer related restrictions. - const auto pointee = _.FindDef(result_type->word(3)); + const auto pointee = untyped_pointer + ? value_id == 0 ? nullptr : _.FindDef(value_id) + : _.FindDef(result_type->word(3)); if (_.addressing_model() == spv::AddressingModel::Logical && !_.options()->relax_logical_pointer) { // VariablePointersStorageBuffer is implied by VariablePointers. - if (pointee->opcode() == spv::Op::OpTypePointer) { + if (pointee && pointee->opcode() == spv::Op::OpTypePointer) { if (!_.HasCapability(spv::Capability::VariablePointersStorageBuffer)) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "In Logical addressing, variables may not allocate a pointer " @@ -546,7 +582,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { // Vulkan Push Constant Interface section: Check type of PushConstant // variables. if (storage_class == spv::StorageClass::PushConstant) { - if (pointee->opcode() != spv::Op::OpTypeStruct) { + if (pointee && pointee->opcode() != spv::Op::OpTypeStruct) { return _.diag(SPV_ERROR_INVALID_ID, inst) << _.VkErrorID(6808) << "PushConstant OpVariable " << _.getIdName(inst->id()) << " has illegal type.\n" @@ -558,11 +594,11 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { // Vulkan Descriptor Set Interface: Check type of UniformConstant and // Uniform variables. if (storage_class == spv::StorageClass::UniformConstant) { - if (!IsAllowedTypeOrArrayOfSame( - _, pointee, - {spv::Op::OpTypeImage, spv::Op::OpTypeSampler, - spv::Op::OpTypeSampledImage, - spv::Op::OpTypeAccelerationStructureKHR})) { + if (pointee && !IsAllowedTypeOrArrayOfSame( + _, pointee, + {spv::Op::OpTypeImage, spv::Op::OpTypeSampler, + spv::Op::OpTypeSampledImage, + spv::Op::OpTypeAccelerationStructureKHR})) { return _.diag(SPV_ERROR_INVALID_ID, inst) << _.VkErrorID(4655) << "UniformConstant OpVariable " << _.getIdName(inst->id()) << " has illegal type.\n" @@ -575,7 +611,8 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } if (storage_class == spv::StorageClass::Uniform) { - if (!IsAllowedTypeOrArrayOfSame(_, pointee, {spv::Op::OpTypeStruct})) { + if (pointee && + !IsAllowedTypeOrArrayOfSame(_, pointee, {spv::Op::OpTypeStruct})) { return _.diag(SPV_ERROR_INVALID_ID, inst) << _.VkErrorID(6807) << "Uniform OpVariable " << _.getIdName(inst->id()) << " has illegal type.\n" @@ -588,7 +625,8 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } if (storage_class == spv::StorageClass::StorageBuffer) { - if (!IsAllowedTypeOrArrayOfSame(_, pointee, {spv::Op::OpTypeStruct})) { + if (pointee && + !IsAllowedTypeOrArrayOfSame(_, pointee, {spv::Op::OpTypeStruct})) { return _.diag(SPV_ERROR_INVALID_ID, inst) << _.VkErrorID(6807) << "StorageBuffer OpVariable " << _.getIdName(inst->id()) << " has illegal type.\n" @@ -621,11 +659,17 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } } } + } - // Initializers in Vulkan are only allowed in some storage clases - if (inst->operands().size() > 3) { + // Vulkan Appendix A: Check that if contains initializer, then + // storage class is Output, Private, or Function. + if (inst->operands().size() > initializer_index && + storage_class != spv::StorageClass::Output && + storage_class != spv::StorageClass::Private && + storage_class != spv::StorageClass::Function) { + if (spvIsVulkanEnv(_.context()->target_env)) { if (storage_class == spv::StorageClass::Workgroup) { - auto init_id = inst->GetOperandAs(3); + auto init_id = inst->GetOperandAs(initializer_index); auto init = _.FindDef(init_id); if (init->opcode() != spv::Op::OpConstantNull) { return _.diag(SPV_ERROR_INVALID_ID, inst) @@ -652,7 +696,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } } - if (inst->operands().size() > 3) { + if (initializer_index < inst->operands().size()) { if (storage_class == spv::StorageClass::TaskPayloadWorkgroupEXT) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpVariable, " << _.getIdName(inst->id()) @@ -676,10 +720,10 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } auto pointee_base = pointee; - while (pointee_base->opcode() == spv::Op::OpTypeArray) { + while (pointee_base && pointee_base->opcode() == spv::Op::OpTypeArray) { pointee_base = _.FindDef(pointee_base->GetOperandAs(1u)); } - if (pointee_base->opcode() == spv::Op::OpTypePointer) { + if (pointee_base && pointee_base->opcode() == spv::Op::OpTypePointer) { if (pointee_base->GetOperandAs(1u) == spv::StorageClass::PhysicalStorageBuffer) { // check for AliasedPointer/RestrictPointer @@ -769,7 +813,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { // Cooperative matrix types can only be allocated in Function or Private if ((storage_class != spv::StorageClass::Function && storage_class != spv::StorageClass::Private) && - ContainsCooperativeMatrix(_, pointee)) { + pointee && ContainsCooperativeMatrix(_, pointee)) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Cooperative matrix types (or types containing them) can only be " "allocated " @@ -785,7 +829,8 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { (!_.HasCapability(spv::Capability::Float16) && _.ContainsSizedIntOrFloatType(value_id, spv::Op::OpTypeFloat, 16))) { auto underlying_type = value_type; - while (underlying_type->opcode() == spv::Op::OpTypePointer) { + while (underlying_type && + underlying_type->opcode() == spv::Op::OpTypePointer) { storage_class = underlying_type->GetOperandAs(1u); underlying_type = _.FindDef(underlying_type->GetOperandAs(2u)); @@ -801,7 +846,8 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } break; case spv::StorageClass::Uniform: - if (!_.HasCapability( + if (underlying_type && + !_.HasCapability( spv::Capability::UniformAndStorageBuffer16BitAccess)) { if (underlying_type->opcode() == spv::Op::OpTypeArray || underlying_type->opcode() == spv::Op::OpTypeRuntimeArray) { @@ -849,7 +895,8 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { if (!_.HasCapability(spv::Capability::Int8) && _.ContainsSizedIntOrFloatType(value_id, spv::Op::OpTypeInt, 8)) { auto underlying_type = value_type; - while (underlying_type->opcode() == spv::Op::OpTypePointer) { + while (underlying_type && + underlying_type->opcode() == spv::Op::OpTypePointer) { storage_class = underlying_type->GetOperandAs(1u); underlying_type = _.FindDef(underlying_type->GetOperandAs(2u)); @@ -865,7 +912,8 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } break; case spv::StorageClass::Uniform: - if (!_.HasCapability( + if (underlying_type && + !_.HasCapability( spv::Capability::UniformAndStorageBuffer8BitAccess)) { if (underlying_type->opcode() == spv::Op::OpTypeArray || underlying_type->opcode() == spv::Op::OpTypeRuntimeArray) { @@ -930,21 +978,23 @@ spv_result_t ValidateLoad(ValidationState_t& _, const Instruction* inst) { } const auto pointer_type = _.FindDef(pointer->type_id()); - if (!pointer_type || pointer_type->opcode() != spv::Op::OpTypePointer) { + if (!pointer_type || + (pointer_type->opcode() != spv::Op::OpTypePointer && + pointer_type->opcode() != spv::Op::OpTypeUntypedPointerKHR)) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpLoad type for pointer " << _.getIdName(pointer_id) << " is not a pointer type."; } - uint32_t pointee_data_type; - spv::StorageClass storage_class; - if (!_.GetPointerTypeInfo(pointer_type->id(), &pointee_data_type, - &storage_class) || - result_type->id() != pointee_data_type) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpLoad Result Type " << _.getIdName(inst->type_id()) - << " does not match Pointer " << _.getIdName(pointer->id()) - << "s type."; + if (pointer_type->opcode() == spv::Op::OpTypePointer) { + const auto pointee_type = + _.FindDef(pointer_type->GetOperandAs(2)); + if (!pointee_type || result_type->id() != pointee_type->id()) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpLoad Result Type " << _.getIdName(inst->type_id()) + << " does not match Pointer " << _.getIdName(pointer->id()) + << "s type."; + } } if (!_.options()->before_hlsl_legalization && @@ -987,17 +1037,23 @@ spv_result_t ValidateStore(ValidationState_t& _, const Instruction* inst) { << " is not a logical pointer."; } const auto pointer_type = _.FindDef(pointer->type_id()); - if (!pointer_type || pointer_type->opcode() != spv::Op::OpTypePointer) { + if (!pointer_type || + (pointer_type->opcode() != spv::Op::OpTypePointer && + pointer_type->opcode() != spv::Op::OpTypeUntypedPointerKHR)) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpStore type for pointer " << _.getIdName(pointer_id) << " is not a pointer type."; } - const auto type_id = pointer_type->GetOperandAs(2); - const auto type = _.FindDef(type_id); - if (!type || spv::Op::OpTypeVoid == type->opcode()) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "OpStore Pointer " << _.getIdName(pointer_id) - << "s type is void."; + + Instruction* type = nullptr; + if (pointer_type->opcode() == spv::Op::OpTypePointer) { + const auto type_id = pointer_type->GetOperandAs(2); + type = _.FindDef(type_id); + if (!type || spv::Op::OpTypeVoid == type->opcode()) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpStore Pointer " << _.getIdName(pointer_id) + << "s type is void."; + } } // validate storage class @@ -1074,7 +1130,7 @@ spv_result_t ValidateStore(ValidationState_t& _, const Instruction* inst) { << "s type is void."; } - if (type->id() != object_type->id()) { + if (type && (type->id() != object_type->id())) { if (!_.options()->relax_struct_store || type->opcode() != spv::Op::OpTypeStruct || object_type->opcode() != spv::Op::OpTypeStruct) { @@ -1179,7 +1235,8 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction* inst) { const auto target_pointer_type = _.FindDef(target->type_id()); if (!target_pointer_type || - target_pointer_type->opcode() != spv::Op::OpTypePointer) { + (target_pointer_type->opcode() != spv::Op::OpTypePointer && + target_pointer_type->opcode() != spv::Op::OpTypeUntypedPointerKHR)) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Target operand " << _.getIdName(target_id) << " is not a pointer."; @@ -1187,35 +1244,52 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction* inst) { const auto source_pointer_type = _.FindDef(source->type_id()); if (!source_pointer_type || - source_pointer_type->opcode() != spv::Op::OpTypePointer) { + (source_pointer_type->opcode() != spv::Op::OpTypePointer && + source_pointer_type->opcode() != spv::Op::OpTypeUntypedPointerKHR)) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Source operand " << _.getIdName(source_id) << " is not a pointer."; } if (inst->opcode() == spv::Op::OpCopyMemory) { - const auto target_type = - _.FindDef(target_pointer_type->GetOperandAs(2)); - if (!target_type || target_type->opcode() == spv::Op::OpTypeVoid) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "Target operand " << _.getIdName(target_id) - << " cannot be a void pointer."; + const bool target_typed = + target_pointer_type->opcode() == spv::Op::OpTypePointer; + const bool source_typed = + source_pointer_type->opcode() == spv::Op::OpTypePointer; + Instruction* target_type = nullptr; + Instruction* source_type = nullptr; + if (target_typed) { + target_type = _.FindDef(target_pointer_type->GetOperandAs(2)); + + if (!target_type || target_type->opcode() == spv::Op::OpTypeVoid) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Target operand " << _.getIdName(target_id) + << " cannot be a void pointer."; + } } - const auto source_type = - _.FindDef(source_pointer_type->GetOperandAs(2)); - if (!source_type || source_type->opcode() == spv::Op::OpTypeVoid) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "Source operand " << _.getIdName(source_id) - << " cannot be a void pointer."; + if (source_typed) { + source_type = _.FindDef(source_pointer_type->GetOperandAs(2)); + if (!source_type || source_type->opcode() == spv::Op::OpTypeVoid) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Source operand " << _.getIdName(source_id) + << " cannot be a void pointer."; + } } - if (target_type->id() != source_type->id()) { + if (target_type && source_type && target_type->id() != source_type->id()) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Target " << _.getIdName(source_id) << "s type does not match Source " << _.getIdName(source_type->id()) << "s type."; } + + if (!target_type && !source_type) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "One of Source or Target must be a typed pointer"; + } + + if (auto error = CheckMemoryAccess(_, inst, 2)) return error; } else { const auto size_id = inst->GetOperandAs(2); const auto size = _.FindDef(size_id); @@ -1231,7 +1305,6 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction* inst) { << "Size operand " << _.getIdName(size_id) << " must be a scalar integer type."; } - bool is_zero = true; switch (size->opcode()) { case spv::Op::OpConstantNull: @@ -1258,18 +1331,125 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction* inst) { // Cannot infer any other opcodes. break; } + + if (_.HasCapability(spv::Capability::Shader)) { + bool is_int = false; + bool is_const = false; + uint32_t value = 0; + std::tie(is_int, is_const, value) = _.EvalInt32IfConst(size_id); + if (is_const) { + if (value % 4 != 0) { + const auto source_sc = + source_pointer_type->GetOperandAs(1); + const auto target_sc = + target_pointer_type->GetOperandAs(1); + const bool int8 = _.HasCapability(spv::Capability::Int8); + const bool ubo_int8 = _.HasCapability( + spv::Capability::UniformAndStorageBuffer8BitAccess); + const bool ssbo_int8 = + _.HasCapability(spv::Capability::StorageBuffer8BitAccess) || + ubo_int8; + const bool pc_int8 = + _.HasCapability(spv::Capability::StoragePushConstant8); + const bool wg_int8 = _.HasCapability( + spv::Capability::WorkgroupMemoryExplicitLayout8BitAccessKHR); + const bool int16 = _.HasCapability(spv::Capability::Int16) || int8; + const bool ubo_int16 = + _.HasCapability( + spv::Capability::UniformAndStorageBuffer16BitAccess) || + ubo_int8; + const bool ssbo_int16 = + _.HasCapability(spv::Capability::StorageBuffer16BitAccess) || + ubo_int16 || ssbo_int8; + const bool pc_int16 = + _.HasCapability(spv::Capability::StoragePushConstant16) || + pc_int8; + const bool io_int16 = + _.HasCapability(spv::Capability::StorageInputOutput16); + const bool wg_int16 = _.HasCapability( + spv::Capability::WorkgroupMemoryExplicitLayout16BitAccessKHR); + + bool source_int16_match = false; + bool target_int16_match = false; + bool source_int8_match = false; + bool target_int8_match = false; + switch (source_sc) { + case spv::StorageClass::StorageBuffer: + source_int16_match = ssbo_int16; + source_int8_match = ssbo_int8; + break; + case spv::StorageClass::Uniform: + source_int16_match = ubo_int16; + source_int8_match = ubo_int8; + break; + case spv::StorageClass::PushConstant: + source_int16_match = pc_int16; + source_int8_match = pc_int8; + break; + case spv::StorageClass::Input: + case spv::StorageClass::Output: + source_int16_match = io_int16; + break; + case spv::StorageClass::Workgroup: + source_int16_match = wg_int16; + source_int8_match = wg_int8; + break; + default: + break; + } + switch (target_sc) { + case spv::StorageClass::StorageBuffer: + target_int16_match = ssbo_int16; + target_int8_match = ssbo_int8; + break; + case spv::StorageClass::Uniform: + target_int16_match = ubo_int16; + target_int8_match = ubo_int8; + break; + case spv::StorageClass::PushConstant: + target_int16_match = pc_int16; + target_int8_match = pc_int8; + break; + // Input is read-only so it cannot be the target pointer. + case spv::StorageClass::Output: + target_int16_match = io_int16; + break; + case spv::StorageClass::Workgroup: + target_int16_match = wg_int16; + target_int8_match = wg_int8; + break; + default: + break; + } + if (!int8 && !int16 && !(source_int16_match && target_int16_match)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Size must be a multiple of 4"; + } + if (value % 2 != 0) { + if (!int8 && !(source_int8_match && target_int8_match)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Size must be a multiple of 2"; + } + } + } + } + } + + if (auto error = CheckMemoryAccess(_, inst, 3)) return error; } if (auto error = ValidateCopyMemoryMemoryAccess(_, inst)) return error; // Get past the pointers to avoid checking a pointer copy. - auto sub_type = _.FindDef(target_pointer_type->GetOperandAs(2)); - while (sub_type->opcode() == spv::Op::OpTypePointer) { - sub_type = _.FindDef(sub_type->GetOperandAs(2)); - } - if (_.HasCapability(spv::Capability::Shader) && - _.ContainsLimitedUseIntOrFloatType(sub_type->id())) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "Cannot copy memory of objects containing 8- or 16-bit types"; + if (target_pointer_type->opcode() == spv::Op::OpTypePointer) { + auto sub_type = _.FindDef(target_pointer_type->GetOperandAs(2)); + while (sub_type->opcode() == spv::Op::OpTypePointer) { + sub_type = _.FindDef(sub_type->GetOperandAs(2)); + } + if (_.HasCapability(spv::Capability::Shader) && + _.ContainsLimitedUseIntOrFloatType(sub_type->id())) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Cannot copy memory of objects containing 8- or 16-bit types"; + } } return SPV_SUCCESS; @@ -1280,27 +1460,50 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, std::string instr_name = "Op" + std::string(spvOpcodeString(static_cast(inst->opcode()))); - // The result type must be OpTypePointer. + const bool untyped_pointer = spvOpcodeGeneratesUntypedPointer(inst->opcode()); + + // The result type must be OpTypePointer for regular access chains and an + // OpTypeUntypedPointerKHR for untyped access chains. auto result_type = _.FindDef(inst->type_id()); - if (spv::Op::OpTypePointer != result_type->opcode()) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << "The Result Type of " << instr_name << " " - << _.getIdName(inst->id()) << " must be OpTypePointer. Found Op" - << spvOpcodeString(static_cast(result_type->opcode())) - << "."; + if (untyped_pointer) { + if (!result_type || + spv::Op::OpTypeUntypedPointerKHR != result_type->opcode()) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "The Result Type of " << instr_name << " " + << _.getIdName(inst->id()) + << " must be OpTypeUntypedPointerKHR. Found Op" + << spvOpcodeString(static_cast(result_type->opcode())) + << "."; + } + } else { + if (!result_type || spv::Op::OpTypePointer != result_type->opcode()) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "The Result Type of " << instr_name << " " + << _.getIdName(inst->id()) << " must be OpTypePointer. Found Op" + << spvOpcodeString(static_cast(result_type->opcode())) + << "."; + } } - // Result type is a pointer. Find out what it's pointing to. - // This will be used to make sure the indexing results in the same type. - // OpTypePointer word 3 is the type being pointed to. - const auto result_type_pointee = _.FindDef(result_type->word(3)); + if (untyped_pointer) { + // Base type must be a non-pointer type. + const auto base_type = _.FindDef(inst->GetOperandAs(2)); + if (!base_type || !spvOpcodeGeneratesType(base_type->opcode()) || + base_type->opcode() == spv::Op::OpTypePointer || + base_type->opcode() == spv::Op::OpTypeUntypedPointerKHR) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Base type must be a non-pointer type"; + } + } // Base must be a pointer, pointing to the base of a composite object. - const auto base_index = 2; + const auto base_index = untyped_pointer ? 3 : 2; const auto base_id = inst->GetOperandAs(base_index); const auto base = _.FindDef(base_id); const auto base_type = _.FindDef(base->type_id()); - if (!base_type || spv::Op::OpTypePointer != base_type->opcode()) { + if (!base_type || !(spv::Op::OpTypePointer == base_type->opcode() || + (untyped_pointer && spv::Op::OpTypeUntypedPointerKHR == + base_type->opcode()))) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "The Base " << _.getIdName(base_id) << " in " << instr_name << " instruction must be a pointer."; @@ -1318,14 +1521,18 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, } // The type pointed to by OpTypePointer (word 3) must be a composite type. - auto type_pointee = _.FindDef(base_type->word(3)); + auto type_pointee = untyped_pointer + ? _.FindDef(inst->GetOperandAs(2)) + : _.FindDef(base_type->word(3)); // Check Universal Limit (SPIR-V Spec. Section 2.17). // The number of indexes passed to OpAccessChain may not exceed 255 // The instruction includes 4 words + N words (for N indexes) size_t num_indexes = inst->words().size() - 4; if (inst->opcode() == spv::Op::OpPtrAccessChain || - inst->opcode() == spv::Op::OpInBoundsPtrAccessChain) { + inst->opcode() == spv::Op::OpInBoundsPtrAccessChain || + inst->opcode() == spv::Op::OpUntypedPtrAccessChainKHR || + inst->opcode() == spv::Op::OpUntypedInBoundsPtrAccessChainKHR) { // In pointer access chains, the element operand is required, but not // counted as an index. --num_indexes; @@ -1344,9 +1551,11 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, // instruction. The second index will apply similarly to that result, and so // on. Once any non-composite type is reached, there must be no remaining // (unused) indexes. - auto starting_index = 4; + auto starting_index = untyped_pointer ? 5 : 4; if (inst->opcode() == spv::Op::OpPtrAccessChain || - inst->opcode() == spv::Op::OpInBoundsPtrAccessChain) { + inst->opcode() == spv::Op::OpInBoundsPtrAccessChain || + inst->opcode() == spv::Op::OpUntypedPtrAccessChainKHR || + inst->opcode() == spv::Op::OpUntypedInBoundsPtrAccessChainKHR) { ++starting_index; } for (size_t i = starting_index; i < inst->words().size(); ++i) { @@ -1411,18 +1620,25 @@ spv_result_t ValidateAccessChain(ValidationState_t& _, } } } - // At this point, we have fully walked down from the base using the indices. - // The type being pointed to should be the same as the result type. - if (type_pointee->id() != result_type_pointee->id()) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << instr_name << " result type (Op" - << spvOpcodeString( - static_cast(result_type_pointee->opcode())) - << ") does not match the type that results from indexing into the " - "base " - " (Op" - << spvOpcodeString(static_cast(type_pointee->opcode())) - << ")."; + + if (!untyped_pointer) { + // Result type is a pointer. Find out what it's pointing to. + // This will be used to make sure the indexing results in the same type. + // OpTypePointer word 3 is the type being pointed to. + const auto result_type_pointee = _.FindDef(result_type->word(3)); + // At this point, we have fully walked down from the base using the indeces. + // The type being pointed to should be the same as the result type. + if (type_pointee->id() != result_type_pointee->id()) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << instr_name << " result type (Op" + << spvOpcodeString( + static_cast(result_type_pointee->opcode())) + << ") does not match the type that results from indexing into the " + "base " + " (Op" + << spvOpcodeString(static_cast(type_pointee->opcode())) + << ")."; + } } return SPV_SUCCESS; @@ -1550,7 +1766,8 @@ spv_result_t ValidateRawAccessChain(ValidationState_t& _, spv_result_t ValidatePtrAccessChain(ValidationState_t& _, const Instruction* inst) { - if (_.addressing_model() == spv::AddressingModel::Logical) { + if (_.addressing_model() == spv::AddressingModel::Logical && + inst->opcode() == spv::Op::OpPtrAccessChain) { if (!_.features().variable_pointers) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Generating variable pointers requires capability " @@ -1561,9 +1778,13 @@ spv_result_t ValidatePtrAccessChain(ValidationState_t& _, // Need to call first, will make sure Base is a valid ID if (auto error = ValidateAccessChain(_, inst)) return error; + const bool untyped_pointer = spvOpcodeGeneratesUntypedPointer(inst->opcode()); + const auto base_id = inst->GetOperandAs(2); const auto base = _.FindDef(base_id); - const auto base_type = _.FindDef(base->type_id()); + const auto base_type = untyped_pointer + ? _.FindDef(inst->GetOperandAs(2)) + : _.FindDef(base->type_id()); const auto base_type_storage_class = base_type->GetOperandAs(1); @@ -1581,15 +1802,17 @@ spv_result_t ValidatePtrAccessChain(ValidationState_t& _, } if (spvIsVulkanEnv(_.context()->target_env)) { + const auto untyped_cap = + untyped_pointer && _.HasCapability(spv::Capability::UntypedPointersKHR); if (base_type_storage_class == spv::StorageClass::Workgroup) { - if (!_.HasCapability(spv::Capability::VariablePointers)) { + if (!_.HasCapability(spv::Capability::VariablePointers) && !untyped_cap) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << _.VkErrorID(7651) << "OpPtrAccessChain Base operand pointing to Workgroup " "storage class must use VariablePointers capability"; } } else if (base_type_storage_class == spv::StorageClass::StorageBuffer) { - if (!_.features().variable_pointers) { + if (!_.features().variable_pointers && !untyped_cap) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << _.VkErrorID(7652) << "OpPtrAccessChain Base operand pointing to StorageBuffer " @@ -1597,7 +1820,8 @@ spv_result_t ValidatePtrAccessChain(ValidationState_t& _, "VariablePointersStorageBuffer capability"; } } else if (base_type_storage_class != - spv::StorageClass::PhysicalStorageBuffer) { + spv::StorageClass::PhysicalStorageBuffer && + !untyped_cap) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << _.VkErrorID(7650) << "OpPtrAccessChain Base operand must point to Workgroup, " @@ -1624,18 +1848,28 @@ spv_result_t ValidateArrayLength(ValidationState_t& state, << " must be OpTypeInt with width 32 and signedness 0."; } - // The structure that is passed in must be an pointer to a structure, whose - // last element is a runtime array. - auto pointer = state.FindDef(inst->GetOperandAs(2)); - auto pointer_type = state.FindDef(pointer->type_id()); - if (pointer_type->opcode() != spv::Op::OpTypePointer) { + const bool untyped = inst->opcode() == spv::Op::OpUntypedArrayLengthKHR; + auto pointer_ty_id = state.GetOperandTypeId(inst, (untyped ? 3 : 2)); + auto pointer_ty = state.FindDef(pointer_ty_id); + if (untyped) { + if (pointer_ty->opcode() != spv::Op::OpTypeUntypedPointerKHR) { + return state.diag(SPV_ERROR_INVALID_ID, inst) + << "Pointer must be an untyped pointer"; + } + } else if (pointer_ty->opcode() != spv::Op::OpTypePointer) { return state.diag(SPV_ERROR_INVALID_ID, inst) << "The Structure's type in " << instr_name << " " << state.getIdName(inst->id()) << " must be a pointer to an OpTypeStruct."; } - auto structure_type = state.FindDef(pointer_type->GetOperandAs(2)); + Instruction* structure_type = nullptr; + if (untyped) { + structure_type = state.FindDef(inst->GetOperandAs(2)); + } else { + structure_type = state.FindDef(pointer_ty->GetOperandAs(2)); + } + if (structure_type->opcode() != spv::Op::OpTypeStruct) { return state.diag(SPV_ERROR_INVALID_ID, inst) << "The Structure's type in " << instr_name << " " @@ -1654,11 +1888,12 @@ spv_result_t ValidateArrayLength(ValidationState_t& state, // The array member must the index of the last element (the run time // array). - if (inst->GetOperandAs(3) != num_of_members - 1) { + const auto index = untyped ? 4 : 3; + if (inst->GetOperandAs(index) != num_of_members - 1) { return state.diag(SPV_ERROR_INVALID_ID, inst) << "The array member in " << instr_name << " " << state.getIdName(inst->id()) - << " must be an the last member of the struct."; + << " must be the last member of the struct."; } return SPV_SUCCESS; } @@ -1843,12 +2078,16 @@ spv_result_t ValidateCooperativeMatrixLoadStoreKHR(ValidationState_t& _, const auto pointer_type_id = pointer->type_id(); const auto pointer_type = _.FindDef(pointer_type_id); - if (!pointer_type || pointer_type->opcode() != spv::Op::OpTypePointer) { + if (!pointer_type || + !(pointer_type->opcode() == spv::Op::OpTypePointer || + pointer_type->opcode() == spv::Op::OpTypeUntypedPointerKHR)) { return _.diag(SPV_ERROR_INVALID_ID, inst) << opname << " type for pointer " << _.getIdName(pointer_id) << " is not a pointer type."; } + const bool untyped = + pointer_type->opcode() == spv::Op::OpTypeUntypedPointerKHR; const auto storage_class_index = 1u; const auto storage_class = pointer_type->GetOperandAs(storage_class_index); @@ -1863,13 +2102,15 @@ spv_result_t ValidateCooperativeMatrixLoadStoreKHR(ValidationState_t& _, << " is not Workgroup, StorageBuffer, or PhysicalStorageBuffer."; } - const auto pointee_id = pointer_type->GetOperandAs(2); - const auto pointee_type = _.FindDef(pointee_id); - if (!pointee_type || !(_.IsIntScalarOrVectorType(pointee_id) || - _.IsFloatScalarOrVectorType(pointee_id))) { - return _.diag(SPV_ERROR_INVALID_ID, inst) - << opname << " Pointer " << _.getIdName(pointer->id()) - << "s Type must be a scalar or vector type."; + if (!untyped) { + const auto pointee_id = pointer_type->GetOperandAs(2); + const auto pointee_type = _.FindDef(pointee_id); + if (!pointee_type || !(_.IsIntScalarOrVectorType(pointee_id) || + _.IsFloatScalarOrVectorType(pointee_id))) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << opname << " Pointer " << _.getIdName(pointer->id()) + << "s Type must be a scalar or vector type."; + } } const auto layout_index = @@ -1935,7 +2176,8 @@ spv_result_t ValidatePtrComparison(ValidationState_t& _, << "The types of Operand 1 and Operand 2 must match"; } const auto op1_type = _.FindDef(op1->type_id()); - if (!op1_type || op1_type->opcode() != spv::Op::OpTypePointer) { + if (!op1_type || (op1_type->opcode() != spv::Op::OpTypePointer && + op1_type->opcode() != spv::Op::OpTypeUntypedPointerKHR)) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Operand type must be a pointer"; } @@ -1967,6 +2209,7 @@ spv_result_t ValidatePtrComparison(ValidationState_t& _, spv_result_t MemoryPass(ValidationState_t& _, const Instruction* inst) { switch (inst->opcode()) { case spv::Op::OpVariable: + case spv::Op::OpUntypedVariableKHR: if (auto error = ValidateVariable(_, inst)) return error; break; case spv::Op::OpLoad: @@ -1980,17 +2223,22 @@ spv_result_t MemoryPass(ValidationState_t& _, const Instruction* inst) { if (auto error = ValidateCopyMemory(_, inst)) return error; break; case spv::Op::OpPtrAccessChain: + case spv::Op::OpUntypedPtrAccessChainKHR: + case spv::Op::OpUntypedInBoundsPtrAccessChainKHR: if (auto error = ValidatePtrAccessChain(_, inst)) return error; break; case spv::Op::OpAccessChain: case spv::Op::OpInBoundsAccessChain: case spv::Op::OpInBoundsPtrAccessChain: + case spv::Op::OpUntypedAccessChainKHR: + case spv::Op::OpUntypedInBoundsAccessChainKHR: if (auto error = ValidateAccessChain(_, inst)) return error; break; case spv::Op::OpRawAccessChainNV: if (auto error = ValidateRawAccessChain(_, inst)) return error; break; case spv::Op::OpArrayLength: + case spv::Op::OpUntypedArrayLengthKHR: if (auto error = ValidateArrayLength(_, inst)) return error; break; case spv::Op::OpCooperativeMatrixLoadNV: diff --git a/source/val/validate_type.cpp b/source/val/validate_type.cpp index cb26a527cc..32024b7356 100644 --- a/source/val/validate_type.cpp +++ b/source/val/validate_type.cpp @@ -36,6 +36,7 @@ spv_result_t ValidateUniqueness(ValidationState_t& _, const Instruction* inst) { const auto opcode = inst->opcode(); if (opcode != spv::Op::OpTypeArray && opcode != spv::Op::OpTypeRuntimeArray && opcode != spv::Op::OpTypeStruct && opcode != spv::Op::OpTypePointer && + opcode != spv::Op::OpTypeUntypedPointerKHR && !_.RegisterUniqueTypeDeclaration(inst)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Duplicate non-aggregate type declarations are not allowed. " @@ -583,6 +584,33 @@ spv_result_t ValidateTypeCooperativeMatrix(ValidationState_t& _, return SPV_SUCCESS; } + +spv_result_t ValidateTypeUntypedPointerKHR(ValidationState_t& _, + const Instruction* inst) { + if (spvIsVulkanEnv(_.context()->target_env)) { + const auto sc = inst->GetOperandAs(1); + switch (sc) { + case spv::StorageClass::Workgroup: + if (!_.HasCapability( + spv::Capability::WorkgroupMemoryExplicitLayoutKHR)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "Workgroup storage class untyped pointers in Vulkan " + "require WorkgroupMemoryExplicitLayoutKHR be declared"; + } + break; + case spv::StorageClass::StorageBuffer: + case spv::StorageClass::PhysicalStorageBuffer: + case spv::StorageClass::Uniform: + case spv::StorageClass::PushConstant: + break; + default: + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "In Vulkan, untyped pointers can only be used in an " + "explicitly laid out storage class"; + } + } + return SPV_SUCCESS; +} } // namespace spv_result_t TypePass(ValidationState_t& _, const Instruction* inst) { @@ -628,6 +656,9 @@ spv_result_t TypePass(ValidationState_t& _, const Instruction* inst) { case spv::Op::OpTypeCooperativeMatrixKHR: if (auto error = ValidateTypeCooperativeMatrix(_, inst)) return error; break; + case spv::Op::OpTypeUntypedPointerKHR: + if (auto error = ValidateTypeUntypedPointerKHR(_, inst)) return error; + break; default: break; } diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp index 1b5954ac54..6f425310ce 100644 --- a/source/val/validation_state.cpp +++ b/source/val/validation_state.cpp @@ -73,6 +73,7 @@ ModuleLayoutSection InstructionLayoutSection( case spv::Op::OpTypeForwardPointer: return kLayoutTypes; case spv::Op::OpVariable: + case spv::Op::OpUntypedVariableKHR: if (current_section == kLayoutTypes) return kLayoutTypes; return kLayoutFunctionDefinitions; case spv::Op::OpExtInst: @@ -1185,7 +1186,9 @@ bool ValidationState_t::GetStructMemberTypes( bool ValidationState_t::IsPointerType(uint32_t id) const { const Instruction* inst = FindDef(id); - return inst && inst->opcode() == spv::Op::OpTypePointer; + assert(inst); + return inst->opcode() == spv::Op::OpTypePointer || + inst->opcode() == spv::Op::OpTypeUntypedPointerKHR; } bool ValidationState_t::GetPointerTypeInfo( @@ -1195,6 +1198,12 @@ bool ValidationState_t::GetPointerTypeInfo( const Instruction* inst = FindDef(id); assert(inst); + if (inst->opcode() == spv::Op::OpTypeUntypedPointerKHR) { + *storage_class = spv::StorageClass(inst->word(2)); + *data_type = 0; + return true; + } + if (inst->opcode() != spv::Op::OpTypePointer) return false; *storage_class = spv::StorageClass(inst->word(2)); @@ -1705,6 +1714,39 @@ bool ValidationState_t::ContainsRuntimeArray(uint32_t id) const { return ContainsType(id, f, /* traverse_all_types = */ false); } +bool ValidationState_t::ContainsUntypedPointer(uint32_t id) const { + const auto inst = FindDef(id); + if (!inst) return false; + if (!spvOpcodeGeneratesType(inst->opcode())) return false; + if (inst->opcode() == spv::Op::OpTypeUntypedPointerKHR) return true; + + switch (inst->opcode()) { + case spv::Op::OpTypeArray: + case spv::Op::OpTypeRuntimeArray: + case spv::Op::OpTypeVector: + case spv::Op::OpTypeMatrix: + case spv::Op::OpTypeImage: + case spv::Op::OpTypeSampledImage: + case spv::Op::OpTypeCooperativeMatrixNV: + return ContainsUntypedPointer(inst->GetOperandAs(1u)); + case spv::Op::OpTypePointer: + if (IsForwardPointer(id)) return false; + return ContainsUntypedPointer(inst->GetOperandAs(2u)); + case spv::Op::OpTypeFunction: + case spv::Op::OpTypeStruct: { + for (uint32_t i = 1; i < inst->operands().size(); ++i) { + if (ContainsUntypedPointer(inst->GetOperandAs(i))) + return true; + } + return false; + } + default: + return false; + } + + return false; +} + bool ValidationState_t::IsValidStorageClass( spv::StorageClass storage_class) const { if (spvIsVulkanEnv(context()->target_env)) { diff --git a/source/val/validation_state.h b/source/val/validation_state.h index 2864755891..372b5b7b9f 100644 --- a/source/val/validation_state.h +++ b/source/val/validation_state.h @@ -649,6 +649,9 @@ class ValidationState_t { const std::function& f, bool traverse_all_types = true) const; + // Returns true if |id| is type id that contains an untyped pointer. + bool ContainsUntypedPointer(uint32_t id) const; + // Returns type_id if id has type or zero otherwise. uint32_t GetTypeId(uint32_t id) const; diff --git a/test/opcode_require_capabilities_test.cpp b/test/opcode_require_capabilities_test.cpp index 37097c6ff2..615c09429e 100644 --- a/test/opcode_require_capabilities_test.cpp +++ b/test/opcode_require_capabilities_test.cpp @@ -61,8 +61,33 @@ INSTANTIATE_TEST_SUITE_P( ExpectedOpCodeCapabilities{ spv::Op::OpImageSparseSampleImplicitLod, CapabilitySet{spv::Capability::SparseResidency}}, - ExpectedOpCodeCapabilities{spv::Op::OpCopyMemorySized, - CapabilitySet{spv::Capability::Addresses}}, + ExpectedOpCodeCapabilities{ + spv::Op::OpCopyMemorySized, + CapabilitySet{spv::Capability::Addresses, + spv::Capability::UntypedPointersKHR}}, + ExpectedOpCodeCapabilities{spv::Op::OpArrayLength, + CapabilitySet{spv::Capability::Shader}}, + ExpectedOpCodeCapabilities{spv::Op::OpFunction, CapabilitySet()}, + ExpectedOpCodeCapabilities{spv::Op::OpConvertFToS, CapabilitySet()}, + ExpectedOpCodeCapabilities{ + spv::Op::OpEmitStreamVertex, + CapabilitySet{spv::Capability::GeometryStreams}}, + ExpectedOpCodeCapabilities{ + spv::Op::OpTypeNamedBarrier, + CapabilitySet{spv::Capability::NamedBarrier}}, + ExpectedOpCodeCapabilities{ + spv::Op::OpGetKernelMaxNumSubgroups, + CapabilitySet{spv::Capability::SubgroupDispatch}}, + ExpectedOpCodeCapabilities{spv::Op::OpImageQuerySamples, + CapabilitySet{spv::Capability::Kernel, + spv::Capability::ImageQuery}}, + ExpectedOpCodeCapabilities{ + spv::Op::OpImageSparseSampleImplicitLod, + CapabilitySet{spv::Capability::SparseResidency}}, + ExpectedOpCodeCapabilities{ + spv::Op::OpCopyMemorySized, + CapabilitySet{spv::Capability::Addresses, + spv::Capability::UntypedPointersKHR}}, ExpectedOpCodeCapabilities{spv::Op::OpArrayLength, CapabilitySet{spv::Capability::Shader}}, ExpectedOpCodeCapabilities{spv::Op::OpFunction, CapabilitySet()}, diff --git a/test/text_to_binary.extension_test.cpp b/test/text_to_binary.extension_test.cpp index 2efd27b49a..59f2af9e79 100644 --- a/test/text_to_binary.extension_test.cpp +++ b/test/text_to_binary.extension_test.cpp @@ -1327,5 +1327,54 @@ INSTANTIATE_TEST_SUITE_P( {1, 2, 3})}, }))); +// SPV_KHR_untyped_pointers +INSTANTIATE_TEST_SUITE_P( + SPV_KHR_untyped_pointers, ExtensionRoundTripTest, + Combine( + Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0, + SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_2), + ValuesIn(std::vector{ + {"OpExtension \"SPV_KHR_untyped_pointers\"\n", + MakeInstruction(spv::Op::OpExtension, + MakeVector("SPV_KHR_untyped_pointers"))}, + {"OpCapability UntypedPointersKHR\n", + MakeInstruction(spv::Op::OpCapability, + {(int)spv::Capability::UntypedPointersKHR})}, + {"OpCapability UntypedPointersKHR\n", + MakeInstruction(spv::Op::OpCapability, {4473})}, + {"%1 = OpTypeUntypedPointerKHR Workgroup\n", + MakeInstruction(spv::Op::OpTypeUntypedPointerKHR, + {1, int(spv::StorageClass::Workgroup)})}, + {"%2 = OpUntypedVariableKHR %1 Workgroup %3\n", + MakeInstruction(spv::Op::OpUntypedVariableKHR, + {1, 2, int(spv::StorageClass::Workgroup), 3})}, + {"%2 = OpUntypedVariableKHR %1 Workgroup %3 %4\n", + MakeInstruction(spv::Op::OpUntypedVariableKHR, + {1, 2, int(spv::StorageClass::Workgroup), 3, 4})}, + {"%2 = OpUntypedAccessChainKHR %1 %3 %4\n", + MakeInstruction(spv::Op::OpUntypedAccessChainKHR, {1, 2, 3, 4})}, + {"%2 = OpUntypedAccessChainKHR %1 %3 %4 %5 %6 %7\n", + MakeInstruction(spv::Op::OpUntypedAccessChainKHR, + {1, 2, 3, 4, 5, 6, 7})}, + {"%2 = OpUntypedInBoundsAccessChainKHR %1 %3 %4\n", + MakeInstruction(spv::Op::OpUntypedInBoundsAccessChainKHR, + {1, 2, 3, 4})}, + {"%2 = OpUntypedInBoundsAccessChainKHR %1 %3 %4 %5 %6 %7\n", + MakeInstruction(spv::Op::OpUntypedInBoundsAccessChainKHR, + {1, 2, 3, 4, 5, 6, 7})}, + {"%2 = OpUntypedPtrAccessChainKHR %1 %3 %4 %5\n", + MakeInstruction(spv::Op::OpUntypedPtrAccessChainKHR, + {1, 2, 3, 4, 5})}, + {"%2 = OpUntypedPtrAccessChainKHR %1 %3 %4 %5 %6 %7\n", + MakeInstruction(spv::Op::OpUntypedPtrAccessChainKHR, + {1, 2, 3, 4, 5, 6, 7})}, + {"%2 = OpUntypedInBoundsPtrAccessChainKHR %1 %3 %4 %5\n", + MakeInstruction(spv::Op::OpUntypedInBoundsPtrAccessChainKHR, + {1, 2, 3, 4, 5})}, + {"%2 = OpUntypedInBoundsPtrAccessChainKHR %1 %3 %4 %5 %6 %7\n", + MakeInstruction(spv::Op::OpUntypedInBoundsPtrAccessChainKHR, + {1, 2, 3, 4, 5, 6, 7})}, + }))); + } // namespace } // namespace spvtools diff --git a/test/val/val_annotation_test.cpp b/test/val/val_annotation_test.cpp index 97dde2df4a..e65e11f45e 100644 --- a/test/val/val_annotation_test.cpp +++ b/test/val/val_annotation_test.cpp @@ -230,6 +230,33 @@ OpFunctionEnd "FPFastMathMode and NoContraction cannot decorate the same target")); } +TEST_F(DecorationTest, RestrictOnUntypedPointer) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpCapability SampleRateShading +OpCapability TransformFeedback +OpCapability GeometryStreams +OpCapability Tessellation +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpDecorate %param Restrict +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%void = OpTypeVoid +%f_ty = OpTypeFunction %void %ptr +%f = OpFunction %void None %f_ty +%param = OpFunctionParameter %ptr +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + using MemberOnlyDecorations = spvtest::ValidateBase; TEST_P(MemberOnlyDecorations, MemberDecoration) { diff --git a/test/val/val_atomics_test.cpp b/test/val/val_atomics_test.cpp index 0f65634a95..1cec51eb8e 100644 --- a/test/val/val_atomics_test.cpp +++ b/test/val/val_atomics_test.cpp @@ -1142,9 +1142,8 @@ OpAtomicStore %f32_1 %device %relaxed %f32_1 CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("AtomicStore: expected Pointer to be of type OpTypePointer")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("AtomicStore: expected Pointer to be a pointer type")); } TEST_F(ValidateAtomics, AtomicStoreWrongPointerDataType) { @@ -1607,7 +1606,7 @@ TEST_F(ValidateAtomics, AtomicFlagTestAndSetNotPointer) { ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicFlagTestAndSet: " - "expected Pointer to be of type OpTypePointer")); + "expected Pointer to be a pointer type")); } TEST_F(ValidateAtomics, AtomicFlagTestAndSetNotIntPointer) { @@ -1681,7 +1680,7 @@ OpAtomicFlagClear %u32_1 %device %relaxed ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicFlagClear: " - "expected Pointer to be of type OpTypePointer")); + "expected Pointer to be a pointer type")); } TEST_F(ValidateAtomics, AtomicFlagClearNotIntPointer) { @@ -2847,6 +2846,125 @@ TEST_F(ValidateAtomics, AtomicFloat16Vector3ExchangeFail) { "float scalar type")); } +TEST_F(ValidateAtomics, AtomicLoadUntypedPointer) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%load = OpAtomicLoad %int %var %int_1 %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateAtomics, AtomicStoreUntypedPointer) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpAtomicStore %var %int_1 %int_0 %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateAtomics, AtomicExchangeUntypedPointer) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%ex = OpAtomicExchange %int %var %int_1 %int_0 %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateAtomics, AtomicFlagClearUntypedPointer) { + const std::string spirv = R"( +OpCapability Kernel +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical OpenCL +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_1 = OpConstant %int 1 +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Workgroup %int +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpAtomicFlagClear %var %int_1 %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Untyped pointers are not supported by atomic flag instructions")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/test/val/val_conversion_test.cpp b/test/val/val_conversion_test.cpp index 0128aa1f22..748ad64f86 100644 --- a/test/val/val_conversion_test.cpp +++ b/test/val/val_conversion_test.cpp @@ -1940,6 +1940,64 @@ OpExtension "SPV_KHR_ray_query" "uint vector as input")); } +TEST_F(ValidateConversion, BitcastUntypedPointerInput) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VariablePointers +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%cast = OpBitcast %int %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateConversion, BitcastUntypedPointerOutput) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VariablePointers +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Workgroup %int +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%cast = OpBitcast %ptr %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + using ValidateSmallConversions = spvtest::ValidateBase; CodeGenerator GetSmallConversionsCodeGenerator() { diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp index 5aff68787c..19cb12bbfb 100644 --- a/test/val/val_decoration_test.cpp +++ b/test/val/val_decoration_test.cpp @@ -9362,6 +9362,37 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3)); } +TEST_F(ValidateDecorations, UntypedVariableDuplicateInterface) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var %var +OpName %var "var" +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Non-unique OpEntryPoint interface '2[%var]' is disallowed")); +} + TEST_F(ValidateDecorations, PhysicalStorageBufferMissingOffset) { const std::string spirv = R"( OpCapability Shader @@ -9967,6 +9998,372 @@ TEST_F(ValidateDecorations, MultipleBuiltinsBlockMixed) { AnyVUID("VUID-StandaloneSpirv-OpEntryPoint-09659")); } +TEST_F(ValidateDecorations, UntypedVariableWorkgroupRequiresStruct) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Workgroup %int +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Untyped workgroup variables in shaders must be block " + "decorated structs")); +} + +TEST_F(ValidateDecorations, UntypedVariableWorkgroupRequiresBlockStruct) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Untyped workgroup variables in shaders must be block " + "decorated")); +} + +TEST_F(ValidateDecorations, UntypedVariableStorageBufferMissingBlock) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpName %struct "struct" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%var = OpUntypedVariableKHR %ptr StorageBuffer %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("StorageBuffer id '2' is missing Block decoration")); +} + +TEST_F(ValidateDecorations, UntypedVariableUniformMissingBlock) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpName %struct "struct" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Uniform +%var = OpUntypedVariableKHR %ptr Uniform %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Uniform id '2' is missing Block or BufferBlock decoration")); +} + +TEST_F(ValidateDecorations, UntypedVariablePushConstantMissingBlock) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpName %struct "struct" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR PushConstant +%var = OpUntypedVariableKHR %ptr PushConstant %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("PushConstant id '2' is missing Block decoration")); +} + +using UntypedVariableSetAndBinding = spvtest::ValidateBase; + +TEST_P(UntypedVariableSetAndBinding, MissingSet) { + const auto sc = GetParam(); + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpName %var "var" +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR )" + + sc + R"( +%var = OpUntypedVariableKHR %ptr )" + sc + R"( %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%load = OpLoad %struct %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr(sc + " id '2' is missing DescriptorSet decoration")); +} + +TEST_P(UntypedVariableSetAndBinding, MissingBinding) { + const auto sc = GetParam(); + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpName %var "var" +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %var DescriptorSet 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR )" + + sc + R"( +%var = OpUntypedVariableKHR %ptr )" + sc + R"( %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%load = OpLoad %struct %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr(sc + " id '2' is missing Binding decoration")); +} + +INSTANTIATE_TEST_SUITE_P(ValidateUntypedVariableSetAndBinding, + UntypedVariableSetAndBinding, + Values("StorageBuffer", "Uniform")); + +using UntypedPointerLayout = + spvtest::ValidateBase>; + +TEST_P(UntypedPointerLayout, BadOffset) { + const auto sc = std::get<0>(GetParam()); + const auto op = std::get<1>(GetParam()); + const std::string set = (sc == "StorageBuffer" || sc == "Uniform" + ? R"(OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +)" + : R"()"); + const std::string spirv = R"( +OpCapability Shader +OpCapability VariablePointers +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var +OpExecutionMode %main LocalSize 1 1 1 +OpName %var "var" +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpMemberDecorate %struct 1 Offset 4 +)" + set + R"(OpMemberDecorate %test_type 0 Offset 0 +OpMemberDecorate %test_type 1 Offset 1 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%struct = OpTypeStruct %int %int +%test_type = OpTypeStruct %int %int +%test_val = OpConstantNull %test_type +%ptr = OpTypeUntypedPointerKHR )" + + sc + R"( +%var = OpUntypedVariableKHR %ptr )" + sc + R"( %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +)" + op + R"( +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + const bool read_only = sc == "Uniform" || sc == "PushConstant"; + if (!read_only || op.find("OpStore") == std::string::npos) { + EXPECT_THAT(getDiagnosticString(), + HasSubstr("member 1 at offset 1 is not aligned to")); + } +} + +TEST_P(UntypedPointerLayout, BadStride) { + const auto sc = std::get<0>(GetParam()); + const auto op = std::get<1>(GetParam()); + const std::string set = (sc == "StorageBuffer" || sc == "Uniform" + ? R"(OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +)" + : R"()"); + const std::string spirv = R"( +OpCapability Shader +OpCapability VariablePointers +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var +OpExecutionMode %main LocalSize 1 1 1 +OpName %var "var" +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpMemberDecorate %struct 1 Offset 4 +)" + set + R"(OpDecorate %test_type ArrayStride 4 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%int_4 = OpConstant %int 4 +%int4 = OpTypeVector %int 4 +%test_type = OpTypeArray %int4 %int_4 +%test_val = OpConstantNull %test_type +%struct = OpTypeStruct %int %int +%ptr = OpTypeUntypedPointerKHR )" + + sc + R"( +%var = OpUntypedVariableKHR %ptr )" + sc + R"( %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +)" + op + R"( +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + const bool read_only = sc == "Uniform" || sc == "PushConstant"; + if (!read_only || op.find("OpStore") == std::string::npos) { + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("array with stride 4 not satisfying alignment to 16")); + } +} + +INSTANTIATE_TEST_SUITE_P( + ValidateUntypedPointerLayout, UntypedPointerLayout, + Combine(Values("StorageBuffer", "Uniform", "PushConstant", "Workgroup"), + Values("%gep = OpUntypedAccessChainKHR %ptr %test_type %var %int_0", + "%gep = OpUntypedInBoundsAccessChainKHR %ptr %test_type " + "%var %int_0", + "%gep = OpUntypedPtrAccessChainKHR %ptr %test_type %var " + "%int_0 %int_0", + "%ld = OpLoad %test_type %var", "OpStore %var %test_val"))); + +TEST_F(ValidateDecorations, UntypedArrayLengthMissingOffset) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpDecorate %array ArrayStride 4 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%array = OpTypeRuntimeArray %int +%struct = OpTypeStruct %array +%block = OpTypeStruct %array +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%var = OpUntypedVariableKHR %ptr StorageBuffer %block +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%len = OpUntypedArrayLengthKHR %int %struct %var 0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("member 0 is missing an Offset decoration")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/test/val/val_extension_spv_khr_subgroup_uniform_control_flow.cpp b/test/val/val_extension_spv_khr_subgroup_uniform_control_flow.cpp new file mode 100644 index 0000000000..f528cb9eef --- /dev/null +++ b/test/val/val_extension_spv_khr_subgroup_uniform_control_flow.cpp @@ -0,0 +1,110 @@ +// Copyright (c) 2021 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. + +// Tests for OpExtension validator rules. + +#include +#include + +#include "gmock/gmock.h" +#include "source/enum_string_mapping.h" +#include "source/extensions.h" +#include "source/spirv_target_env.h" +#include "test/test_fixture.h" +#include "test/unit_spirv.h" +#include "test/val/val_fixtures.h" + +namespace spvtools { +namespace val { +namespace { + +using ::testing::HasSubstr; +using ::testing::Values; +using ::testing::ValuesIn; + +using ValidateSpvKHRSubgroupUniformControlFlow = spvtest::ValidateBase; + +TEST_F(ValidateSpvKHRSubgroupUniformControlFlow, Valid) { + const std::string str = R"( + OpCapability Shader + OpExtension "SPV_KHR_subgroup_uniform_control_flow" + OpMemoryModel Logical Simple + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpExecutionMode %main SubgroupUniformControlFlowKHR + + %void = OpTypeVoid + %void_fn = OpTypeFunction %void + + %main = OpFunction %void None %void_fn + %entry = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateSpvKHRSubgroupUniformControlFlow, RequiresExtension) { + const std::string str = R"( + OpCapability Shader + OpMemoryModel Logical Simple + OpEntryPoint GLCompute %main "main" + OpExecutionMode %main LocalSize 1 1 1 + OpExecutionMode %main SubgroupUniformControlFlowKHR + + %void = OpTypeVoid + %void_fn = OpTypeFunction %void + + %main = OpFunction %void None %void_fn + %entry = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + EXPECT_NE(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("2nd operand of ExecutionMode: operand " + "SubgroupUniformControlFlowKHR(4421) " + "requires one of these extensions: " + "SPV_KHR_subgroup_uniform_control_flow")); +} + +TEST_F(ValidateSpvKHRSubgroupUniformControlFlow, RequiresShaderCapability) { + const std::string str = R"( + OpCapability Kernel + OpCapability Addresses + OpExtension "SPV_KHR_subgroup_uniform_control_flow" + OpMemoryModel Physical32 OpenCL + OpEntryPoint Kernel %main "main" + OpExecutionMode %main SubgroupUniformControlFlowKHR + + %void = OpTypeVoid + %void_fn = OpTypeFunction %void + + %main = OpFunction %void None %void_fn + %entry = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str()); + EXPECT_NE(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Operand 2 of ExecutionMode requires one of these " + "capabilities: Shader")); +} + +} // namespace +} // namespace val +} // namespace spvtools diff --git a/test/val/val_fixtures.h b/test/val/val_fixtures.h index 98d8d32a99..db9d0452e1 100644 --- a/test/val/val_fixtures.h +++ b/test/val/val_fixtures.h @@ -76,6 +76,8 @@ class ValidateBase : public ::testing::Test, diagnostic_ = nullptr; } + void SetAssembleOptions(uint32_t options) { assemble_options_ = options; } + std::string getDiagnosticString(); spv_position_t getErrorPosition(); spv_validator_options getValidatorOptions(); @@ -84,6 +86,7 @@ class ValidateBase : public ::testing::Test, spv_diagnostic diagnostic_; spv_validator_options options_; std::unique_ptr vstate_; + uint32_t assemble_options_ = SPV_TEXT_TO_BINARY_OPTION_NONE; }; template @@ -132,8 +135,9 @@ void ValidateBase::CompileSuccessfully(std::string code, DestroyBinary(); spv_diagnostic diagnostic = nullptr; ScopedContext context(env); - auto status = spvTextToBinary(context.context, code.c_str(), code.size(), - &binary_, &diagnostic); + auto status = + spvTextToBinaryWithOptions(context.context, code.c_str(), code.size(), + assemble_options_, &binary_, &diagnostic); EXPECT_EQ(SPV_SUCCESS, status) << "ERROR: " << diagnostic->error << "\nSPIR-V could not be compiled into binary:\n" diff --git a/test/val/val_function_test.cpp b/test/val/val_function_test.cpp index 24b52638a2..119edd3e6c 100644 --- a/test/val/val_function_test.cpp +++ b/test/val/val_function_test.cpp @@ -836,6 +836,113 @@ TEST_F(ValidateFunctionCall, LogicallyMismatchedPointersArraySize) { HasSubstr("type does not match Function ")); } +TEST_F(ValidateFunctionCall, UntypedPointerParameterMismatch) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpName %var "var" +OpName %ptr2 "ptr2" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr = OpTypeUntypedPointerKHR Private +%ptr2 = OpTypeUntypedPointerKHR Private +%var = OpUntypedVariableKHR %ptr Private %int +%void_fn = OpTypeFunction %void +%ptr_fn = OpTypeFunction %void %ptr2 +%foo = OpFunction %void None %ptr_fn +%param = OpFunctionParameter %ptr2 +%first = OpLabel +OpReturn +OpFunctionEnd +%main = OpFunction %void None %void_fn +%entry = OpLabel +%call = OpFunctionCall %void %foo %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpFunctionCall Argument '2[%var]'s type does not " + "match Function '3[%ptr2]'s parameter type")); +} + +TEST_F(ValidateFunctionCall, UntypedPointerParameterGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpName %var "var" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr = OpTypeUntypedPointerKHR Private +%var = OpUntypedVariableKHR %ptr Private %int +%void_fn = OpTypeFunction %void +%ptr_fn = OpTypeFunction %void %ptr +%foo = OpFunction %void None %ptr_fn +%param = OpFunctionParameter %ptr +%first = OpLabel +OpReturn +OpFunctionEnd +%main = OpFunction %void None %void_fn +%entry = OpLabel +%call = OpFunctionCall %void %foo %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateFunctionCall, + UntypedPointerParameterNotMemoryObjectDeclaration) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpName %var "var" +OpName %gep "gep" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Private +%var = OpUntypedVariableKHR %ptr Private %int +%void_fn = OpTypeFunction %void +%ptr_fn = OpTypeFunction %void %ptr +%foo = OpFunction %void None %ptr_fn +%param = OpFunctionParameter %ptr +%first = OpLabel +OpReturn +OpFunctionEnd +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = OpUntypedAccessChainKHR %ptr %struct %var %int_0 +%call = OpFunctionCall %void %foo %gep +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Pointer operand '3[%gep]' must be a memory object declaration")); +} + INSTANTIATE_TEST_SUITE_P(StorageClass, ValidateFunctionCall, Values("UniformConstant", "Input", "Uniform", "Output", "Workgroup", "Private", "Function", diff --git a/test/val/val_id_test.cpp b/test/val/val_id_test.cpp index c1b8e41f94..1e050183b2 100644 --- a/test/val/val_id_test.cpp +++ b/test/val/val_id_test.cpp @@ -578,9 +578,8 @@ TEST_P(ValidateIdWithMessage, OpEntryPointInterfaceIsNotVariableTypeBad) { CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr(make_message( - "Interfaces passed to OpEntryPoint must be of type " - "OpTypeVariable. Found OpTypePointer."))); + HasSubstr("Interfaces passed to OpEntryPoint must be variables. " + "Found OpTypePointer.")); } TEST_P(ValidateIdWithMessage, OpEntryPointInterfaceStorageClassBad) { @@ -1167,6 +1166,160 @@ TEST_P(ValidateIdWithMessage, OpTypePointerBad) { "type."))); } +TEST_P(ValidateIdWithMessage, OpTypePointerCanHaveUntypedPointer) { + const std::string spirv = R"( +OpCapability Kernel +OpCapability Linkage +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical OpenCL +%ptr = OpTypeUntypedPointerKHR Workgroup +%ptr2 = OpTypePointer Private %ptr +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_P(ValidateIdWithMessage, OpTypeUntypedPointerWorkgroupGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +%ptr = OpTypeUntypedPointerKHR Workgroup +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_P(ValidateIdWithMessage, + OpTypeUntypedPointerWorkgroupMissingExplicitLayout) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%ptr = OpTypeUntypedPointerKHR Workgroup +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Workgroup storage class untyped pointers in Vulkan require " + "WorkgroupMemoryExplicitLayoutKHR be declared")); +} + +TEST_P(ValidateIdWithMessage, OpTypeUntypedPointerWorkgroupGoodAll) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +%ptr = OpTypeUntypedPointerKHR Workgroup +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateIdWithMessage, OpTypeUntypedPointerStorageBufferGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +%ptr = OpTypeUntypedPointerKHR StorageBuffer +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateIdWithMessage, OpTypeUntypedPointerUniformGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +%ptr = OpTypeUntypedPointerKHR Uniform +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateIdWithMessage, OpTypeUntypedPointerPushConstantGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +%ptr = OpTypeUntypedPointerKHR PushConstant +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateIdWithMessage, OpTypeUntypedPointerCrossWorkgroupGood) { + const std::string spirv = R"( +OpCapability Kernel +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical OpenCL +%ptr = OpTypeUntypedPointerKHR CrossWorkgroup +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateIdWithMessage, OpTypeUntypedPointerVulkanInvalidStorageClass) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%ptr = OpTypeUntypedPointerKHR Private +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("In Vulkan, untyped pointers can only be used in an " + "explicitly laid out storage class")); +} + TEST_P(ValidateIdWithMessage, OpTypeFunctionGood) { std::string spirv = kGLSL450MemoryModel + R"( %1 = OpTypeVoid @@ -2270,9 +2423,8 @@ OpFunctionEnd CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr(make_message( - "OpVariable Initializer '8[%8]' is not a constant " - "or module-scope variable"))); + HasSubstr("Variable Initializer '8[%8]' is not a constant " + "or module-scope variable")); } TEST_P(ValidateIdWithMessage, OpVariableInitializerIsModuleVarGood) { @@ -6404,9 +6556,10 @@ OpMemoryModel Logical VulkanKHR %7 = OpConstant %2 2 %8 = OpConstant %2 5 %9 = OpTypeFunction %1 +%12 = OpConstant %2 4 %10 = OpFunction %1 None %9 %11 = OpLabel -OpCopyMemorySized %4 %6 %7 NonPrivatePointerKHR|MakePointerAvailableKHR %7 +OpCopyMemorySized %4 %6 %12 NonPrivatePointerKHR|MakePointerAvailableKHR %7 OpReturn OpFunctionEnd )"; @@ -6431,10 +6584,11 @@ OpMemoryModel Logical VulkanKHR %6 = OpVariable %5 Uniform %7 = OpConstant %2 2 %8 = OpConstant %2 5 +%12 = OpConstant %2 4 %9 = OpTypeFunction %1 %10 = OpFunction %1 None %9 %11 = OpLabel -OpCopyMemorySized %4 %6 %7 NonPrivatePointerKHR|MakePointerVisibleKHR %8 +OpCopyMemorySized %4 %6 %12 NonPrivatePointerKHR|MakePointerVisibleKHR %8 OpReturn OpFunctionEnd )"; @@ -6460,10 +6614,11 @@ OpMemoryModel Logical VulkanKHR %6 = OpVariable %5 Uniform %7 = OpConstant %2 2 %8 = OpConstant %2 5 +%12 = OpConstant %2 4 %9 = OpTypeFunction %1 %10 = OpFunction %1 None %9 %11 = OpLabel -OpCopyMemorySized %4 %6 %7 NonPrivatePointerKHR|MakePointerAvailableKHR|MakePointerVisibleKHR %7 %8 +OpCopyMemorySized %4 %6 %12 NonPrivatePointerKHR|MakePointerAvailableKHR|MakePointerVisibleKHR %7 %8 OpReturn OpFunctionEnd )"; @@ -6489,10 +6644,11 @@ OpMemoryModel Logical VulkanKHR %6 = OpVariable %5 Uniform %7 = OpConstant %2 2 %8 = OpConstant %2 5 +%12 = OpConstant %2 4 %9 = OpTypeFunction %1 %10 = OpFunction %1 None %9 %11 = OpLabel -OpCopyMemorySized %4 %6 %7 MakePointerAvailableKHR %7 +OpCopyMemorySized %4 %6 %12 MakePointerAvailableKHR %7 OpReturn OpFunctionEnd )"; @@ -6522,10 +6678,11 @@ OpMemoryModel Logical VulkanKHR %6 = OpVariable %5 Uniform %7 = OpConstant %2 2 %8 = OpConstant %2 5 +%12 = OpConstant %2 4 %9 = OpTypeFunction %1 %10 = OpFunction %1 None %9 %11 = OpLabel -OpCopyMemorySized %4 %6 %7 MakePointerVisibleKHR %8 +OpCopyMemorySized %4 %6 %12 MakePointerVisibleKHR %8 OpReturn OpFunctionEnd )"; @@ -6555,10 +6712,11 @@ OpMemoryModel Logical VulkanKHR %6 = OpVariable %5 Uniform %7 = OpConstant %2 2 %8 = OpConstant %2 5 +%12 = OpConstant %2 4 %9 = OpTypeFunction %1 %10 = OpFunction %1 None %9 %11 = OpLabel -OpCopyMemorySized %4 %6 %7 NonPrivatePointerKHR +OpCopyMemorySized %4 %6 %12 NonPrivatePointerKHR OpReturn OpFunctionEnd )"; @@ -6589,10 +6747,11 @@ OpMemoryModel Logical VulkanKHR %6 = OpVariable %5 Input %7 = OpConstant %2 2 %8 = OpConstant %2 5 +%12 = OpConstant %2 4 %9 = OpTypeFunction %1 %10 = OpFunction %1 None %9 %11 = OpLabel -OpCopyMemorySized %4 %6 %7 NonPrivatePointerKHR +OpCopyMemorySized %4 %6 %12 NonPrivatePointerKHR OpReturn OpFunctionEnd )"; diff --git a/test/val/val_interfaces_test.cpp b/test/val/val_interfaces_test.cpp index 40e67184d5..50f45573f7 100644 --- a/test/val/val_interfaces_test.cpp +++ b/test/val/val_interfaces_test.cpp @@ -1691,6 +1691,122 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3)); } +TEST_F(ValidateInterfacesTest, UntypedVariableInputMissing) { + const std::string text = R"( +OpCapability Kernel +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical OpenCL +OpEntryPoint Kernel %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpName %var "var" +OpDecorate %var BuiltIn LocalInvocationId +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int3 = OpTypeVector %int 3 +%ptr = OpTypeUntypedPointerKHR Input +%var = OpUntypedVariableKHR %ptr Input %int3 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%load = OpLoad %int3 %var +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(text); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Interface variable id <2> is used by entry point " + "'main' id <1>, but is not listed as an interface")); +} + +TEST_F(ValidateInterfacesTest, UntypedVariableWorkgroupMissingSpv1p4) { + const std::string text = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpName %var "var" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Workgroup %int +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%load = OpLoad %int %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Interface variable id <2> is used by entry point " + "'main' id <1>, but is not listed as an interface")); +} + +TEST_F(ValidateInterfacesTest, UntypedIdMatchesInputVulkan1p3) { + const std::string text = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %var +OpExecutionMode %main OriginUpperLeft +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %1 Block +OpMemberDecorate %1 0 Offset 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%1 = OpTypeStruct %float ; this id matches Input storage class +%ptr = OpTypeUntypedPointerKHR Uniform +%var = OpUntypedVariableKHR %ptr Uniform %1 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + CompileSuccessfully(text, SPV_ENV_VULKAN_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3)); +} + +TEST_F(ValidateInterfacesTest, UntypedIdMatchesPushConstantVulkan1p3) { + const std::string text = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" %var +OpExecutionMode %main OriginUpperLeft +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %9 Block +OpMemberDecorate %9 0 Offset 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%9 = OpTypeStruct %float ; this id matches PushConstant storage class +%ptr = OpTypeUntypedPointerKHR Uniform +%var = OpUntypedVariableKHR %ptr Uniform %9 +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + CompileSuccessfully(text, SPV_ENV_VULKAN_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3)); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp index dfddc98725..b4689f2e9d 100644 --- a/test/val/val_memory_test.cpp +++ b/test/val/val_memory_test.cpp @@ -352,12 +352,8 @@ OpFunctionEnd )"; CompileSuccessfully(spirv.c_str()); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr( - "From SPIR-V spec, section 3.32.8 on OpVariable:\n" - "Its Storage Class operand must be the same as the Storage Class " - "operand of the result type.")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Storage class must match result type storage class")); } TEST_F(ValidateMemory, MatchingStorageClassesGood) { @@ -788,7 +784,7 @@ TEST_F(ValidateMemory, ArrayLenIndexNotLastMember) { EXPECT_THAT( getDiagnosticString(), HasSubstr( - "The array member in OpArrayLength '11[%11]' must be an the " + "The array member in OpArrayLength '11[%11]' must be the " "last member of the struct.\n %11 = OpArrayLength %uint %10 0\n")); } @@ -1465,6 +1461,7 @@ OpExtension "SPV_KHR_vulkan_memory_model" OpMemoryModel Logical VulkanKHR %void = OpTypeVoid %int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 %device = OpConstant %int 1 %int_ptr_ssbo = OpTypePointer StorageBuffer %int %var1 = OpVariable %int_ptr_ssbo StorageBuffer @@ -1472,7 +1469,7 @@ OpMemoryModel Logical VulkanKHR %voidfn = OpTypeFunction %void %func = OpFunction %void None %voidfn %entry = OpLabel -OpCopyMemorySized %var1 %var2 %device MakePointerAvailableKHR|NonPrivatePointerKHR %device +OpCopyMemorySized %var1 %var2 %int_4 MakePointerAvailableKHR|NonPrivatePointerKHR %device OpReturn OpFunctionEnd )"; @@ -1496,6 +1493,7 @@ OpExtension "SPV_KHR_vulkan_memory_model" OpMemoryModel Logical VulkanKHR %void = OpTypeVoid %int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 %device = OpConstant %int 1 %workgroup = OpConstant %int 1 %int_ptr_ssbo = OpTypePointer StorageBuffer %int @@ -1504,7 +1502,7 @@ OpMemoryModel Logical VulkanKHR %voidfn = OpTypeFunction %void %func = OpFunction %void None %voidfn %entry = OpLabel -OpCopyMemorySized %var1 %var2 %device Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %device %workgroup +OpCopyMemorySized %var1 %var2 %int_4 Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %device %workgroup OpReturn OpFunctionEnd )"; @@ -1528,6 +1526,7 @@ OpExtension "SPV_KHR_vulkan_memory_model" OpMemoryModel Logical VulkanKHR %void = OpTypeVoid %int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 %device = OpConstant %int 1 %workgroup = OpConstant %int 1 %int_ptr_ssbo = OpTypePointer StorageBuffer %int @@ -1536,7 +1535,7 @@ OpMemoryModel Logical VulkanKHR %voidfn = OpTypeFunction %void %func = OpFunction %void None %voidfn %entry = OpLabel -OpCopyMemorySized %var1 %var2 %device Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %workgroup %device +OpCopyMemorySized %var1 %var2 %int_4 Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %workgroup %device OpReturn OpFunctionEnd )"; @@ -1561,6 +1560,7 @@ OpExtension "SPV_KHR_vulkan_memory_model" OpMemoryModel Logical VulkanKHR %void = OpTypeVoid %int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 %device = OpConstant %int 1 %int_ptr_ssbo = OpTypePointer StorageBuffer %int %var1 = OpVariable %int_ptr_ssbo StorageBuffer @@ -1568,7 +1568,7 @@ OpMemoryModel Logical VulkanKHR %voidfn = OpTypeFunction %void %func = OpFunction %void None %voidfn %entry = OpLabel -OpCopyMemorySized %var1 %var2 %device MakePointerAvailableKHR|NonPrivatePointerKHR %device +OpCopyMemorySized %var1 %var2 %int_4 MakePointerAvailableKHR|NonPrivatePointerKHR %device OpReturn OpFunctionEnd )"; @@ -1588,6 +1588,7 @@ OpExtension "SPV_KHR_vulkan_memory_model" OpMemoryModel Logical VulkanKHR %void = OpTypeVoid %int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 %device = OpConstant %int 1 %workgroup = OpConstant %int 2 %int_ptr_ssbo = OpTypePointer StorageBuffer %int @@ -1596,7 +1597,7 @@ OpMemoryModel Logical VulkanKHR %voidfn = OpTypeFunction %void %func = OpFunction %void None %voidfn %entry = OpLabel -OpCopyMemorySized %var1 %var2 %device Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %device %workgroup +OpCopyMemorySized %var1 %var2 %int_4 Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %device %workgroup OpReturn OpFunctionEnd )"; @@ -1616,6 +1617,7 @@ OpExtension "SPV_KHR_vulkan_memory_model" OpMemoryModel Logical VulkanKHR %void = OpTypeVoid %int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 %device = OpConstant %int 1 %workgroup = OpConstant %int 2 %int_ptr_ssbo = OpTypePointer StorageBuffer %int @@ -1624,7 +1626,7 @@ OpMemoryModel Logical VulkanKHR %voidfn = OpTypeFunction %void %func = OpFunction %void None %voidfn %entry = OpLabel -OpCopyMemorySized %var1 %var2 %device Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %workgroup %device +OpCopyMemorySized %var1 %var2 %int_4 Aligned|MakePointerVisibleKHR|MakePointerAvailableKHR|NonPrivatePointerKHR 4 %workgroup %device OpReturn OpFunctionEnd )"; @@ -3857,8 +3859,7 @@ OpMemoryModel Logical GLSL450 CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); EXPECT_THAT(getDiagnosticString(), - HasSubstr("Initializer type must match the type pointed to by " - "the Result Type")); + HasSubstr("Initializer type must match the data type")); } TEST_F(ValidateMemory, StoreToUniformBlock) { @@ -5087,6 +5088,128 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateMemory, UntypedVariableGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%ptr = OpTypeUntypedPointerKHR Private +%var = OpUntypedVariableKHR %ptr Private %int %int_0 +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMemory, UntypedVariableNoDataType) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%var = OpUntypedVariableKHR %ptr StorageBuffer +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMemory, UntypedVariableNoDataTypeFunction) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%ptr = OpTypeUntypedPointerKHR Function +%var = OpUntypedVariableKHR %ptr Function +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Data type must be specified for Function, " + "Private, and Workgroup storage classes")); +} + +TEST_F(ValidateMemory, UntypedVariableNoDataTypePrivate) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%ptr = OpTypeUntypedPointerKHR Private +%var = OpUntypedVariableKHR %ptr Private +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Data type must be specified for Function, " + "Private, and Workgroup storage classes")); +} + +TEST_F(ValidateMemory, UntypedVariableNoDataTypeWorkgroup) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Workgroup +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Data type must be specified for Function, " + "Private, and Workgroup storage classes")); +} + +TEST_F(ValidateMemory, UntypedVariableNoDataTypeVulkan) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%var = OpUntypedVariableKHR %ptr StorageBuffer +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Vulkan requires that data type be specified")); +} + TEST_F(ValidateMemory, PtrAccessChainArrayStrideBad) { const std::string spirv = R"( OpCapability Shader @@ -5359,6 +5482,1467 @@ OpFunctionEnd EXPECT_THAT(getDiagnosticString(), HasSubstr("cannot find index -224")); } +TEST_F(ValidateMemory, UntypedVariableFunctionOutsideFunction) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%ptr = OpTypeUntypedPointerKHR Function +%var = OpUntypedVariableKHR %ptr Function %int +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Variables can not have a function[7] storage class " + "outside of a function")); +} + +TEST_F(ValidateMemory, UntypedVariableBadResultType) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %int Workgroup %int +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Result type must be an untyped pointer")); +} + +TEST_F(ValidateMemory, UntypedVariableBadDataType) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Workgroup %int_0 +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Data type must be a type instruction")); +} + +TEST_F(ValidateMemory, UntypedVariableBadStorageClass) { + const std::string spirv = R"( +OpCapability Kernel +OpCapability GenericPointer +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical OpenCL +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%ptr = OpTypeUntypedPointerKHR Generic +%var = OpUntypedVariableKHR %ptr Generic %int +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_2); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, + ValidateInstructions(SPV_ENV_UNIVERSAL_1_2)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Variable storage class cannot be Generic")); +} + +TEST_F(ValidateMemory, UntypedVariableMismatchedStorageClass) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Private %int +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Storage class must match result type storage class")); +} + +TEST_F(ValidateMemory, UntypedVariableBadInitializer) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +%int = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%ptr = OpTypeUntypedPointerKHR Private +%var = OpUntypedVariableKHR %ptr Private %int %float_0 +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Initializer type must match the data type")); +} + +TEST_F(ValidateMemory, AccessChainBaseUntypedPointer) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpName %var "var" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%block = OpTypeStruct %int +%ptr_ssbo = OpTypePointer StorageBuffer %block +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%var = OpUntypedVariableKHR %ptr StorageBuffer %int +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = OpAccessChain %ptr_ssbo_int %var %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("The Base '2[%var]' in OpAccessChain " + "instruction must be a pointer")); +} + +using ValidateMemoryUntypedAccessChain = spvtest::ValidateBase; + +TEST_P(ValidateMemoryUntypedAccessChain, GoodTypedPointerBase) { + const std::string opcode = GetParam(); + const bool ptr = opcode == "OpUntypedPtrAccessChainKHR" || + opcode == "OpUntypedInBoundsPtrAccessChainKHR"; + const std::string extra_param = ptr ? "%int_0" : ""; + + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability VariablePointers +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%block = OpTypeStruct %int +%ptr_ssbo = OpTypePointer StorageBuffer %block +%var = OpVariable %ptr_ssbo StorageBuffer +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = )" + opcode + R"( %ptr %block %var )" + + extra_param + R"( %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateMemoryUntypedAccessChain, GoodUntypedPointerBase) { + const std::string opcode = GetParam(); + const bool ptr = opcode == "OpUntypedPtrAccessChainKHR" || + opcode == "OpUntypedInBoundsPtrAccessChainKHR"; + const std::string extra_param = ptr ? "%int_0" : ""; + + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability VariablePointers +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%block = OpTypeStruct %int +%ptr_ssbo = OpTypePointer StorageBuffer %block +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%var = OpUntypedVariableKHR %ptr StorageBuffer %int +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = )" + opcode + R"( %ptr %block %var )" + + extra_param + R"( %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_P(ValidateMemoryUntypedAccessChain, ResultTypedPointer) { + const std::string opcode = GetParam(); + const bool ptr = opcode == "OpUntypedPtrAccessChainKHR" || + opcode == "OpUntypedInBoundsPtrAccessChainKHR"; + const std::string extra_param = ptr ? "%int_0" : ""; + + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability VariablePointers +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpName %gep "gep" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%block = OpTypeStruct %int +%ptr_ssbo = OpTypePointer StorageBuffer %block +%var = OpVariable %ptr_ssbo StorageBuffer +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%ptr_int = OpTypePointer StorageBuffer %int +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = )" + opcode + R"( %ptr_int %block %var )" + + extra_param + R"( %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("The Result Type of " + opcode + + " '2[%gep]' must be OpTypeUntypedPointer")); +} + +TEST_P(ValidateMemoryUntypedAccessChain, BaseTypeNotAType) { + const std::string opcode = GetParam(); + const bool ptr = opcode == "OpUntypedPtrAccessChainKHR" || + opcode == "OpUntypedInBoundsPtrAccessChainKHR"; + const std::string extra_param = ptr ? "%int_0" : ""; + + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability VariablePointers +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpName %gep "gep" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%block = OpTypeStruct %int +%ptr_ssbo = OpTypePointer StorageBuffer %block +%var = OpVariable %ptr_ssbo StorageBuffer +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = )" + opcode + R"( %ptr %int_0 %var )" + + extra_param + R"( %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Base type must be a non-pointer type")); +} + +TEST_P(ValidateMemoryUntypedAccessChain, BaseTypedPointer) { + const std::string opcode = GetParam(); + const bool ptr = opcode == "OpUntypedPtrAccessChainKHR" || + opcode == "OpUntypedInBoundsPtrAccessChainKHR"; + const std::string extra_param = ptr ? "%int_0" : ""; + + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability VariablePointers +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpName %gep "gep" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%block = OpTypeStruct %int +%ptr_ssbo = OpTypePointer StorageBuffer %block +%var = OpVariable %ptr_ssbo StorageBuffer +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = )" + opcode + R"( %ptr %ptr_ssbo %var )" + + extra_param + R"( %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Base type must be a non-pointer type")); +} + +TEST_P(ValidateMemoryUntypedAccessChain, BaseUntypedPointer) { + const std::string opcode = GetParam(); + const bool ptr = opcode == "OpUntypedPtrAccessChainKHR" || + opcode == "OpUntypedInBoundsPtrAccessChainKHR"; + const std::string extra_param = ptr ? "%int_0" : ""; + + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability VariablePointers +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpName %gep "gep" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%block = OpTypeStruct %int +%ptr_ssbo = OpTypePointer StorageBuffer %block +%var = OpVariable %ptr_ssbo StorageBuffer +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = )" + opcode + R"( %ptr %ptr %var )" + + extra_param + R"( %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Base type must be a non-pointer type")); +} + +TEST_P(ValidateMemoryUntypedAccessChain, BaseNotAPointer) { + const std::string opcode = GetParam(); + const bool ptr = opcode == "OpUntypedPtrAccessChainKHR" || + opcode == "OpUntypedInBoundsPtrAccessChainKHR"; + const std::string extra_param = ptr ? "%int_0" : ""; + + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability VariablePointers +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpName %int_0 "int_0" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%block = OpTypeStruct %int +%ptr_ssbo = OpTypePointer StorageBuffer %block +%var = OpVariable %ptr_ssbo StorageBuffer +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = )" + opcode + R"( %ptr %int %int_0 )" + + extra_param + R"( %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("The Base '2[%int_0]' in " + opcode + + " instruction must be a pointer")); +} + +TEST_P(ValidateMemoryUntypedAccessChain, StorageClassMismatch) { + const std::string opcode = GetParam(); + const bool ptr = opcode == "OpUntypedPtrAccessChainKHR" || + opcode == "OpUntypedInBoundsPtrAccessChainKHR"; + const std::string extra_param = ptr ? "%int_0" : ""; + + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability VariablePointers +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpName %int_0 "int_0" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%block = OpTypeStruct %int +%ptr_wg = OpTypePointer Workgroup %block +%var = OpVariable %ptr_wg Workgroup +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = )" + opcode + R"( %ptr %block %var )" + + extra_param + R"( %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("The result pointer storage class and base pointer storage " + "class in " + + opcode + " do not match")); +} + +TEST_P(ValidateMemoryUntypedAccessChain, NonCompositeBase) { + const std::string opcode = GetParam(); + const bool ptr = opcode == "OpUntypedPtrAccessChainKHR" || + opcode == "OpUntypedInBoundsPtrAccessChainKHR"; + const std::string extra_param = ptr ? "%int_0" : ""; + + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability VariablePointers +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpName %int_0 "int_0" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%block = OpTypeStruct %int +%ptr_wg = OpTypePointer StorageBuffer %block +%var = OpVariable %ptr_wg StorageBuffer +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = )" + opcode + R"( %ptr %int %var )" + + extra_param + R"( %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr(opcode + " reached non-composite type while indexes " + "still remain to be traversed")); +} + +TEST_P(ValidateMemoryUntypedAccessChain, TooManyIndices) { + const std::string opcode = GetParam(); + const bool ptr = opcode == "OpUntypedPtrAccessChainKHR" || + opcode == "OpUntypedInBoundsPtrAccessChainKHR"; + const std::string extra_param = ptr ? "%int_0" : ""; + + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability VariablePointers +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpName %int_0 "int_0" +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%block = OpTypeStruct %int +%ptr_wg = OpTypePointer StorageBuffer %block +%var = OpVariable %ptr_wg StorageBuffer +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = )" + opcode + R"( %ptr %block %var )" + + extra_param + R"( %int_0 %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr(opcode + " reached non-composite type while indexes " + "still remain to be traversed")); +} + +INSTANTIATE_TEST_SUITE_P( + ValidateUntypedAccessChains, ValidateMemoryUntypedAccessChain, + Values("OpUntypedAccessChainKHR", "OpUntypedInBoundsAccessChainKHR", + "OpUntypedPtrAccessChainKHR", "OpUntypedInBoundsPtrAccessChainKHR")); + +TEST_F(ValidateMemory, LoadUntypedPointerGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%load = OpLoad %float %var +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateMemory, StoreUntypedPointerGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpStore %var %float_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateMemory, CopyMemoryUntypedPointerSourceGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var1 %var2 +OpName %var1 "var1" +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Workgroup +%var1 = OpUntypedVariableKHR %ptr Workgroup %struct +%ptr_wg = OpTypePointer Workgroup %int +%var2 = OpVariable %ptr_wg Workgroup +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %var2 %var1 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateMemory, CopyMemoryUntypedPointerTargetGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var1 %var2 +OpName %var1 "var1" +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Workgroup +%var1 = OpUntypedVariableKHR %ptr Workgroup %struct +%ptr_wg = OpTypePointer Workgroup %int +%var2 = OpVariable %ptr_wg Workgroup +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %var1 %var2 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateMemory, CopyMemoryUntypedPointerTargetAndSourceBad) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var1 %var2 +OpName %var1 "var1" +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Workgroup +%var1 = OpUntypedVariableKHR %ptr Workgroup %struct +%var2 = OpUntypedVariableKHR %ptr Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemory %var1 %var2 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("One of Source or Target must be a typed pointer")); +} + +TEST_F(ValidateMemory, CopyMemorySizedUntypedPointersGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %v1 %v2 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_4 = OpConstant %int 4 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Workgroup +%v1 = OpUntypedVariableKHR %ptr Workgroup %struct +%v2 = OpUntypedVariableKHR %ptr Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemorySized %v2 %v1 %int_4 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateMemory, CopyMemorySizedUntypedPointersSizeBad1) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability StorageBuffer16BitAccess +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var_wg %var_ssbo +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%short = OpTypeInt 16 0 +%int_2 = OpConstant %int 2 +%struct = OpTypeStruct %int +%ptr_ssbo = OpTypeUntypedPointerKHR StorageBuffer +%ptr_wg = OpTypeUntypedPointerKHR Workgroup +%var_ssbo = OpUntypedVariableKHR %ptr_ssbo StorageBuffer %struct +%var_wg = OpUntypedVariableKHR %ptr_wg Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemorySized %var_ssbo %var_wg %int_2 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Size must be a multiple of 4")); +} + +TEST_F(ValidateMemory, CopyMemorySizedUntypedPointersSizeBad2) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability StorageBuffer16BitAccess +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var_ssbo %var_wg +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%short = OpTypeInt 16 0 +%int_2 = OpConstant %int 2 +%struct = OpTypeStruct %int +%ptr_ssbo = OpTypeUntypedPointerKHR StorageBuffer +%ptr_wg = OpTypeUntypedPointerKHR Workgroup +%var_ssbo = OpUntypedVariableKHR %ptr_ssbo StorageBuffer %struct +%var_wg = OpUntypedVariableKHR %ptr_wg Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemorySized %var_wg %var_ssbo %int_2 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Size must be a multiple of 4")); +} + +TEST_F(ValidateMemory, CopyMemorySizedUntypedPointersSizeBad3) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Int16 +OpCapability UntypedPointersKHR +OpCapability StorageBuffer8BitAccess +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_8bit_storage" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var_ssbo %var_wg +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%short = OpTypeInt 16 0 +%int_1 = OpConstant %int 1 +%struct = OpTypeStruct %int +%ptr_ssbo = OpTypeUntypedPointerKHR StorageBuffer +%ptr_wg = OpTypeUntypedPointerKHR Workgroup +%var_ssbo = OpUntypedVariableKHR %ptr_ssbo StorageBuffer %struct +%var_wg = OpUntypedVariableKHR %ptr_wg Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemorySized %var_ssbo %var_wg %int_1 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Size must be a multiple of 2")); +} + +TEST_F(ValidateMemory, CopyMemorySizedUntypedPointersSizeBad4) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Int16 +OpCapability UntypedPointersKHR +OpCapability StorageBuffer8BitAccess +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_8bit_storage" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %var_ssbo %var_wg +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%short = OpTypeInt 16 0 +%int_1 = OpConstant %int 1 +%struct = OpTypeStruct %int +%ptr_ssbo = OpTypeUntypedPointerKHR StorageBuffer +%ptr_wg = OpTypeUntypedPointerKHR Workgroup +%var_ssbo = OpUntypedVariableKHR %ptr_ssbo StorageBuffer %struct +%var_wg = OpUntypedVariableKHR %ptr_wg Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpCopyMemorySized %var_wg %var_ssbo %int_1 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("Size must be a multiple of 2")); +} + +TEST_F(ValidateMemory, PtrEqualUntypedPointersGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VariablePointers +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %v1 %v2 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Workgroup +%v1 = OpUntypedVariableKHR %ptr Workgroup %struct +%v2 = OpUntypedVariableKHR %ptr Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%res = OpPtrEqual %bool %v1 %v2 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateMemory, PtrNotEqualUntypedPointersGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VariablePointers +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %v1 %v2 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%bool = OpTypeBool +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Workgroup +%v1 = OpUntypedVariableKHR %ptr Workgroup %struct +%v2 = OpUntypedVariableKHR %ptr Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%res = OpPtrNotEqual %bool %v1 %v2 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateMemory, PtrDiffUntypedPointersGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability VariablePointers +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" %v1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Workgroup +%v1 = OpUntypedVariableKHR %ptr Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%res = OpPtrDiff %int %v1 %v1 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + +TEST_F(ValidateMemory, UntypedVariableVulkanPushConstantGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR PushConstant +%var = OpUntypedVariableKHR %ptr PushConstant %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + +TEST_F(ValidateMemory, UntypedVariableVulkanStorageBufferGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%var = OpUntypedVariableKHR %ptr StorageBuffer %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + +TEST_F(ValidateMemory, UntypedVariableVulkanUniformGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Uniform +%var = OpUntypedVariableKHR %ptr Uniform %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); +} + +TEST_F(ValidateMemory, UntypedVariableVulkanWorkgroupGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%struct = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR Workgroup +%var = OpUntypedVariableKHR %ptr Workgroup %struct +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1_SPIRV_1_4); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1_SPIRV_1_4)); +} + +TEST_F(ValidateMemory, UntypedPointerAsVariableType) { + const std::string spirv = R"( +OpCapability Shader +OpCapability Linkage +OpCapability VariablePointers +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%priv_ptr = OpTypePointer Private %ptr +%var = OpVariable %priv_ptr Private +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateMemory, UntypedArrayLengthGood) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpDecorate %array ArrayStride 4 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%array = OpTypeRuntimeArray %int +%block = OpTypeStruct %array +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%var = OpUntypedVariableKHR %ptr StorageBuffer %block +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%length = OpUntypedArrayLengthKHR %int %block %var 0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); +} + +TEST_F(ValidateMemory, UntypedArrayLengthBadResultType) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpDecorate %array ArrayStride 4 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%float = OpTypeFloat 32 +%array = OpTypeRuntimeArray %int +%block = OpTypeStruct %array +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%var = OpUntypedVariableKHR %ptr StorageBuffer %block +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%length = OpUntypedArrayLengthKHR %float %block %var 0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must be OpTypeInt with width 32 and signedness 0")); +} + +TEST_F(ValidateMemory, UntypedArrayLengthBadPointer) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpDecorate %array ArrayStride 4 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%array = OpTypeRuntimeArray %int +%block = OpTypeStruct %array +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%typed_ptr = OpTypePointer StorageBuffer %block +%var = OpVariable %typed_ptr StorageBuffer +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%length = OpUntypedArrayLengthKHR %int %block %var 0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Pointer must be an untyped pointer")); +} + +TEST_F(ValidateMemory, UntypedArrayLengtBadStruct) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpDecorate %array ArrayStride 4 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%array = OpTypeRuntimeArray %int +%block = OpTypeStruct %array +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%var = OpUntypedVariableKHR %ptr StorageBuffer %block +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%length = OpUntypedArrayLengthKHR %int %int %var 0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), HasSubstr("to an OpTypeStruct")); +} + +TEST_F(ValidateMemory, UntypedArrayLengthLastMemberNotArray) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpDecorate %array ArrayStride 4 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%array = OpTypeRuntimeArray %int +%block = OpTypeStruct %int +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%var = OpUntypedVariableKHR %ptr StorageBuffer %block +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%length = OpUntypedArrayLengthKHR %int %block %var 0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must be an OpTypeRuntimeArray")); +} + +TEST_F(ValidateMemory, UntypedArrayLengthBadIndex) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpDecorate %array ArrayStride 4 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%array = OpTypeRuntimeArray %int +%block = OpTypeStruct %array +%ptr = OpTypeUntypedPointerKHR StorageBuffer +%var = OpUntypedVariableKHR %ptr StorageBuffer %block +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%length = OpUntypedArrayLengthKHR %int %block %var 1 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_UNIVERSAL_1_3); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("must be the last member of the struct")); +} + +TEST_F(ValidateMemory, UntypedCooperativeMatrixLoad) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability CooperativeMatrixKHR +OpCapability VulkanMemoryModel +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_cooperative_matrix" +OpMemoryModel Logical Vulkan +OpEntryPoint GLCompute %main "main" %var +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpDecorate %array ArrayStride 4 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%untyped = OpTypeUntypedPointerKHR StorageBuffer +%float = OpTypeFloat 32 +%array = OpTypeRuntimeArray %float +%block = OpTypeStruct %array +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%subgroup = OpConstant %int 3 +%rows = OpSpecConstant %int 1 +%cols = OpSpecConstant %int 1 +%matrix_a = OpConstant %int 1 +%matrix = OpTypeCooperativeMatrixKHR %float %subgroup %rows %cols %matrix_a +%var = OpUntypedVariableKHR %untyped StorageBuffer %block +%main = OpFunction %void None %void_fn +%entry = OpLabel +%ld = OpCooperativeMatrixLoadKHR %matrix %var %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3)); +} + +TEST_F(ValidateMemory, UntypedCooperativeMatrixLoad2) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability CooperativeMatrixKHR +OpCapability VulkanMemoryModel +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_cooperative_matrix" +OpMemoryModel Logical Vulkan +OpEntryPoint GLCompute %main "main" %var +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpDecorate %array ArrayStride 4 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%untyped = OpTypeUntypedPointerKHR StorageBuffer +%float = OpTypeFloat 32 +%array = OpTypeRuntimeArray %float +%block = OpTypeStruct %array +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%subgroup = OpConstant %int 3 +%rows = OpSpecConstant %int 1 +%cols = OpSpecConstant %int 1 +%matrix_a = OpConstant %int 1 +%matrix = OpTypeCooperativeMatrixKHR %float %subgroup %rows %cols %matrix_a +%var = OpUntypedVariableKHR %untyped StorageBuffer %block +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = OpUntypedAccessChainKHR %untyped %block %var %int_0 %int_0 +%ld = OpCooperativeMatrixLoadKHR %matrix %gep %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3)); +} + +TEST_F(ValidateMemory, UntypedCooperativeMatrixStore) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability CooperativeMatrixKHR +OpCapability VulkanMemoryModel +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_cooperative_matrix" +OpMemoryModel Logical Vulkan +OpEntryPoint GLCompute %main "main" %var1 %var2 +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var1 DescriptorSet 0 +OpDecorate %var1 Binding 0 +OpDecorate %var2 DescriptorSet 0 +OpDecorate %var2 Binding 1 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpDecorate %array ArrayStride 4 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%untyped = OpTypeUntypedPointerKHR StorageBuffer +%float = OpTypeFloat 32 +%array = OpTypeRuntimeArray %float +%block = OpTypeStruct %array +%ptr = OpTypePointer StorageBuffer %block +%ptr_float = OpTypePointer StorageBuffer %float +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%subgroup = OpConstant %int 3 +%rows = OpSpecConstant %int 1 +%cols = OpSpecConstant %int 1 +%matrix_a = OpConstant %int 1 +%matrix = OpTypeCooperativeMatrixKHR %float %subgroup %rows %cols %matrix_a +%var1 = OpVariable %ptr StorageBuffer +%var2 = OpUntypedVariableKHR %untyped StorageBuffer %block +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = OpAccessChain %ptr_float %var1 %int_0 %int_0 +%ld = OpCooperativeMatrixLoadKHR %matrix %gep %int_0 +OpCooperativeMatrixStoreKHR %var2 %ld %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3)); +} + +TEST_F(ValidateMemory, UntypedCooperativeMatrixStore2) { + const std::string spirv = R"( +OpCapability Shader +OpCapability UntypedPointersKHR +OpCapability CooperativeMatrixKHR +OpCapability VulkanMemoryModel +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_cooperative_matrix" +OpMemoryModel Logical Vulkan +OpEntryPoint GLCompute %main "main" %var1 %var2 +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %var1 DescriptorSet 0 +OpDecorate %var1 Binding 0 +OpDecorate %var2 DescriptorSet 0 +OpDecorate %var2 Binding 1 +OpDecorate %block Block +OpMemberDecorate %block 0 Offset 0 +OpDecorate %array ArrayStride 4 +%void = OpTypeVoid +%void_fn = OpTypeFunction %void +%untyped = OpTypeUntypedPointerKHR StorageBuffer +%float = OpTypeFloat 32 +%array = OpTypeRuntimeArray %float +%block = OpTypeStruct %array +%ptr = OpTypePointer StorageBuffer %block +%ptr_float = OpTypePointer StorageBuffer %float +%int = OpTypeInt 32 0 +%int_0 = OpConstant %int 0 +%subgroup = OpConstant %int 3 +%rows = OpSpecConstant %int 1 +%cols = OpSpecConstant %int 1 +%matrix_a = OpConstant %int 1 +%matrix = OpTypeCooperativeMatrixKHR %float %subgroup %rows %cols %matrix_a +%var1 = OpVariable %ptr StorageBuffer +%var2 = OpUntypedVariableKHR %untyped StorageBuffer %block +%main = OpFunction %void None %void_fn +%entry = OpLabel +%gep = OpAccessChain %ptr_float %var1 %int_0 %int_0 +%ld = OpCooperativeMatrixLoadKHR %matrix %gep %int_0 +%gep2 = OpUntypedAccessChainKHR %untyped %block %var2 %int_0 %int_0 +OpCooperativeMatrixStoreKHR %gep2 %ld %int_0 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_3); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3)); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/test/val/val_storage_test.cpp b/test/val/val_storage_test.cpp index 6a3e4bdb26..d4170e6dc7 100644 --- a/test/val/val_storage_test.cpp +++ b/test/val/val_storage_test.cpp @@ -165,7 +165,7 @@ TEST_F(ValidateStorage, GenericVariableOutsideFunction) { CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpVariable storage class cannot be Generic")); + HasSubstr("Variable storage class cannot be Generic")); } TEST_F(ValidateStorage, GenericVariableInsideFunction) { @@ -187,7 +187,7 @@ TEST_F(ValidateStorage, GenericVariableInsideFunction) { CompileSuccessfully(str); EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), - HasSubstr("OpVariable storage class cannot be Generic")); + HasSubstr("Variable storage class cannot be Generic")); } TEST_F(ValidateStorage, RelaxedLogicalPointerFunctionParam) { diff --git a/test/val/val_type_unique_test.cpp b/test/val/val_type_unique_test.cpp index 31ad3a6597..00e2e7f14f 100644 --- a/test/val/val_type_unique_test.cpp +++ b/test/val/val_type_unique_test.cpp @@ -270,6 +270,24 @@ OpMemoryModel Logical GLSL450 Not(HasSubstr(GetErrorString(spv::Op::OpTypePointer)))); } +TEST_F(ValidateTypeUnique, DuplicateUntypedPointer) { + std::string str = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpCapability WorkgroupMemoryExplicitLayoutKHR +OpExtension "SPV_KHR_workgroup_memory_explicit_layout" +OpExtension "SPV_KHR_untyped_pointers" +OpMemoryModel Logical GLSL450 +%u32 = OpTypeInt 32 0 +%ptr1 = OpTypeUntypedPointerKHR Workgroup +%ptr2 = OpTypeUntypedPointerKHR Workgroup +)"; + + CompileSuccessfully(str.c_str(), SPV_ENV_UNIVERSAL_1_4); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); +} + } // namespace } // namespace val } // namespace spvtools From 4c7e1fa5c3d988cca0e626d359d30b117b9c2822 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 18 Jul 2024 02:54:47 +0000 Subject: [PATCH 477/523] Roll external/abseil_cpp/ 074a32af6..af4c589ed (1 commit) (#5731) * Roll external/googletest/ 34ad51b3d..9ff2450a5 (8 commits) https://github.com/google/googletest/compare/34ad51b3dc4f...9ff2450a56ae Created with: roll-dep external/googletest * Roll external/abseil_cpp/ 074a32af6..eb8522077 (13 commits) https://github.com/abseil/abseil-cpp/compare/074a32af6664...eb852207758a Created with: roll-dep external/abseil_cpp * Roll external/effcee/ d74d33d93..2c97e5689 (1 commit) https://github.com/google/effcee/compare/d74d33d93043...2c97e5689ed8 Created with: roll-dep external/effcee --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index 7ed619a487..56ca60c487 100644 --- a/DEPS +++ b/DEPS @@ -3,11 +3,11 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': '074a32af66648c74dd0104e251e44ace5b59f7fa', + 'abseil_revision': 'eb852207758a773965301d0ae717e4235fc5301a', - 'effcee_revision': 'd74d33d93043952a99ae7cd7458baf6bc8df1da0', + 'effcee_revision': '2c97e5689ed8d7ab6ae5820f884f03a601ae124b', - 'googletest_revision': '34ad51b3dc4f922d8ab622491dd44fc2c39afee9', + 'googletest_revision': '9ff2450a56aed4f7f124f5104d9e3088bf791ee9', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From 2ea40036336195a2d0e911bd722fbc1cbc2f1bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Fri, 19 Jul 2024 17:48:21 +0200 Subject: [PATCH 478/523] opt: split composite from array flattening (#5733) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * opt: split composite from array flattening DXC has an option to flatten resource arrays. But when this option is not used, the resource arrays should be kept as-is. On the other hand, when a struct contains resources, we MUST flatten is to be compliant with the Vulkan spec. Because this pass flattens both types of resources, using a struct of resources automatically implied flattening arrays. By adding those 2 new settings, we decide if the pass flattens only one type of resources, or both. Note: the flatten_arrays flag only impacts resource arrays. Arrays of composites containing resources are still flattened. Since the API is considered stable, I added 2 new functions to create passes with one flag or the other, and kept the original behavior as-is. Related to https://github.com/microsoft/DirectXShaderCompiler/issues/6745 Signed-off-by: Nathan Gauër * add commandline options Signed-off-by: Nathan Gauër * clang-format Signed-off-by: Nathan Gauër --------- Signed-off-by: Nathan Gauër --- include/spirv-tools/optimizer.hpp | 19 ++- source/opt/desc_sroa.cpp | 7 +- source/opt/desc_sroa.h | 16 ++- source/opt/desc_sroa_util.cpp | 51 ++++--- source/opt/desc_sroa_util.h | 4 + source/opt/optimizer.cpp | 19 ++- test/opt/desc_sroa_test.cpp | 227 ++++++++++++++++++++++++++++-- tools/opt/opt.cpp | 8 ++ 8 files changed, 307 insertions(+), 44 deletions(-) diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp index 216e68ade5..fe02ec7d70 100644 --- a/include/spirv-tools/optimizer.hpp +++ b/include/spirv-tools/optimizer.hpp @@ -827,14 +827,19 @@ Optimizer::PassToken CreateReplaceDescArrayAccessUsingVarIndexPass(); // Create descriptor scalar replacement pass. // This pass replaces every array variable |desc| that has a DescriptorSet and -// Binding decorations with a new variable for each element of the array. -// Suppose |desc| was bound at binding |b|. Then the variable corresponding to -// |desc[i]| will have binding |b+i|. The descriptor set will be the same. It -// is assumed that no other variable already has a binding that will used by one -// of the new variables. If not, the pass will generate invalid Spir-V. All -// accesses to |desc| must be OpAccessChain instructions with a literal index -// for the first index. +// Binding decorations with a new variable for each element of the +// array/composite. Suppose |desc| was bound at binding |b|. Then the variable +// corresponding to |desc[i]| will have binding |b+i|. The descriptor set will +// be the same. It is assumed that no other variable already has a binding that +// will used by one of the new variables. If not, the pass will generate +// invalid Spir-V. All accesses to |desc| must be OpAccessChain instructions +// with a literal index for the first index. This variant flattens both +// composites and arrays. Optimizer::PassToken CreateDescriptorScalarReplacementPass(); +// This variant flattens only composites. +Optimizer::PassToken CreateDescriptorCompositeScalarReplacementPass(); +// This variant flattens only arrays. +Optimizer::PassToken CreateDescriptorArrayScalarReplacementPass(); // Create a pass to replace each OpKill instruction with a function call to a // function that has a single OpKill. Also replace each OpTerminateInvocation diff --git a/source/opt/desc_sroa.cpp b/source/opt/desc_sroa.cpp index 2c0f4829f2..124a3d3a8e 100644 --- a/source/opt/desc_sroa.cpp +++ b/source/opt/desc_sroa.cpp @@ -31,11 +31,14 @@ bool IsDecorationBinding(Instruction* inst) { Pass::Status DescriptorScalarReplacement::Process() { bool modified = false; - std::vector vars_to_kill; for (Instruction& var : context()->types_values()) { - if (descsroautil::IsDescriptorArray(context(), &var)) { + bool is_candidate = + flatten_arrays_ && descsroautil::IsDescriptorArray(context(), &var); + is_candidate |= flatten_composites_ && + descsroautil::IsDescriptorStruct(context(), &var); + if (is_candidate) { modified = true; if (!ReplaceCandidate(&var)) { return Status::Failure; diff --git a/source/opt/desc_sroa.h b/source/opt/desc_sroa.h index 901be3e98b..d6af4df597 100644 --- a/source/opt/desc_sroa.h +++ b/source/opt/desc_sroa.h @@ -32,9 +32,16 @@ namespace opt { // Documented in optimizer.hpp class DescriptorScalarReplacement : public Pass { public: - DescriptorScalarReplacement() {} - - const char* name() const override { return "descriptor-scalar-replacement"; } + DescriptorScalarReplacement(bool flatten_composites, bool flatten_arrays) + : flatten_composites_(flatten_composites), + flatten_arrays_(flatten_arrays) {} + + const char* name() const override { + if (flatten_composites_ && flatten_arrays_) + return "descriptor-scalar-replacement"; + if (flatten_composites_) return "descriptor-compososite-scalar-replacement"; + return "descriptor-array-scalar-replacement"; + } Status Process() override; @@ -141,6 +148,9 @@ class DescriptorScalarReplacement : public Pass { // array |var|. If the entry is |0|, then the variable has not been // created yet. std::map> replacement_variables_; + + bool flatten_composites_; + bool flatten_arrays_; }; } // namespace opt diff --git a/source/opt/desc_sroa_util.cpp b/source/opt/desc_sroa_util.cpp index dba3de9c05..62d9476467 100644 --- a/source/opt/desc_sroa_util.cpp +++ b/source/opt/desc_sroa_util.cpp @@ -29,41 +29,58 @@ uint32_t GetLengthOfArrayType(IRContext* context, Instruction* type) { return length_const->GetU32(); } -} // namespace - -namespace descsroautil { +bool HasDescriptorDecorations(IRContext* context, Instruction* var) { + const auto& decoration_mgr = context->get_decoration_mgr(); + return decoration_mgr->HasDecoration( + var->result_id(), uint32_t(spv::Decoration::DescriptorSet)) && + decoration_mgr->HasDecoration(var->result_id(), + uint32_t(spv::Decoration::Binding)); +} -bool IsDescriptorArray(IRContext* context, Instruction* var) { +Instruction* GetVariableType(IRContext* context, Instruction* var) { if (var->opcode() != spv::Op::OpVariable) { - return false; + return nullptr; } uint32_t ptr_type_id = var->type_id(); Instruction* ptr_type_inst = context->get_def_use_mgr()->GetDef(ptr_type_id); if (ptr_type_inst->opcode() != spv::Op::OpTypePointer) { - return false; + return nullptr; } uint32_t var_type_id = ptr_type_inst->GetSingleWordInOperand(1); - Instruction* var_type_inst = context->get_def_use_mgr()->GetDef(var_type_id); - if (var_type_inst->opcode() != spv::Op::OpTypeArray && - var_type_inst->opcode() != spv::Op::OpTypeStruct) { - return false; + return context->get_def_use_mgr()->GetDef(var_type_id); +} + +} // namespace + +namespace descsroautil { + +bool IsDescriptorArray(IRContext* context, Instruction* var) { + Instruction* var_type_inst = GetVariableType(context, var); + if (var_type_inst == nullptr) return false; + return var_type_inst->opcode() == spv::Op::OpTypeArray && + HasDescriptorDecorations(context, var); +} + +bool IsDescriptorStruct(IRContext* context, Instruction* var) { + Instruction* var_type_inst = GetVariableType(context, var); + if (var_type_inst == nullptr) return false; + + while (var_type_inst->opcode() == spv::Op::OpTypeArray) { + var_type_inst = context->get_def_use_mgr()->GetDef( + var_type_inst->GetInOperand(0).AsId()); } + if (var_type_inst->opcode() != spv::Op::OpTypeStruct) return false; + // All structures with descriptor assignments must be replaced by variables, // one for each of their members - with the exceptions of buffers. if (IsTypeOfStructuredBuffer(context, var_type_inst)) { return false; } - if (!context->get_decoration_mgr()->HasDecoration( - var->result_id(), uint32_t(spv::Decoration::DescriptorSet))) { - return false; - } - - return context->get_decoration_mgr()->HasDecoration( - var->result_id(), uint32_t(spv::Decoration::Binding)); + return HasDescriptorDecorations(context, var); } bool IsTypeOfStructuredBuffer(IRContext* context, const Instruction* type) { diff --git a/source/opt/desc_sroa_util.h b/source/opt/desc_sroa_util.h index 2f45c0c2f4..04233565b1 100644 --- a/source/opt/desc_sroa_util.h +++ b/source/opt/desc_sroa_util.h @@ -27,6 +27,10 @@ namespace descsroautil { // descriptor array. bool IsDescriptorArray(IRContext* context, Instruction* var); +// Returns true if |var| is an OpVariable instruction that represents a +// struct containing descriptors. +bool IsDescriptorStruct(IRContext* context, Instruction* var); + // Returns true if |type| is a type that could be used for a structured buffer // as opposed to a type that would be used for a structure of resource // descriptors. diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index 4add68a232..4523d627e0 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -364,6 +364,10 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag, RegisterPass(CreateSpreadVolatileSemanticsPass()); } else if (pass_name == "descriptor-scalar-replacement") { RegisterPass(CreateDescriptorScalarReplacementPass()); + } else if (pass_name == "descriptor-composite-scalar-replacement") { + RegisterPass(CreateDescriptorCompositeScalarReplacementPass()); + } else if (pass_name == "descriptor-array-scalar-replacement") { + RegisterPass(CreateDescriptorArrayScalarReplacementPass()); } else if (pass_name == "eliminate-dead-code-aggressive") { RegisterPass(CreateAggressiveDCEPass(preserve_interface)); } else if (pass_name == "eliminate-insert-extract") { @@ -1059,7 +1063,20 @@ Optimizer::PassToken CreateSpreadVolatileSemanticsPass() { Optimizer::PassToken CreateDescriptorScalarReplacementPass() { return MakeUnique( - MakeUnique()); + MakeUnique( + /* flatten_composites= */ true, /* flatten_arrays= */ true)); +} + +Optimizer::PassToken CreateDescriptorCompositeScalarReplacementPass() { + return MakeUnique( + MakeUnique( + /* flatten_composites= */ true, /* flatten_arrays= */ false)); +} + +Optimizer::PassToken CreateDescriptorArrayScalarReplacementPass() { + return MakeUnique( + MakeUnique( + /* flatten_composites= */ false, /* flatten_arrays= */ true)); } Optimizer::PassToken CreateWrapOpKillPass() { diff --git a/test/opt/desc_sroa_test.cpp b/test/opt/desc_sroa_test.cpp index 5c166d83f7..f86fa3a8fa 100644 --- a/test/opt/desc_sroa_test.cpp +++ b/test/opt/desc_sroa_test.cpp @@ -198,7 +198,8 @@ TEST_F(DescriptorScalarReplacementTest, ExpandArrayOfTextures) { )"; - SinglePassRunAndMatch(text, true); + SinglePassRunAndMatch( + text, true, /* flatten_composites=*/true, /* flatten_arrays=*/true); } TEST_F(DescriptorScalarReplacementTest, ExpandArrayOfSamplers) { @@ -249,7 +250,8 @@ TEST_F(DescriptorScalarReplacementTest, ExpandArrayOfSamplers) { OpFunctionEnd )"; - SinglePassRunAndMatch(text, true); + SinglePassRunAndMatch( + text, true, /* flatten_composites=*/true, /* flatten_arrays=*/true); } TEST_F(DescriptorScalarReplacementTest, ExpandArrayOfSSBOs) { @@ -308,7 +310,8 @@ TEST_F(DescriptorScalarReplacementTest, ExpandArrayOfSSBOs) { OpFunctionEnd )"; - SinglePassRunAndMatch(text, true); + SinglePassRunAndMatch( + text, true, /* flatten_composites=*/true, /* flatten_arrays=*/true); } TEST_F(DescriptorScalarReplacementTest, NameNewVariables) { @@ -370,7 +373,8 @@ TEST_F(DescriptorScalarReplacementTest, NameNewVariables) { OpFunctionEnd )"; - SinglePassRunAndMatch(text, true); + SinglePassRunAndMatch( + text, true, /* flatten_composites=*/true, /* flatten_arrays=*/true); } TEST_F(DescriptorScalarReplacementTest, DontExpandCBuffers) { @@ -430,7 +434,8 @@ TEST_F(DescriptorScalarReplacementTest, DontExpandCBuffers) { OpFunctionEnd )"; - SinglePassRunAndMatch(text, true); + SinglePassRunAndMatch( + text, true, /* flatten_composites=*/true, /* flatten_arrays=*/true); } TEST_F(DescriptorScalarReplacementTest, DontExpandStructuredBuffers) { @@ -497,7 +502,8 @@ TEST_F(DescriptorScalarReplacementTest, DontExpandStructuredBuffers) { OpFunctionEnd )"; - SinglePassRunAndMatch(text, true); + SinglePassRunAndMatch( + text, true, /* flatten_composites=*/true, /* flatten_arrays=*/true); } TEST_F(DescriptorScalarReplacementTest, StructureArrayNames) { @@ -511,7 +517,39 @@ TEST_F(DescriptorScalarReplacementTest, StructureArrayNames) { )"; const std::string text = checks + GetStructureArrayTestSpirv(); - SinglePassRunAndMatch(text, true); + SinglePassRunAndMatch( + text, true, /* flatten_composites=*/true, /* flatten_arrays=*/true); +} + +TEST_F(DescriptorScalarReplacementTest, + FlattensArraysOfStructsButNoResourceArrays) { + // Check that only the composite array is flattenned, but internal resource + // arrays are left as-is. + const std::string checks = R"( +; CHECK: OpName %globalS_0__0__t "globalS[0][0].t" +; CHECK: OpName %globalS_0__0__s "globalS[0][0].s" +; CHECK: OpName %globalS_1__1__t "globalS[1][1].t" +; CHECK: OpName %globalS_1__1__s "globalS[1][1].s" +; CHECK-NOT: OpName %globalS_1__1__t_0_ +; CHECK-NOT: OpName %globalS_1__1__s_0_ + )"; + + const std::string text = checks + GetStructureArrayTestSpirv(); + SinglePassRunAndMatch( + text, true, /* flatten_composites=*/true, /* flatten_arrays=*/false); +} + +TEST_F(DescriptorScalarReplacementTest, FlattenNothingIfAskedTo) { + // Not useful, but checks what happens if both are set to false. + // In such case, nothing happens. + const std::string checks = R"( +; CHECK: OpName %globalS +; CHECK-NOT: OpName %globalS_ + )"; + + const std::string text = checks + GetStructureArrayTestSpirv(); + SinglePassRunAndMatch( + text, true, /* flatten_composites=*/false, /* flatten_arrays=*/false); } TEST_F(DescriptorScalarReplacementTest, StructureArrayBindings) { @@ -525,7 +563,8 @@ TEST_F(DescriptorScalarReplacementTest, StructureArrayBindings) { )"; const std::string text = checks + GetStructureArrayTestSpirv(); - SinglePassRunAndMatch(text, true); + SinglePassRunAndMatch( + text, true, /* flatten_composites=*/true, /* flatten_arrays=*/true); } TEST_F(DescriptorScalarReplacementTest, StructureArrayReplacements) { @@ -540,7 +579,8 @@ TEST_F(DescriptorScalarReplacementTest, StructureArrayReplacements) { )"; const std::string text = checks + GetStructureArrayTestSpirv(); - SinglePassRunAndMatch(text, true); + SinglePassRunAndMatch( + text, true, /* flatten_composites=*/true, /* flatten_arrays=*/true); } TEST_F(DescriptorScalarReplacementTest, ResourceStructAsFunctionParam) { @@ -724,7 +764,9 @@ TEST_F(DescriptorScalarReplacementTest, ResourceStructAsFunctionParam) { ; CHECK: OpFAdd %v4float [[sample_3]] [[sample_4]] )"; - SinglePassRunAndMatch(checks + shader, true); + SinglePassRunAndMatch( + checks + shader, true, /* flatten_composites=*/true, + /* flatten_arrays=*/true); } TEST_F(DescriptorScalarReplacementTest, BindingForResourceArrayOfStructs) { @@ -765,7 +807,8 @@ TEST_F(DescriptorScalarReplacementTest, BindingForResourceArrayOfStructs) { OpFunctionEnd )"; - SinglePassRunAndMatch(shader, true); + SinglePassRunAndMatch( + shader, true, /* flatten_composites=*/true, /* flatten_arrays=*/true); } TEST_F(DescriptorScalarReplacementTest, MemberDecorationForResourceStruct) { @@ -828,7 +871,8 @@ TEST_F(DescriptorScalarReplacementTest, MemberDecorationForResourceStruct) { OpFunctionEnd )"; - SinglePassRunAndMatch(shader, true); + SinglePassRunAndMatch( + shader, true, /* flatten_composites=*/true, /* flatten_arrays=*/true); } TEST_F(DescriptorScalarReplacementTest, DecorateStringForReflect) { @@ -915,7 +959,8 @@ TEST_F(DescriptorScalarReplacementTest, DecorateStringForReflect) { OpFunctionEnd )"; - SinglePassRunAndMatch(shader, true); + SinglePassRunAndMatch( + shader, true, /* flatten_composites=*/true, /* flatten_arrays=*/true); } TEST_F(DescriptorScalarReplacementTest, ExpandArrayInOpEntryPoint) { @@ -983,7 +1028,161 @@ TEST_F(DescriptorScalarReplacementTest, ExpandArrayInOpEntryPoint) { OpFunctionEnd )"; - SinglePassRunAndMatch(text, false); + SinglePassRunAndMatch( + text, false, /* flatten_composites=*/true, /* flatten_arrays=*/true); +} + +TEST_F(DescriptorScalarReplacementTest, + ExpandArrayWhenCompositeExpensionIsOff) { + const std::string text = R"(; SPIR-V +; Version: 1.6 +; Bound: 31 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + +; CHECK: OpEntryPoint GLCompute %main "main" %output_0_ %output_1_ + + OpEntryPoint GLCompute %main "main" %output + OpExecutionMode %main LocalSize 1 1 1 + OpSource HLSL 670 + OpName %type_RWByteAddressBuffer "type.RWByteAddressBuffer" + OpName %output "output" + OpName %main "main" + OpName %src_main "src.main" + OpName %bb_entry "bb.entry" + +; CHECK: OpDecorate %output_1_ DescriptorSet 0 +; CHECK: OpDecorate %output_1_ Binding 1 +; CHECK: OpDecorate %output_0_ DescriptorSet 0 +; CHECK: OpDecorate %output_0_ Binding 0 + + OpDecorate %output DescriptorSet 0 + OpDecorate %output Binding 0 + + OpDecorate %_runtimearr_uint ArrayStride 4 + OpMemberDecorate %type_RWByteAddressBuffer 0 Offset 0 + OpDecorate %type_RWByteAddressBuffer Block + %int = OpTypeInt 32 1 + %int_1 = OpConstant %int 1 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_2 = OpConstant %uint 2 + %uint_32 = OpConstant %uint 32 +%_runtimearr_uint = OpTypeRuntimeArray %uint +%type_RWByteAddressBuffer = OpTypeStruct %_runtimearr_uint +%_arr_type_RWByteAddressBuffer_uint_2 = OpTypeArray %type_RWByteAddressBuffer %uint_2 +%_ptr_StorageBuffer__arr_type_RWByteAddressBuffer_uint_2 = OpTypePointer StorageBuffer %_arr_type_RWByteAddressBuffer_uint_2 + %void = OpTypeVoid + %23 = OpTypeFunction %void +%_ptr_StorageBuffer_type_RWByteAddressBuffer = OpTypePointer StorageBuffer %type_RWByteAddressBuffer +%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint + +; CHECK: %output_1_ = OpVariable %_ptr_StorageBuffer_type_RWByteAddressBuffer StorageBuffer +; CHECK: %output_0_ = OpVariable %_ptr_StorageBuffer_type_RWByteAddressBuffer StorageBuffer + + %output = OpVariable %_ptr_StorageBuffer__arr_type_RWByteAddressBuffer_uint_2 StorageBuffer + + %main = OpFunction %void None %23 + %26 = OpLabel + %27 = OpFunctionCall %void %src_main + OpReturn + OpFunctionEnd + %src_main = OpFunction %void None %23 + %bb_entry = OpLabel + %28 = OpAccessChain %_ptr_StorageBuffer_type_RWByteAddressBuffer %output %int_1 + %29 = OpShiftRightLogical %uint %uint_0 %uint_2 + %30 = OpAccessChain %_ptr_StorageBuffer_uint %28 %uint_0 %29 + OpStore %30 %uint_32 + OpReturn + OpFunctionEnd + )"; + + SinglePassRunAndMatch( + text, false, /* flatten_composites=*/false, /* flatten_arrays=*/true); +} + +TEST_F(DescriptorScalarReplacementTest, ExpandStructButNotArray) { + const std::string text = R"(; SPIR-V +; Version: 1.6 +; Generator: Khronos SPIR-V Tools Assembler; 0 +; Bound: 41 +; Schema: 0 + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" %out_var_SV_Target + OpExecutionMode %main OriginUpperLeft + OpSource HLSL 660 + OpName %type_2d_image "type.2d.image" + OpName %Textures "Textures" + OpName %type_sampler "type.sampler" + OpName %out_var_SV_Target "out.var.SV_Target" + OpName %main "main" + OpName %type_sampled_image "type.sampled.image" + OpName %TheStruct "TheStruct" + OpMemberName %StructOfResources 0 "Texture" + OpMemberName %StructOfResources 1 "Sampler" +; CHECK: OpName %TheStruct_Sampler "TheStruct.Sampler" +; CHECK: OpName %TheStruct_Texture "TheStruct.Texture" + OpDecorate %out_var_SV_Target Location 0 + OpDecorate %Textures DescriptorSet 0 + OpDecorate %Textures Binding 0 + OpDecorate %TheStruct DescriptorSet 0 + OpDecorate %TheStruct Binding 10 +; CHECK: OpDecorate %TheStruct_Sampler DescriptorSet 0 +; CHECK: OpDecorate %TheStruct_Sampler Binding 11 +; CHECK: OpDecorate %TheStruct_Texture DescriptorSet 0 +; CHECK: OpDecorate %TheStruct_Texture Binding 10 + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %float = OpTypeFloat 32 + %float_0 = OpConstant %float 0 + %v2float = OpTypeVector %float 2 + %13 = OpConstantComposite %v2float %float_0 %float_0 + %uint = OpTypeInt 32 0 + %uint_10 = OpConstant %uint 10 + %type_2d_image = OpTypeImage %float 2D 2 0 0 1 Unknown + %_arr_type_2d_image_uint_10 = OpTypeArray %type_2d_image %uint_10 +%_ptr_UniformConstant__arr_type_2d_image_uint_10 = OpTypePointer UniformConstant %_arr_type_2d_image_uint_10 + %type_sampler = OpTypeSampler + %StructOfResources = OpTypeStruct %type_2d_image %type_sampler +%_ptr_UniformConstant__struct_18 = OpTypePointer UniformConstant %StructOfResources + %v4float = OpTypeVector %float 4 + %_ptr_Output_v4float = OpTypePointer Output %v4float + %void = OpTypeVoid + %23 = OpTypeFunction %void +%_ptr_UniformConstant_type_2d_image = OpTypePointer UniformConstant %type_2d_image + %_ptr_UniformConstant_type_sampler = OpTypePointer UniformConstant %type_sampler + %type_sampled_image = OpTypeSampledImage %type_2d_image + %Textures = OpVariable %_ptr_UniformConstant__arr_type_2d_image_uint_10 UniformConstant + %out_var_SV_Target = OpVariable %_ptr_Output_v4float Output + %TheStruct = OpVariable %_ptr_UniformConstant__struct_18 UniformConstant + %main = OpFunction %void None %23 + %26 = OpLabel + %27 = OpAccessChain %_ptr_UniformConstant_type_2d_image %Textures %int_0 + %28 = OpLoad %type_2d_image %27 + %29 = OpAccessChain %_ptr_UniformConstant_type_sampler %TheStruct %int_1 + %31 = OpLoad %type_sampler %29 +; CHECK: %31 = OpLoad %type_sampler %TheStruct_Sampler + %32 = OpSampledImage %type_sampled_image %28 %31 + %33 = OpImageSampleImplicitLod %v4float %32 %13 None + %34 = OpAccessChain %_ptr_UniformConstant_type_2d_image %TheStruct %int_0 + %35 = OpLoad %type_2d_image %34 +; CHECK: %35 = OpLoad %type_2d_image %TheStruct_Texture + %36 = OpAccessChain %_ptr_UniformConstant_type_sampler %TheStruct %int_1 + %37 = OpLoad %type_sampler %36 +; CHECK: %37 = OpLoad %type_sampler %TheStruct_Sampler + %38 = OpSampledImage %type_sampled_image %35 %37 + %39 = OpImageSampleImplicitLod %v4float %38 %13 None + %40 = OpFAdd %v4float %33 %39 + OpStore %out_var_SV_Target %40 + OpReturn + OpFunctionEnd + )"; + + SinglePassRunAndMatch( + text, false, /* flatten_composites=*/true, /* flatten_arrays=*/false); } } // namespace diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index f8456d7144..3b8d5fc236 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -181,6 +181,14 @@ Options (in lexicographical order):)", must be in OpAccessChain instructions with a literal index for the first index.)"); printf(R"( + --descriptor-composite-scalar-replacement + Same as descriptor-scalar-replacement, but only impacts composite/structs. + For details, see --descriptor-scalar-replacement help.)"); + printf(R"( + --descriptor-array-scalar-replacement + Same as descriptor-scalar-replacement, but only impacts arrays. + For details, see --descriptor-scalar-replacement help.)"); + printf(R"( --eliminate-dead-branches Convert conditional branches with constant condition to the indicated unconditional branch. Delete all resulting dead From 626dfbff49b53a5d054d4437d3bf3aa9ef85a6ee Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 19 Jul 2024 16:04:25 +0000 Subject: [PATCH 479/523] Roll external/abseil_cpp/ eb8522077..3cb498899 (4 commits) (#5741) https://github.com/abseil/abseil-cpp/compare/eb852207758a...3cb4988999d2 Created with: roll-dep external/abseil_cpp Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 56ca60c487..f914bc9967 100644 --- a/DEPS +++ b/DEPS @@ -3,7 +3,7 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': 'eb852207758a773965301d0ae717e4235fc5301a', + 'abseil_revision': '3cb4988999d2f16e11d86f9921e9526486ef1960', 'effcee_revision': '2c97e5689ed8d7ab6ae5820f884f03a601ae124b', From d1b35bb1712e90fd0d341b7b56fa27984c7b3b0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jul 2024 09:34:13 -0400 Subject: [PATCH 480/523] build(deps): bump the github-actions group with 2 updates (#5744) Bumps the github-actions group with 2 updates: [lukka/get-cmake](https://github.com/lukka/get-cmake) and [github/codeql-action](https://github.com/github/codeql-action). Updates `lukka/get-cmake` from 3.30.0 to 3.30.1 - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/983956e4a5edce90f0dfcc38c1543077e668402b...34181361be075620f7c3871daa1cadb92d9a903e) Updates `github/codeql-action` from 3.25.12 to 3.25.13 - [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/4fa2a7953630fd2f3fb380f21be14ede0169dd4f...2d790406f505036ef40ecba973cc774a50395aac) --- updated-dependencies: - dependency-name: lukka/get-cmake 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/ios.yml | 2 +- .github/workflows/scorecard.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 64f0459878..c859f8e21a 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@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: lukka/get-cmake@983956e4a5edce90f0dfcc38c1543077e668402b # v3.30.0 + - uses: lukka/get-cmake@34181361be075620f7c3871daa1cadb92d9a903e # v3.30.1 - name: Download dependencies run: python3 utils/git-sync-deps # NOTE: The MacOS SDK ships universal binaries. CI should reflect this. diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index f52dcbb068..344b0ba70d 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@4fa2a7953630fd2f3fb380f21be14ede0169dd4f # v3.25.12 + uses: github/codeql-action/upload-sarif@2d790406f505036ef40ecba973cc774a50395aac # v3.25.13 with: sarif_file: results.sarif From a0817526b8e391732632e6a887134be256a20a18 Mon Sep 17 00:00:00 2001 From: Ben Ashbaugh Date: Mon, 22 Jul 2024 08:18:16 -0700 Subject: [PATCH 481/523] properly handle the load and store cache control operand types (#5664) * properly handle the load and store cache control operand types Without handling these operand types, disassembling a SPIR-V module that uses the cache control extension produces an invalid operand type error. * add a round trip test for SPV_INTEL_cache_controls --- source/binary.cpp | 2 ++ test/binary_to_text_test.cpp | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/source/binary.cpp b/source/binary.cpp index b9bd7568ad..19098aa130 100644 --- a/source/binary.cpp +++ b/source/binary.cpp @@ -673,6 +673,8 @@ spv_result_t Parser::parseOperand(size_t inst_offset, case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT: case SPV_OPERAND_TYPE_FPENCODING: case SPV_OPERAND_TYPE_OPTIONAL_FPENCODING: + case SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL: + case SPV_OPERAND_TYPE_STORE_CACHE_CONTROL: case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS: { // A single word that is a plain enum value. diff --git a/test/binary_to_text_test.cpp b/test/binary_to_text_test.cpp index dd7569382f..4630a985f8 100644 --- a/test/binary_to_text_test.cpp +++ b/test/binary_to_text_test.cpp @@ -402,6 +402,22 @@ INSTANTIATE_TEST_SUITE_P( "OpDecorateId %1 MaxByteOffsetId %2\n", }))); +INSTANTIATE_TEST_SUITE_P( + CacheControlsINTEL, RoundTripInstructionsTest, + Combine( + ::testing::Values(SPV_ENV_UNIVERSAL_1_0), + ::testing::ValuesIn(std::vector{ + "OpDecorate %1 CacheControlLoadINTEL 0 UncachedINTEL\n", + "OpDecorate %1 CacheControlLoadINTEL 1 CachedINTEL\n", + "OpDecorate %1 CacheControlLoadINTEL 2 StreamingINTEL\n", + "OpDecorate %1 CacheControlLoadINTEL 3 InvalidateAfterReadINTEL\n", + "OpDecorate %1 CacheControlLoadINTEL 4 ConstCachedINTEL\n", + "OpDecorate %1 CacheControlStoreINTEL 0 UncachedINTEL\n", + "OpDecorate %1 CacheControlStoreINTEL 1 WriteThroughINTEL\n", + "OpDecorate %1 CacheControlStoreINTEL 2 WriteBackINTEL\n", + "OpDecorate %1 CacheControlStoreINTEL 3 StreamingINTEL\n", + }))); + using MaskSorting = TextToBinaryTest; TEST_F(MaskSorting, MasksAreSortedFromLSBToMSB) { From ca373497f1efac1eb555dde090789140ac51f513 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 24 Jul 2024 08:36:26 -0400 Subject: [PATCH 482/523] [opt] Fix pointer stores in DCE (#5739) When a trying to mark store that use the same address as a load live, we consider any use of the pointer in the store instruction enough to make the store live. This is not correct. We should only mark the store as live if it store to the pointer, and not storing the pointer to another memory location. This causes DCE to miss some dead code. --- source/opt/aggressive_dead_code_elim_pass.cpp | 7 +- test/opt/aggressive_dead_code_elim_test.cpp | 77 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp index 44432399ca..4f5b7230a4 100644 --- a/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/source/opt/aggressive_dead_code_elim_pass.cpp @@ -134,7 +134,12 @@ void AggressiveDCEPass::AddStores(Function* func, uint32_t ptrId) { } break; // If default, assume it stores e.g. frexp, modf, function call - case spv::Op::OpStore: + case spv::Op::OpStore: { + const uint32_t kStoreTargetAddrInIdx = 0; + if (user->GetSingleWordInOperand(kStoreTargetAddrInIdx) == ptrId) + AddToWorklist(user); + break; + } default: AddToWorklist(user); break; diff --git a/test/opt/aggressive_dead_code_elim_test.cpp b/test/opt/aggressive_dead_code_elim_test.cpp index 66f5887165..dcce4f5789 100644 --- a/test/opt/aggressive_dead_code_elim_test.cpp +++ b/test/opt/aggressive_dead_code_elim_test.cpp @@ -7992,6 +7992,83 @@ OpFunctionEnd SinglePassRunAndCheck(test, test, true, true); } +TEST_F(AggressiveDCETest, StoringAPointer) { + // A store that stores a pointer should not be kept live because the value + // being stored is eventually loaded from. + + const std::string text = R"( + OpCapability CooperativeMatrixKHR + OpCapability Shader + OpExtension "SPV_KHR_cooperative_matrix" + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" %2 + OpExecutionMode %1 LocalSize 64 1 1 + OpSource HLSL 600 + OpDecorate %2 DescriptorSet 0 + OpDecorate %2 Binding 0 + OpDecorate %_runtimearr_int ArrayStride 4 + OpMemberDecorate %_struct_4 0 Offset 0 + OpDecorate %_struct_4 Block + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %int_1 = OpConstant %int 1 + %uint = OpTypeInt 32 0 + %uint_0 = OpConstant %uint 0 + %uint_64 = OpConstant %uint 64 + %uint_3 = OpConstant %uint 3 + %uint_16 = OpConstant %uint 16 + %uint_4 = OpConstant %uint 4 +%_runtimearr_int = OpTypeRuntimeArray %int + %_struct_4 = OpTypeStruct %_runtimearr_int +%_ptr_StorageBuffer__struct_4 = OpTypePointer StorageBuffer %_struct_4 + %void = OpTypeVoid + %16 = OpTypeFunction %void +; CHECK: [[mat:%\w+]] = OpTypeCooperativeMatrixKHR %int %uint_3 %uint_16 %uint_4 %uint_0 + %17 = OpTypeCooperativeMatrixKHR %int %uint_3 %uint_16 %uint_4 %uint_0 +; CHECK: [[struct:%\w+]] = OpTypeStruct [[mat]] + %_struct_18 = OpTypeStruct %17 +; CHECK: [[ptr:%\w+]] = OpTypePointer Function [[struct]] +%_ptr_Function__struct_18 = OpTypePointer Function %_struct_18 +%_ptr_StorageBuffer_int = OpTypePointer StorageBuffer %int +%_ptr_Function_17 = OpTypePointer Function %17 +%_ptr_Function_int = OpTypePointer Function %int +%_ptr_Function__ptr_Function_int = OpTypePointer Function %_ptr_Function_int + %2 = OpVariable %_ptr_StorageBuffer__struct_4 StorageBuffer + +; The stored to the fist two variables should be removed and the variables +; as well. The only function scope variable should be the cooperative matrix. +; CHECK: OpFunction +; CHECK-NOT: OpVariable %_ptr_Function__ptr_Function_int Function +; CHECK: OpVariable [[ptr]] Function +; CHECK-NOT: OpVariable + %1 = OpFunction %void None %16 + %24 = OpLabel + %25 = OpVariable %_ptr_Function__ptr_Function_int Function + %26 = OpVariable %_ptr_Function__ptr_Function_int Function + %27 = OpVariable %_ptr_Function__struct_18 Function + %28 = OpAccessChain %_ptr_StorageBuffer_int %2 %int_0 %uint_0 + %29 = OpCooperativeMatrixLoadKHR %17 %28 %int_1 + %30 = OpCompositeConstruct %_struct_18 %29 + OpStore %27 %30 + %31 = OpAccessChain %_ptr_Function_17 %27 %int_0 + %32 = OpAccessChain %_ptr_Function_int %27 %int_0 %uint_0 + OpStore %26 %32 + %33 = OpLoad %int %32 + %34 = OpIAdd %int %33 %int_1 + OpStore %25 %32 + OpStore %32 %34 + %35 = OpAccessChain %_ptr_StorageBuffer_int %2 %int_0 %uint_64 + %36 = OpLoad %17 %31 + OpCooperativeMatrixStoreKHR %35 %36 %int_0 + OpReturn + OpFunctionEnd +)"; + + // For physical storage buffer support + SetTargetEnv(SPV_ENV_VULKAN_1_2); + SinglePassRunAndMatch(text, true); +} + } // namespace } // namespace opt } // namespace spvtools From e99a5c033ea2c933d0403b97db590212fb5a2542 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Wed, 24 Jul 2024 14:38:19 +0200 Subject: [PATCH 483/523] spirv-link: allow linking functions with different pointer arguments (#5534) * linker: run dedup earlier Otherwise `linkings_to_do` might end up with stale IDs. * linker: allow linking functions with different pointer arguments Since llvm-17 there are no typed pointers and hte SPIRV-LLVM-Translator doesn't know the function signature of imported functions. I'm investigating different ways of solving this problem and adding an option to work around it inside `spirv-link` is one of those. The code is almost complete, just I'm having troubles constructing the bitcast to cast the pointer parameters to the final type. Closes: https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/2153 * test/linker: add tests to test the AllowPtrTypeMismatch feature --- include/spirv-tools/linker.hpp | 7 +- source/link/linker.cpp | 123 +++++- .../link/matching_imports_to_exports_test.cpp | 393 +++++++++++++++++- tools/link/linker.cpp | 24 +- 4 files changed, 498 insertions(+), 49 deletions(-) diff --git a/include/spirv-tools/linker.hpp b/include/spirv-tools/linker.hpp index 6ba6e9654a..9037b94889 100644 --- a/include/spirv-tools/linker.hpp +++ b/include/spirv-tools/linker.hpp @@ -16,7 +16,6 @@ #define INCLUDE_SPIRV_TOOLS_LINKER_HPP_ #include - #include #include @@ -63,11 +62,17 @@ class SPIRV_TOOLS_EXPORT LinkerOptions { use_highest_version_ = use_highest_vers; } + bool GetAllowPtrTypeMismatch() const { return allow_ptr_type_mismatch_; } + void SetAllowPtrTypeMismatch(bool allow_ptr_type_mismatch) { + allow_ptr_type_mismatch_ = allow_ptr_type_mismatch; + } + private: bool create_library_{false}; bool verify_ids_{false}; bool allow_partial_linkage_{false}; bool use_highest_version_{false}; + bool allow_ptr_type_mismatch_{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 58930e452e..e6aa72e32c 100644 --- a/source/link/linker.cpp +++ b/source/link/linker.cpp @@ -31,6 +31,7 @@ #include "source/opt/build_module.h" #include "source/opt/compact_ids_pass.h" #include "source/opt/decoration_manager.h" +#include "source/opt/ir_builder.h" #include "source/opt/ir_loader.h" #include "source/opt/pass_manager.h" #include "source/opt/remove_duplicates_pass.h" @@ -46,12 +47,14 @@ namespace spvtools { namespace { using opt::Instruction; +using opt::InstructionBuilder; using opt::IRContext; using opt::Module; using opt::PassManager; using opt::RemoveDuplicatesPass; using opt::analysis::DecorationManager; using opt::analysis::DefUseManager; +using opt::analysis::Function; using opt::analysis::Type; using opt::analysis::TypeManager; @@ -126,6 +129,7 @@ spv_result_t GetImportExportPairs(const MessageConsumer& consumer, // checked. spv_result_t CheckImportExportCompatibility(const MessageConsumer& consumer, const LinkageTable& linkings_to_do, + bool allow_ptr_type_mismatch, opt::IRContext* context); // Remove linkage specific instructions, such as prototypes of imported @@ -502,6 +506,7 @@ spv_result_t GetImportExportPairs(const MessageConsumer& consumer, spv_result_t CheckImportExportCompatibility(const MessageConsumer& consumer, const LinkageTable& linkings_to_do, + bool allow_ptr_type_mismatch, opt::IRContext* context) { spv_position_t position = {}; @@ -513,7 +518,34 @@ spv_result_t CheckImportExportCompatibility(const MessageConsumer& consumer, type_manager.GetType(linking_entry.imported_symbol.type_id); Type* exported_symbol_type = type_manager.GetType(linking_entry.exported_symbol.type_id); - if (!(*imported_symbol_type == *exported_symbol_type)) + if (!(*imported_symbol_type == *exported_symbol_type)) { + Function* imported_symbol_type_func = imported_symbol_type->AsFunction(); + Function* exported_symbol_type_func = exported_symbol_type->AsFunction(); + + if (imported_symbol_type_func && exported_symbol_type_func) { + const auto& imported_params = imported_symbol_type_func->param_types(); + const auto& exported_params = exported_symbol_type_func->param_types(); + // allow_ptr_type_mismatch allows linking functions where the pointer + // type of arguments doesn't match. Everything else still needs to be + // equal. This is to workaround LLVM-17+ not having typed pointers and + // generated SPIR-Vs not knowing the actual pointer types in some cases. + if (allow_ptr_type_mismatch && + imported_params.size() == exported_params.size()) { + bool correct = true; + for (size_t i = 0; i < imported_params.size(); i++) { + const auto& imported_param = imported_params[i]; + const auto& exported_param = exported_params[i]; + + if (!imported_param->IsSame(exported_param) && + (imported_param->kind() != Type::kPointer || + exported_param->kind() != Type::kPointer)) { + correct = false; + break; + } + } + if (correct) continue; + } + } return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY) << "Type mismatch on symbol \"" << linking_entry.imported_symbol.name @@ -521,6 +553,7 @@ spv_result_t CheckImportExportCompatibility(const MessageConsumer& consumer, << linking_entry.imported_symbol.id << " and exported variable/function %" << linking_entry.exported_symbol.id << "."; + } } // Ensure the import and export decorations are similar @@ -696,6 +729,57 @@ spv_result_t VerifyLimits(const MessageConsumer& consumer, return SPV_SUCCESS; } +spv_result_t FixFunctionCallTypes(opt::IRContext& context, + const LinkageTable& linkings) { + auto mod = context.module(); + const auto type_manager = context.get_type_mgr(); + const auto def_use_mgr = context.get_def_use_mgr(); + + for (auto& func : *mod) { + func.ForEachInst([&](Instruction* inst) { + if (inst->opcode() != spv::Op::OpFunctionCall) return; + opt::Operand& target = inst->GetInOperand(0); + + // only fix calls to imported functions + auto linking = std::find_if( + linkings.begin(), linkings.end(), [&](const auto& entry) { + return entry.exported_symbol.id == target.AsId(); + }); + if (linking == linkings.end()) return; + + auto builder = InstructionBuilder(&context, inst); + for (uint32_t i = 1; i < inst->NumInOperands(); ++i) { + auto exported_func_param = + def_use_mgr->GetDef(linking->exported_symbol.parameter_ids[i - 1]); + const Type* target_type = + type_manager->GetType(exported_func_param->type_id()); + if (target_type->kind() != Type::kPointer) continue; + + opt::Operand& arg = inst->GetInOperand(i); + const Type* param_type = + type_manager->GetType(def_use_mgr->GetDef(arg.AsId())->type_id()); + + // No need to cast if it already matches + if (*param_type == *target_type) continue; + + auto new_id = context.TakeNextId(); + + // cast to the expected pointer type + builder.AddInstruction(MakeUnique( + &context, spv::Op::OpBitcast, exported_func_param->type_id(), + new_id, + opt::Instruction::OperandList( + {{SPV_OPERAND_TYPE_ID, {arg.AsId()}}}))); + + inst->SetInOperand(i, {new_id}); + } + }); + } + context.InvalidateAnalyses(opt::IRContext::kAnalysisDefUse | + opt::IRContext::kAnalysisInstrToBlockMapping); + return SPV_SUCCESS; +} + } // namespace spv_result_t Link(const Context& context, @@ -773,7 +857,14 @@ spv_result_t Link(const Context& context, const uint32_t* const* binaries, if (res != SPV_SUCCESS) return res; } - // Phase 4: Find the import/export pairs + // Phase 4: Remove duplicates + PassManager manager; + manager.SetMessageConsumer(consumer); + manager.AddPass(); + opt::Pass::Status pass_res = manager.Run(&linked_context); + if (pass_res == opt::Pass::Status::Failure) return SPV_ERROR_INVALID_DATA; + + // Phase 5: Find the import/export pairs LinkageTable linkings_to_do; res = GetImportExportPairs(consumer, linked_context, *linked_context.get_def_use_mgr(), @@ -781,18 +872,12 @@ spv_result_t Link(const Context& context, const uint32_t* const* binaries, options.GetAllowPartialLinkage(), &linkings_to_do); if (res != SPV_SUCCESS) return res; - // Phase 5: Ensure the import and export have the same types and decorations. - res = - CheckImportExportCompatibility(consumer, linkings_to_do, &linked_context); + // Phase 6: Ensure the import and export have the same types and decorations. + res = CheckImportExportCompatibility(consumer, linkings_to_do, + options.GetAllowPtrTypeMismatch(), + &linked_context); if (res != SPV_SUCCESS) return res; - // Phase 6: Remove duplicates - PassManager manager; - manager.SetMessageConsumer(consumer); - manager.AddPass(); - opt::Pass::Status pass_res = manager.Run(&linked_context); - if (pass_res == opt::Pass::Status::Failure) return SPV_ERROR_INVALID_DATA; - // Phase 7: Remove all names and decorations of import variables/functions for (const auto& linking_entry : linkings_to_do) { linked_context.KillNamesAndDecorates(linking_entry.imported_symbol.id); @@ -815,21 +900,27 @@ spv_result_t Link(const Context& context, const uint32_t* const* binaries, &linked_context); if (res != SPV_SUCCESS) return res; - // Phase 10: Compact the IDs used in the module + // Phase 10: Optionally fix function call types + if (options.GetAllowPtrTypeMismatch()) { + res = FixFunctionCallTypes(linked_context, linkings_to_do); + if (res != SPV_SUCCESS) return res; + } + + // Phase 11: Compact the IDs used in the module manager.AddPass(); pass_res = manager.Run(&linked_context); if (pass_res == opt::Pass::Status::Failure) return SPV_ERROR_INVALID_DATA; - // Phase 11: Recompute EntryPoint variables + // Phase 12: Recompute EntryPoint variables manager.AddPass(); pass_res = manager.Run(&linked_context); if (pass_res == opt::Pass::Status::Failure) return SPV_ERROR_INVALID_DATA; - // Phase 12: Warn if SPIR-V limits were exceeded + // Phase 13: Warn if SPIR-V limits were exceeded res = VerifyLimits(consumer, linked_context); if (res != SPV_SUCCESS) return res; - // Phase 13: Output the module + // Phase 14: Output the module linked_context.module()->ToBinary(linked_binary, true); return SPV_SUCCESS; diff --git a/test/link/matching_imports_to_exports_test.cpp b/test/link/matching_imports_to_exports_test.cpp index 6b02fc46dd..c7c962fa20 100644 --- a/test/link/matching_imports_to_exports_test.cpp +++ b/test/link/matching_imports_to_exports_test.cpp @@ -174,14 +174,18 @@ OpDecorate %1 LinkageAttributes "foo" Export %1 = OpVariable %2 Uniform %3 )"; - spvtest::Binary linked_binary; - EXPECT_EQ(SPV_ERROR_INVALID_BINARY, - AssembleAndLink({body1, body2}, &linked_binary)) - << GetErrorMessage(); - EXPECT_THAT( - GetErrorMessage(), - HasSubstr("Type mismatch on symbol \"foo\" between imported " - "variable/function %1 and exported variable/function %4")); + LinkerOptions options; + for (int i = 0; i < 2; i++) { + spvtest::Binary linked_binary; + options.SetAllowPtrTypeMismatch(i == 1); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, + AssembleAndLink({body1, body2}, &linked_binary)) + << GetErrorMessage(); + EXPECT_THAT( + GetErrorMessage(), + HasSubstr("Type mismatch on symbol \"foo\" between imported " + "variable/function %1 and exported variable/function %4")); + } } TEST_F(MatchingImportsToExports, MultipleDefinitions) { @@ -216,13 +220,17 @@ OpDecorate %1 LinkageAttributes "foo" Export %1 = OpVariable %2 Uniform %3 )"; - spvtest::Binary linked_binary; - EXPECT_EQ(SPV_ERROR_INVALID_BINARY, - AssembleAndLink({body1, body2, body3}, &linked_binary)) - << GetErrorMessage(); - EXPECT_THAT(GetErrorMessage(), - HasSubstr("Too many external references, 2, were found " - "for \"foo\".")); + LinkerOptions options; + for (int i = 0; i < 2; i++) { + spvtest::Binary linked_binary; + options.SetAllowPtrTypeMismatch(i == 1); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, + AssembleAndLink({body1, body2, body3}, &linked_binary)) + << GetErrorMessage(); + EXPECT_THAT(GetErrorMessage(), + HasSubstr("Too many external references, 2, were found " + "for \"foo\".")); + } } TEST_F(MatchingImportsToExports, SameNameDifferentTypes) { @@ -289,14 +297,18 @@ OpDecorate %1 LinkageAttributes "foo" Export %1 = OpVariable %2 Uniform %3 )"; - spvtest::Binary linked_binary; - EXPECT_EQ(SPV_ERROR_INVALID_BINARY, - AssembleAndLink({body1, body2}, &linked_binary)) - << GetErrorMessage(); - EXPECT_THAT( - GetErrorMessage(), - HasSubstr("Type mismatch on symbol \"foo\" between imported " - "variable/function %1 and exported variable/function %4")); + LinkerOptions options; + for (int i = 0; i < 2; i++) { + spvtest::Binary linked_binary; + options.SetAllowPtrTypeMismatch(i == 1); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, + AssembleAndLink({body1, body2}, &linked_binary)) + << GetErrorMessage(); + EXPECT_THAT( + GetErrorMessage(), + HasSubstr("Type mismatch on symbol \"foo\" between imported " + "variable/function %1 and exported variable/function %4")); + } } TEST_F(MatchingImportsToExports, @@ -557,5 +569,340 @@ OpFunctionEnd EXPECT_EQ(expected_res, res_body); } +TEST_F(MatchingImportsToExports, FunctionCall) { + const std::string body1 = R"( +OpCapability Linkage +OpCapability Addresses +OpCapability Kernel +OpMemoryModel Physical64 OpenCL +OpName %1 "foo" +OpName %3 "param" +OpDecorate %1 LinkageAttributes "foo" Import + %5 = OpTypeVoid + %6 = OpTypeInt 32 0 + %9 = OpTypePointer Function %6 + %7 = OpTypeFunction %5 %9 + %1 = OpFunction %5 None %7 + %3 = OpFunctionParameter %9 +OpFunctionEnd + %8 = OpFunction %5 None %7 + %4 = OpFunctionParameter %9 +%10 = OpLabel +%11 = OpFunctionCall %5 %1 %4 +OpReturn +OpFunctionEnd +)"; + const std::string body2 = R"( +OpCapability Linkage +OpCapability Addresses +OpCapability Kernel +OpMemoryModel Physical64 OpenCL +OpName %1 "foo" +OpName %2 "param" +OpDecorate %1 LinkageAttributes "foo" Export +%3 = OpTypeVoid +%4 = OpTypeInt 32 0 +%7 = OpTypePointer Function %4 +%5 = OpTypeFunction %3 %7 +%1 = OpFunction %3 None %5 +%2 = OpFunctionParameter %7 +%6 = OpLabel +OpReturn +OpFunctionEnd +)"; + + LinkerOptions options; + for (int i = 0; i < 2; i++) { + spvtest::Binary linked_binary; + options.SetAllowPtrTypeMismatch(i == 1); + ASSERT_EQ(SPV_SUCCESS, + AssembleAndLink({body1, body2}, &linked_binary, options)) + << GetErrorMessage(); + + const std::string expected_res = R"(OpCapability Addresses +OpCapability Kernel +OpMemoryModel Physical64 OpenCL +OpName %1 "foo" +OpName %2 "param" +OpModuleProcessed "Linked by SPIR-V Tools Linker" +%3 = OpTypeVoid +%4 = OpTypeInt 32 0 +%5 = OpTypePointer Function %4 +%6 = OpTypeFunction %3 %5 +%7 = OpFunction %3 None %6 +%8 = OpFunctionParameter %5 +%9 = OpLabel +%10 = OpFunctionCall %3 %1 %8 +OpReturn +OpFunctionEnd +%1 = OpFunction %3 None %6 +%2 = OpFunctionParameter %5 +%11 = OpLabel +OpReturn +OpFunctionEnd +)"; + + std::string res_body; + SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); + ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body)) + << GetErrorMessage(); + EXPECT_EQ(expected_res, res_body); + } +} + +TEST_F(MatchingImportsToExports, FunctionSignatureMismatchPointer) { + const std::string body1 = R"( +OpCapability Linkage +OpCapability Addresses +OpCapability Kernel +OpMemoryModel Physical64 OpenCL +OpName %1 "foo" +OpName %3 "param" +OpDecorate %1 LinkageAttributes "foo" Import + %5 = OpTypeVoid + %6 = OpTypeInt 8 0 + %9 = OpTypePointer Function %6 + %7 = OpTypeFunction %5 %9 + %1 = OpFunction %5 None %7 + %3 = OpFunctionParameter %9 +OpFunctionEnd + %8 = OpFunction %5 None %7 + %4 = OpFunctionParameter %9 +%10 = OpLabel +%11 = OpFunctionCall %5 %1 %4 +OpReturn +OpFunctionEnd +)"; + const std::string body2 = R"( +OpCapability Linkage +OpCapability Addresses +OpCapability Kernel +OpMemoryModel Physical64 OpenCL +OpName %1 "foo" +OpName %2 "param" +OpDecorate %1 LinkageAttributes "foo" Export +%3 = OpTypeVoid +%4 = OpTypeInt 32 0 +%7 = OpTypePointer Function %4 +%5 = OpTypeFunction %3 %7 +%1 = OpFunction %3 None %5 +%2 = OpFunctionParameter %7 +%6 = OpLabel +OpReturn +OpFunctionEnd +)"; + + spvtest::Binary linked_binary; + ASSERT_EQ(SPV_ERROR_INVALID_BINARY, + AssembleAndLink({body1, body2}, &linked_binary)) + << GetErrorMessage(); + EXPECT_THAT( + GetErrorMessage(), + HasSubstr("Type mismatch on symbol \"foo\" between imported " + "variable/function %1 and exported variable/function %11")); + + LinkerOptions options; + options.SetAllowPtrTypeMismatch(true); + ASSERT_EQ(SPV_SUCCESS, + AssembleAndLink({body1, body2}, &linked_binary, options)) + << GetErrorMessage(); + + const std::string expected_res = R"(OpCapability Addresses +OpCapability Kernel +OpMemoryModel Physical64 OpenCL +OpName %1 "foo" +OpName %2 "param" +OpModuleProcessed "Linked by SPIR-V Tools Linker" +%3 = OpTypeVoid +%4 = OpTypeInt 8 0 +%5 = OpTypePointer Function %4 +%6 = OpTypeFunction %3 %5 +%7 = OpTypeInt 32 0 +%8 = OpTypePointer Function %7 +%9 = OpTypeFunction %3 %8 +%10 = OpFunction %3 None %6 +%11 = OpFunctionParameter %5 +%12 = OpLabel +%13 = OpBitcast %8 %11 +%14 = OpFunctionCall %3 %1 %13 +OpReturn +OpFunctionEnd +%1 = OpFunction %3 None %9 +%2 = OpFunctionParameter %8 +%15 = OpLabel +OpReturn +OpFunctionEnd +)"; + std::string res_body; + SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); + ASSERT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body)) + << GetErrorMessage(); + EXPECT_EQ(expected_res, res_body); +} + +TEST_F(MatchingImportsToExports, FunctionSignatureMismatchValue) { + const std::string body1 = R"( +OpCapability Linkage +OpCapability Addresses +OpCapability Kernel +OpMemoryModel Physical64 OpenCL +OpName %1 "foo" +OpName %3 "param" +OpDecorate %1 LinkageAttributes "foo" Import + %5 = OpTypeVoid + %6 = OpTypeInt 8 0 + %7 = OpTypeFunction %5 %6 + %1 = OpFunction %5 None %7 + %3 = OpFunctionParameter %6 +OpFunctionEnd + %8 = OpFunction %5 None %7 + %4 = OpFunctionParameter %6 +%10 = OpLabel +%11 = OpFunctionCall %5 %1 %4 +OpReturn +OpFunctionEnd +)"; + const std::string body2 = R"( +OpCapability Linkage +OpCapability Addresses +OpCapability Kernel +OpMemoryModel Physical64 OpenCL +OpName %1 "foo" +OpName %2 "param" +OpDecorate %1 LinkageAttributes "foo" Export +%3 = OpTypeVoid +%4 = OpTypeInt 32 0 +%5 = OpTypeFunction %3 %4 +%1 = OpFunction %3 None %5 +%2 = OpFunctionParameter %4 +%6 = OpLabel +OpReturn +OpFunctionEnd +)"; + + LinkerOptions options; + for (int i = 0; i < 2; i++) { + spvtest::Binary linked_binary; + options.SetAllowPtrTypeMismatch(i == 1); + ASSERT_EQ(SPV_ERROR_INVALID_BINARY, + AssembleAndLink({body1, body2}, &linked_binary)) + << GetErrorMessage(); + EXPECT_THAT( + GetErrorMessage(), + HasSubstr("Type mismatch on symbol \"foo\" between imported " + "variable/function %1 and exported variable/function %10")); + } +} + +TEST_F(MatchingImportsToExports, FunctionSignatureMismatchTypePointerInt) { + const std::string body1 = R"( +OpCapability Linkage +OpCapability Addresses +OpCapability Kernel +OpMemoryModel Physical64 OpenCL +OpName %1 "foo" +OpName %3 "param" +OpDecorate %1 LinkageAttributes "foo" Import + %5 = OpTypeVoid + %6 = OpTypeInt 64 0 + %7 = OpTypeFunction %5 %6 + %1 = OpFunction %5 None %7 + %3 = OpFunctionParameter %6 +OpFunctionEnd + %8 = OpFunction %5 None %7 + %4 = OpFunctionParameter %6 +%10 = OpLabel +%11 = OpFunctionCall %5 %1 %4 +OpReturn +OpFunctionEnd +)"; + const std::string body2 = R"( +OpCapability Linkage +OpCapability Addresses +OpCapability Kernel +OpMemoryModel Physical64 OpenCL +OpName %1 "foo" +OpName %2 "param" +OpDecorate %1 LinkageAttributes "foo" Export +%3 = OpTypeVoid +%4 = OpTypeInt 64 0 +%7 = OpTypePointer Function %4 +%5 = OpTypeFunction %3 %7 +%1 = OpFunction %3 None %5 +%2 = OpFunctionParameter %7 +%6 = OpLabel +OpReturn +OpFunctionEnd +)"; + + LinkerOptions options; + for (int i = 0; i < 2; i++) { + spvtest::Binary linked_binary; + options.SetAllowPtrTypeMismatch(i == 1); + ASSERT_EQ(SPV_ERROR_INVALID_BINARY, + AssembleAndLink({body1, body2}, &linked_binary)) + << GetErrorMessage(); + EXPECT_THAT( + GetErrorMessage(), + HasSubstr("Type mismatch on symbol \"foo\" between imported " + "variable/function %1 and exported variable/function %10")); + } +} + +TEST_F(MatchingImportsToExports, FunctionSignatureMismatchTypeIntPointer) { + const std::string body1 = R"( +OpCapability Linkage +OpCapability Addresses +OpCapability Kernel +OpMemoryModel Physical64 OpenCL +OpName %1 "foo" +OpName %3 "param" +OpDecorate %1 LinkageAttributes "foo" Import + %5 = OpTypeVoid + %6 = OpTypeInt 64 0 + %9 = OpTypePointer Function %6 + %7 = OpTypeFunction %5 %9 + %1 = OpFunction %5 None %7 + %3 = OpFunctionParameter %9 +OpFunctionEnd + %8 = OpFunction %5 None %7 + %4 = OpFunctionParameter %9 +%10 = OpLabel +%11 = OpFunctionCall %5 %1 %4 +OpReturn +OpFunctionEnd +)"; + const std::string body2 = R"( +OpCapability Linkage +OpCapability Addresses +OpCapability Kernel +OpMemoryModel Physical64 OpenCL +OpName %1 "foo" +OpName %2 "param" +OpDecorate %1 LinkageAttributes "foo" Export +%3 = OpTypeVoid +%4 = OpTypeInt 64 0 +%5 = OpTypeFunction %3 %4 +%1 = OpFunction %3 None %5 +%2 = OpFunctionParameter %4 +%6 = OpLabel +OpReturn +OpFunctionEnd +)"; + + LinkerOptions options; + for (int i = 0; i < 2; i++) { + spvtest::Binary linked_binary; + options.SetAllowPtrTypeMismatch(i == 1); + ASSERT_EQ(SPV_ERROR_INVALID_BINARY, + AssembleAndLink({body1, body2}, &linked_binary)) + << GetErrorMessage(); + EXPECT_THAT( + GetErrorMessage(), + HasSubstr("Type mismatch on symbol \"foo\" between imported " + "variable/function %1 and exported variable/function %11")); + } +} + } // namespace } // namespace spvtools diff --git a/tools/link/linker.cpp b/tools/link/linker.cpp index f3898aab0d..7dbd8596fa 100644 --- a/tools/link/linker.cpp +++ b/tools/link/linker.cpp @@ -48,6 +48,10 @@ Options (in lexicographical order): --allow-partial-linkage Allow partial linkage by accepting imported symbols to be unresolved. + --allow-pointer-mismatch + Allow pointer function parameters to mismatch the target link + target. This is useful to workaround lost correct parameter type + information due to LLVM's opaque pointers. --create-library Link the binaries into a library, keeping all exported symbols. -h, --help @@ -77,15 +81,16 @@ Options (in lexicographical order): } // namespace // clang-format off -FLAG_SHORT_bool( h, /* default_value= */ false, /* required= */ false); -FLAG_LONG_bool( help, /* default_value= */ false, /* required= */false); -FLAG_LONG_bool( version, /* default_value= */ false, /* required= */ false); -FLAG_LONG_bool( verify_ids, /* default_value= */ false, /* required= */ false); -FLAG_LONG_bool( create_library, /* default_value= */ false, /* required= */ 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); +FLAG_SHORT_bool( h, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( help, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( version, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( verify_ids, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( create_library, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( allow_partial_linkage, /* default_value= */ false, /* required= */ false); +FLAG_LONG_bool( allow_pointer_mismatch, /* 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[]) { @@ -126,6 +131,7 @@ int main(int, const char* argv[]) { spvtools::LinkerOptions options; options.SetAllowPartialLinkage(flags::allow_partial_linkage.value()); + options.SetAllowPtrTypeMismatch(flags::allow_pointer_mismatch.value()); options.SetCreateLibrary(flags::create_library.value()); options.SetVerifyIds(flags::verify_ids.value()); options.SetUseHighestVersion(flags::use_highest_version.value()); From 81a116002b2847c1c86e54f3418a0480b984e6b6 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 24 Jul 2024 08:42:00 -0400 Subject: [PATCH 484/523] [opt] Fix uses of type manager in fix storage class (#5740) This removes some uses of the type manager. One use could not be removed. Instead I had to update GenCopy to not use the type manager, and be able to copy pointers. Part of #5691 --- source/opt/fix_storage_class.cpp | 44 +++++++++----- source/opt/pass.cpp | 92 ++++++++++++++--------------- test/opt/fix_storage_class_test.cpp | 34 +++++++++++ 3 files changed, 108 insertions(+), 62 deletions(-) diff --git a/source/opt/fix_storage_class.cpp b/source/opt/fix_storage_class.cpp index 6345667f88..367418d77a 100644 --- a/source/opt/fix_storage_class.cpp +++ b/source/opt/fix_storage_class.cpp @@ -141,22 +141,26 @@ bool FixStorageClass::IsPointerResultType(Instruction* inst) { if (inst->type_id() == 0) { return false; } - const analysis::Type* ret_type = - context()->get_type_mgr()->GetType(inst->type_id()); - return ret_type->AsPointer() != nullptr; + + Instruction* type_def = get_def_use_mgr()->GetDef(inst->type_id()); + return type_def->opcode() == spv::Op::OpTypePointer; } bool FixStorageClass::IsPointerToStorageClass(Instruction* inst, spv::StorageClass storage_class) { - analysis::TypeManager* type_mgr = context()->get_type_mgr(); - analysis::Type* pType = type_mgr->GetType(inst->type_id()); - const analysis::Pointer* result_type = pType->AsPointer(); + if (inst->type_id() == 0) { + return false; + } - if (result_type == nullptr) { + Instruction* type_def = get_def_use_mgr()->GetDef(inst->type_id()); + if (type_def->opcode() != spv::Op::OpTypePointer) { return false; } - return (result_type->storage_class() == storage_class); + const uint32_t kPointerTypeStorageClassIndex = 0; + spv::StorageClass pointer_storage_class = static_cast( + type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex)); + return pointer_storage_class == storage_class; } bool FixStorageClass::ChangeResultType(Instruction* inst, @@ -301,9 +305,11 @@ uint32_t FixStorageClass::WalkAccessChainType(Instruction* inst, uint32_t id) { break; } - Instruction* orig_type_inst = get_def_use_mgr()->GetDef(id); - assert(orig_type_inst->opcode() == spv::Op::OpTypePointer); - id = orig_type_inst->GetSingleWordInOperand(1); + Instruction* id_type_inst = get_def_use_mgr()->GetDef(id); + assert(id_type_inst->opcode() == spv::Op::OpTypePointer); + id = id_type_inst->GetSingleWordInOperand(1); + spv::StorageClass input_storage_class = + static_cast(id_type_inst->GetSingleWordInOperand(0)); for (uint32_t i = start_idx; i < inst->NumInOperands(); ++i) { Instruction* type_inst = get_def_use_mgr()->GetDef(id); @@ -336,9 +342,19 @@ uint32_t FixStorageClass::WalkAccessChainType(Instruction* inst, uint32_t id) { "Tried to extract from an object where it cannot be done."); } - return context()->get_type_mgr()->FindPointerToType( - id, static_cast( - orig_type_inst->GetSingleWordInOperand(0))); + Instruction* orig_type_inst = get_def_use_mgr()->GetDef(inst->type_id()); + spv::StorageClass orig_storage_class = + static_cast(orig_type_inst->GetSingleWordInOperand(0)); + assert(orig_type_inst->opcode() == spv::Op::OpTypePointer); + if (orig_type_inst->GetSingleWordInOperand(1) == id && + input_storage_class == orig_storage_class) { + // The existing type is correct. Avoid the search for the type. Note that if + // there is a duplicate type, the search below could return a different type + // forcing more changes to the code than necessary. + return inst->type_id(); + } + + return context()->get_type_mgr()->FindPointerToType(id, input_storage_class); } // namespace opt diff --git a/source/opt/pass.cpp b/source/opt/pass.cpp index 75c37407fd..28f26c5868 100644 --- a/source/opt/pass.cpp +++ b/source/opt/pass.cpp @@ -83,7 +83,6 @@ uint32_t Pass::GetNullId(uint32_t type_id) { uint32_t Pass::GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id, Instruction* insertion_position) { - analysis::TypeManager* type_mgr = context()->get_type_mgr(); analysis::ConstantManager* const_mgr = context()->get_constant_mgr(); uint32_t original_type_id = object_to_copy->type_id(); @@ -95,55 +94,52 @@ uint32_t Pass::GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id, context(), insertion_position, IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisDefUse); - analysis::Type* original_type = type_mgr->GetType(original_type_id); - analysis::Type* new_type = type_mgr->GetType(new_type_id); - - if (const analysis::Array* original_array_type = original_type->AsArray()) { - uint32_t original_element_type_id = - type_mgr->GetId(original_array_type->element_type()); - - analysis::Array* new_array_type = new_type->AsArray(); - assert(new_array_type != nullptr && "Can't copy an array to a non-array."); - uint32_t new_element_type_id = - type_mgr->GetId(new_array_type->element_type()); - - std::vector element_ids; - const analysis::Constant* length_const = - const_mgr->FindDeclaredConstant(original_array_type->LengthId()); - assert(length_const->AsIntConstant()); - uint32_t array_length = length_const->AsIntConstant()->GetU32(); - for (uint32_t i = 0; i < array_length; i++) { - Instruction* extract = ir_builder.AddCompositeExtract( - original_element_type_id, object_to_copy->result_id(), {i}); - element_ids.push_back( - GenerateCopy(extract, new_element_type_id, insertion_position)); + Instruction* original_type = get_def_use_mgr()->GetDef(original_type_id); + Instruction* new_type = get_def_use_mgr()->GetDef(new_type_id); + assert(new_type->opcode() == original_type->opcode() && + "Can't copy an aggragate type unless the type correspond."); + + switch (original_type->opcode()) { + case spv::Op::OpTypeArray: { + uint32_t original_element_type_id = + original_type->GetSingleWordInOperand(0); + uint32_t new_element_type_id = new_type->GetSingleWordInOperand(0); + + std::vector element_ids; + uint32_t length_id = original_type->GetSingleWordInOperand(1); + const analysis::Constant* length_const = + const_mgr->FindDeclaredConstant(length_id); + assert(length_const->AsIntConstant()); + uint32_t array_length = length_const->AsIntConstant()->GetU32(); + for (uint32_t i = 0; i < array_length; i++) { + Instruction* extract = ir_builder.AddCompositeExtract( + original_element_type_id, object_to_copy->result_id(), {i}); + element_ids.push_back( + GenerateCopy(extract, new_element_type_id, insertion_position)); + } + + return ir_builder.AddCompositeConstruct(new_type_id, element_ids) + ->result_id(); } - - return ir_builder.AddCompositeConstruct(new_type_id, element_ids) - ->result_id(); - } else if (const analysis::Struct* original_struct_type = - original_type->AsStruct()) { - analysis::Struct* new_struct_type = new_type->AsStruct(); - - const std::vector& original_types = - original_struct_type->element_types(); - const std::vector& new_types = - new_struct_type->element_types(); - std::vector element_ids; - for (uint32_t i = 0; i < original_types.size(); i++) { - Instruction* extract = ir_builder.AddCompositeExtract( - type_mgr->GetId(original_types[i]), object_to_copy->result_id(), {i}); - element_ids.push_back(GenerateCopy(extract, type_mgr->GetId(new_types[i]), - insertion_position)); + case spv::Op::OpTypeStruct: { + std::vector element_ids; + for (uint32_t i = 0; i < original_type->NumInOperands(); i++) { + uint32_t orig_member_type_id = original_type->GetSingleWordInOperand(i); + uint32_t new_member_type_id = new_type->GetSingleWordInOperand(i); + Instruction* extract = ir_builder.AddCompositeExtract( + orig_member_type_id, object_to_copy->result_id(), {i}); + element_ids.push_back( + GenerateCopy(extract, new_member_type_id, insertion_position)); + } + return ir_builder.AddCompositeConstruct(new_type_id, element_ids) + ->result_id(); } - return ir_builder.AddCompositeConstruct(new_type_id, element_ids) - ->result_id(); - } else { - // If we do not have an aggregate type, then we have a problem. Either we - // found multiple instances of the same type, or we are copying to an - // incompatible type. Either way the code is illegal. - assert(false && - "Don't know how to copy this type. Code is likely illegal."); + default: + // If we do not have an aggregate type, then we have a problem. Either we + // found multiple instances of the same type, or we are copying to an + // incompatible type. Either way the code is illegal. + assert(false && + "Don't know how to copy this type. Code is likely illegal."); } return 0; } diff --git a/test/opt/fix_storage_class_test.cpp b/test/opt/fix_storage_class_test.cpp index 18afccbe72..410f140ea9 100644 --- a/test/opt/fix_storage_class_test.cpp +++ b/test/opt/fix_storage_class_test.cpp @@ -953,6 +953,40 @@ OpFunctionEnd SinglePassRunAndCheck(text, text, false, false); } +// Tests that the pass is not confused when there are multiple definitions +// of a pointer type to the same type with the same storage class. +TEST_F(FixStorageClassTest, DuplicatePointerType) { + const std::string text = R"(OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %1 "main" +OpExecutionMode %1 LocalSize 64 1 1 +OpSource HLSL 600 +%uint = OpTypeInt 32 0 +%uint_0 = OpConstant %uint 0 +%uint_3 = OpConstant %uint 3 +%_arr_uint_uint_3 = OpTypeArray %uint %uint_3 +%void = OpTypeVoid +%7 = OpTypeFunction %void +%_struct_8 = OpTypeStruct %_arr_uint_uint_3 +%_ptr_Function__struct_8 = OpTypePointer Function %_struct_8 +%_ptr_Function_uint = OpTypePointer Function %uint +%_ptr_Function__arr_uint_uint_3 = OpTypePointer Function %_arr_uint_uint_3 +%_ptr_Function_uint_0 = OpTypePointer Function %uint +%_ptr_Function__ptr_Function_uint_0 = OpTypePointer Function %_ptr_Function_uint_0 +%1 = OpFunction %void None %7 +%14 = OpLabel +%15 = OpVariable %_ptr_Function__ptr_Function_uint_0 Function +%16 = OpVariable %_ptr_Function__struct_8 Function +%17 = OpAccessChain %_ptr_Function__arr_uint_uint_3 %16 %uint_0 +%18 = OpAccessChain %_ptr_Function_uint_0 %17 %uint_0 +OpStore %15 %18 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndCheck(text, text, false); +} + } // namespace } // namespace opt } // namespace spvtools From ffb8d85eac107e8a7442d5166bceac1dae8c6409 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2024 13:15:31 -0400 Subject: [PATCH 485/523] Roll external/googletest/ 9ff2450a5..cee1ba1f2 (1 commit) (#5743) * Roll external/googletest/ 9ff2450a5..57e107a10 (2 commits) https://github.com/google/googletest/compare/9ff2450a56ae...57e107a10ea4 Created with: roll-dep external/googletest * Roll external/abseil_cpp/ 3cb498899..5ea745c2a (3 commits) https://github.com/abseil/abseil-cpp/compare/3cb4988999d2...5ea745c2ae28 Created with: roll-dep external/abseil_cpp --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index f914bc9967..370de6b201 100644 --- a/DEPS +++ b/DEPS @@ -3,11 +3,11 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': '3cb4988999d2f16e11d86f9921e9526486ef1960', + 'abseil_revision': '5ea745c2ae2860898835b4fceafb286d42b495a1', 'effcee_revision': '2c97e5689ed8d7ab6ae5820f884f03a601ae124b', - 'googletest_revision': '9ff2450a56aed4f7f124f5104d9e3088bf791ee9', + 'googletest_revision': '57e107a10ea4ff5d8d31df9e4833f80b414b0dd2', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From 8731673a5daafed012310c8e8ab2d8ded8cbe025 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Wed, 24 Jul 2024 13:36:11 -0400 Subject: [PATCH 486/523] Allow ArrayStride on untyped pointers (#5746) --- source/val/validate_annotation.cpp | 3 ++- test/val/val_annotation_test.cpp | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/source/val/validate_annotation.cpp b/source/val/validate_annotation.cpp index dfafaaa855..cf6f96b8b0 100644 --- a/source/val/validate_annotation.cpp +++ b/source/val/validate_annotation.cpp @@ -123,7 +123,8 @@ spv_result_t ValidateDecorationTarget(ValidationState_t& _, spv::Decoration dec, case spv::Decoration::ArrayStride: if (target->opcode() != spv::Op::OpTypeArray && target->opcode() != spv::Op::OpTypeRuntimeArray && - target->opcode() != spv::Op::OpTypePointer) { + target->opcode() != spv::Op::OpTypePointer && + target->opcode() != spv::Op::OpTypeUntypedPointerKHR) { return fail(0) << "must be an array or pointer type"; } break; diff --git a/test/val/val_annotation_test.cpp b/test/val/val_annotation_test.cpp index e65e11f45e..e4a947499c 100644 --- a/test/val/val_annotation_test.cpp +++ b/test/val/val_annotation_test.cpp @@ -257,6 +257,22 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(DecorationTest, ArrayStrideUntypedPointerKHR) { + const std::string text = R"( +OpCapability Shader +OpCapability Linkage +OpCapability UntypedPointersKHR +OpExtension "SPV_KHR_untyped_pointers" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpMemoryModel Logical GLSL450 +OpDecorate %ptr ArrayStride 4 +%ptr = OpTypeUntypedPointerKHR StorageBuffer +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + using MemberOnlyDecorations = spvtest::ValidateBase; TEST_P(MemberOnlyDecorations, MemberDecoration) { From e7216170d02921ce8acd49aebed0098adc050d23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2024 13:51:47 -0400 Subject: [PATCH 487/523] build(deps): bump braces from 3.0.2 to 3.0.3 in /tools/sva (#5737) Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3. - [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md) - [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3) --- updated-dependencies: - dependency-name: braces dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tools/sva/yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/sva/yarn.lock b/tools/sva/yarn.lock index eed94ced15..50f0fab47c 100644 --- a/tools/sva/yarn.lock +++ b/tools/sva/yarn.lock @@ -219,11 +219,11 @@ brace-expansion@^2.0.1: balanced-match "^1.0.0" braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" browser-stdout@1.3.1: version "1.3.1" @@ -602,10 +602,10 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" From 363486479d4c8dfbfdf2e2dc397cd10aa15f80b0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 13:26:22 +0000 Subject: [PATCH 488/523] roll deps (#5748) * Roll external/googletest/ 57e107a10..5bcb2d78a (2 commits) https://github.com/google/googletest/compare/57e107a10ea4...5bcb2d78a16e Created with: roll-dep external/googletest * Roll external/abseil_cpp/ 5ea745c2a..52fad5aa0 (10 commits) https://github.com/abseil/abseil-cpp/compare/5ea745c2ae28...52fad5aa026b Created with: roll-dep external/abseil_cpp * Roll external/spirv-headers/ db5a00f8c..f013f08e4 (2 commits) https://github.com/KhronosGroup/SPIRV-Headers/compare/db5a00f8cebe...f013f08e4455 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 370de6b201..ff46fea638 100644 --- a/DEPS +++ b/DEPS @@ -3,18 +3,18 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': '5ea745c2ae2860898835b4fceafb286d42b495a1', + 'abseil_revision': '52fad5aa026b6202dd8dabb5723f2ee3f604048f', 'effcee_revision': '2c97e5689ed8d7ab6ae5820f884f03a601ae124b', - 'googletest_revision': '57e107a10ea4ff5d8d31df9e4833f80b414b0dd2', + 'googletest_revision': '5bcb2d78a16edd7110e72ef694d229815aa29542', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', 're2_revision': '6dcd83d60f7944926bfd308cc13979fc53dd69ca', - 'spirv_headers_revision': 'db5a00f8cebe81146cafabf89019674a3c4bf03d', + 'spirv_headers_revision': 'f013f08e4455bcc1f0eed8e3dd5e2009682656d9', } deps = { From 246daf246bb17336afcf4482680bba434b1e5557 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 31 Jul 2024 17:11:45 -0400 Subject: [PATCH 489/523] [OPT] Avoid assert in generatecopy (#5756) We want to be able to recover when fix storage class is not able to fix everything, and just leave the spir-v in an invalid state. The pass should not fail because of that. --- source/opt/copy_prop_arrays.cpp | 2 ++ source/opt/fix_storage_class.cpp | 3 ++ source/opt/pass.cpp | 29 +++++++++++------- source/opt/pass.h | 3 +- test/opt/fix_storage_class_test.cpp | 46 +++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 11 deletions(-) diff --git a/source/opt/copy_prop_arrays.cpp b/source/opt/copy_prop_arrays.cpp index c2bea8ad04..26b5ef77ee 100644 --- a/source/opt/copy_prop_arrays.cpp +++ b/source/opt/copy_prop_arrays.cpp @@ -751,6 +751,8 @@ void CopyPropagateArrays::UpdateUses(Instruction* original_ptr_inst, uint32_t pointee_type_id = pointer_type->GetSingleWordInOperand(kTypePointerPointeeInIdx); uint32_t copy = GenerateCopy(original_ptr_inst, pointee_type_id, use); + assert(copy != 0 && + "Should not be updating uses unless we know it can be done."); context()->ForgetUses(use); use->SetInOperand(index, {copy}); diff --git a/source/opt/fix_storage_class.cpp b/source/opt/fix_storage_class.cpp index 367418d77a..b64026e6a5 100644 --- a/source/opt/fix_storage_class.cpp +++ b/source/opt/fix_storage_class.cpp @@ -237,6 +237,9 @@ bool FixStorageClass::PropagateType(Instruction* inst, uint32_t type_id, } uint32_t copy_id = GenerateCopy(obj_inst, pointee_type_id, inst); + if (copy_id == 0) { + return false; + } inst->SetInOperand(1, {copy_id}); context()->UpdateDefUse(inst); } diff --git a/source/opt/pass.cpp b/source/opt/pass.cpp index 28f26c5868..0f260e2efe 100644 --- a/source/opt/pass.cpp +++ b/source/opt/pass.cpp @@ -96,8 +96,10 @@ uint32_t Pass::GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id, Instruction* original_type = get_def_use_mgr()->GetDef(original_type_id); Instruction* new_type = get_def_use_mgr()->GetDef(new_type_id); - assert(new_type->opcode() == original_type->opcode() && - "Can't copy an aggragate type unless the type correspond."); + + if (new_type->opcode() != original_type->opcode()) { + return 0; + } switch (original_type->opcode()) { case spv::Op::OpTypeArray: { @@ -114,8 +116,12 @@ uint32_t Pass::GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id, for (uint32_t i = 0; i < array_length; i++) { Instruction* extract = ir_builder.AddCompositeExtract( original_element_type_id, object_to_copy->result_id(), {i}); - element_ids.push_back( - GenerateCopy(extract, new_element_type_id, insertion_position)); + uint32_t new_id = + GenerateCopy(extract, new_element_type_id, insertion_position); + if (new_id == 0) { + return 0; + } + element_ids.push_back(new_id); } return ir_builder.AddCompositeConstruct(new_type_id, element_ids) @@ -128,8 +134,12 @@ uint32_t Pass::GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id, uint32_t new_member_type_id = new_type->GetSingleWordInOperand(i); Instruction* extract = ir_builder.AddCompositeExtract( orig_member_type_id, object_to_copy->result_id(), {i}); - element_ids.push_back( - GenerateCopy(extract, new_member_type_id, insertion_position)); + uint32_t new_id = + GenerateCopy(extract, new_member_type_id, insertion_position); + if (new_id == 0) { + return 0; + } + element_ids.push_back(new_id); } return ir_builder.AddCompositeConstruct(new_type_id, element_ids) ->result_id(); @@ -137,11 +147,10 @@ uint32_t Pass::GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id, default: // If we do not have an aggregate type, then we have a problem. Either we // found multiple instances of the same type, or we are copying to an - // incompatible type. Either way the code is illegal. - assert(false && - "Don't know how to copy this type. Code is likely illegal."); + // incompatible type. Either way the code is illegal. Leave the code as + // is and let the caller deal with it. + return 0; } - return 0; } } // namespace opt diff --git a/source/opt/pass.h b/source/opt/pass.h index b2303e2316..3e6c4d0763 100644 --- a/source/opt/pass.h +++ b/source/opt/pass.h @@ -145,7 +145,8 @@ class Pass { // Returns the id whose value is the same as |object_to_copy| except its type // is |new_type_id|. Any instructions needed to generate this value will be - // inserted before |insertion_position|. + // inserted before |insertion_position|. Returns 0 if a copy could not be + // done. uint32_t GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id, Instruction* insertion_position); diff --git a/test/opt/fix_storage_class_test.cpp b/test/opt/fix_storage_class_test.cpp index 410f140ea9..01a75e0d95 100644 --- a/test/opt/fix_storage_class_test.cpp +++ b/test/opt/fix_storage_class_test.cpp @@ -987,6 +987,52 @@ OpFunctionEnd SinglePassRunAndCheck(text, text, false); } +// This example is generated by DXC when certain inline spiir-v is used. +// The intention is that the function scope variable will eventually be +// optimized away, removing the type mismatch. We want to make sure the +// OpCopyObject is rewritten, and that the pass does not fail. +TEST_F(FixStorageClassTest, DoNotFailWithMismatchedPointerTypes) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint GLCompute %1 "main" %38 + OpExecutionMode %1 LocalSize 64 1 1 + OpSource HLSL 600 + %int = OpTypeInt 32 1 + %int_0 = OpConstant %int 0 + %float = OpTypeFloat 32 + %uint = OpTypeInt 32 0 + %uint_64 = OpConstant %uint 64 +%_arr_float_uint_64 = OpTypeArray %float %uint_64 +%_ptr_Workgroup__arr_float_uint_64 = OpTypePointer Workgroup %_arr_float_uint_64 + %void = OpTypeVoid + %80 = OpTypeFunction %void +%_ptr_Workgroup_float = OpTypePointer Workgroup %float +%_ptr_Function__ptr_Workgroup_float = OpTypePointer Function %_ptr_Workgroup_float +%_ptr_Workgroup_float_0 = OpTypePointer Workgroup %float + %38 = OpVariable %_ptr_Workgroup__arr_float_uint_64 Workgroup + %1 = OpFunction %void None %80 + %98 = OpLabel +; CHECK: [[var:%\d+]] = OpVariable %_ptr_Function__ptr_Workgroup_float Function + %113 = OpVariable %_ptr_Function__ptr_Workgroup_float Function +; CHECK: [[ac:%\d+]] = OpAccessChain %_ptr_Workgroup_float_0 {{%\d+}} %int_0 + %136 = OpAccessChain %_ptr_Workgroup_float_0 %38 %int_0 +; Verify that the type for the OpCopyObject has changed to match [[ac]]. +; CHECK: [[copy:%\d+]] = OpCopyObject %_ptr_Workgroup_float_0 [[ac]] + %137 = OpCopyObject %_ptr_Workgroup_float %136 +; This has a type mismatch, but this is because we do not have a way to copy +; a pointer from one type to another, so FixStorageClass cannot do anything +; about it. We want fix storage class to leave it as is, and the validator +; will report an error if the store is not remove by a later optimization. +; CHECK: OpStore [[var]] [[copy]] + OpStore %113 %137 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, false); +} + } // namespace } // namespace opt } // namespace spvtools From bc2478c9223f1b931269e2aef86a9197413d3dc9 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 7 Aug 2024 10:43:18 -0400 Subject: [PATCH 490/523] Use "docker compose" in wasm build (#5764) The wasm github action is using the deprecated `docker-compose` command. This is update to use `docker compose`. --- .github/workflows/wasm.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 8a81140afd..1645315956 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -13,6 +13,6 @@ jobs: with: fetch-depth: '0' - name: Build web - run: docker-compose -f source/wasm/docker-compose.yml --project-directory . up + run: docker compose -f source/wasm/docker-compose.yml --project-directory . up - name: Run tests run: node test/wasm/test.js From 72c291332a0558ab4121eff9db97e428b574b58b Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 7 Aug 2024 12:33:51 -0400 Subject: [PATCH 491/523] Add OpTypeRuntimeArray to composite types (#5765) --- source/opcode.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/opcode.cpp b/source/opcode.cpp index c4ec94e4b1..32fa10d155 100644 --- a/source/opcode.cpp +++ b/source/opcode.cpp @@ -276,6 +276,7 @@ int32_t spvOpcodeIsComposite(const spv::Op opcode) { case spv::Op::OpTypeMatrix: case spv::Op::OpTypeArray: case spv::Op::OpTypeStruct: + case spv::Op::OpTypeRuntimeArray: case spv::Op::OpTypeCooperativeMatrixNV: case spv::Op::OpTypeCooperativeMatrixKHR: return true; From b64a423b44f448df5464978173e28be12069b73c Mon Sep 17 00:00:00 2001 From: Markus Tavenrath Date: Wed, 7 Aug 2024 20:11:11 +0200 Subject: [PATCH 492/523] Workaround issue in MSVC arm64 compiler returning random upper 32-bits in function spvtools::util::CountSetBits. (#5763) Fix issue #5762 --- source/util/bitutils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/util/bitutils.h b/source/util/bitutils.h index a121dc356b..2763bc273b 100644 --- a/source/util/bitutils.h +++ b/source/util/bitutils.h @@ -97,7 +97,7 @@ template size_t CountSetBits(T word) { static_assert(std::is_integral::value, "CountSetBits requires integer type"); - size_t count = 0; + uint32_t count = 0; while (word) { word &= word - 1; ++count; From 87fcbaf1bc8346469e178711eff27cfd20aa1960 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 9 Aug 2024 14:31:05 -0400 Subject: [PATCH 493/523] build(deps): bump the github-actions group across 1 directory with 4 updates (#5761) Bumps the github-actions group with 4 updates in the / directory: [lukka/get-cmake](https://github.com/lukka/get-cmake), [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 `lukka/get-cmake` from 3.30.1 to 3.30.2 - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/34181361be075620f7c3871daa1cadb92d9a903e...a70f1cfa1857a3eecfe0d34962269e1b1e8be56c) Updates `ossf/scorecard-action` from 2.3.3 to 2.4.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/dc50aa9510b46c811795eb24b2f1ba02a914e534...62b2cac7ed8198b15735ed49ab1e5cf35480ba46) Updates `actions/upload-artifact` from 4.3.4 to 4.3.6 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/0b2256b8c012f0828dc542b3febcab082c67f72b...834a144ee995460fba8ed112a2fc961b36a5ec5a) Updates `github/codeql-action` from 3.25.13 to 3.26.0 - [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/2d790406f505036ef40ecba973cc774a50395aac...eb055d739abdc2e8de2e5f4ba1a8b246daa779aa) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-type: direct:production update-type: version-update:semver-patch 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/ios.yml | 2 +- .github/workflows/scorecard.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index c859f8e21a..0f8f693363 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@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: lukka/get-cmake@34181361be075620f7c3871daa1cadb92d9a903e # v3.30.1 + - uses: lukka/get-cmake@a70f1cfa1857a3eecfe0d34962269e1b1e8be56c # v3.30.2 - name: Download dependencies run: python3 utils/git-sync-deps # NOTE: The MacOS SDK ships universal binaries. CI should reflect this. diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 344b0ba70d..3cbeb9bc9f 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@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3 + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.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@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 + uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 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@2d790406f505036ef40ecba973cc774a50395aac # v3.25.13 + uses: github/codeql-action/upload-sarif@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # v3.26.0 with: sarif_file: results.sarif From 988995c3b7afdfe60a43cb06c03fc1c8a5c12813 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 10:57:06 -0400 Subject: [PATCH 494/523] build(deps): bump github/codeql-action (#5769) Bumps the github-actions group with 1 update in the / directory: [github/codeql-action](https://github.com/github/codeql-action). Updates `github/codeql-action` from 3.26.0 to 3.26.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/eb055d739abdc2e8de2e5f4ba1a8b246daa779aa...883d8588e56d1753a8a58c1c86e88976f0c23449) --- 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 3cbeb9bc9f..7a636cd97b 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@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa # v3.26.0 + uses: github/codeql-action/upload-sarif@883d8588e56d1753a8a58c1c86e88976f0c23449 # v3.26.3 with: sarif_file: results.sarif From e8c2fbca1ec2f0f07a8921fc3531e7a2482c0385 Mon Sep 17 00:00:00 2001 From: Kaylee Lubick Date: Wed, 21 Aug 2024 11:04:38 -0400 Subject: [PATCH 495/523] Remove local attribute from build_version_inc genrule (#5766) --- BUILD.bazel | 1 - 1 file changed, 1 deletion(-) diff --git a/BUILD.bazel b/BUILD.bazel index 4becf281ec..ee16c0a3b7 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -110,7 +110,6 @@ genrule( outs = ["build-version.inc"], cmd = "SOURCE_DATE_EPOCH=0 $(location :update_build_version) $(location CHANGES) $(location build-version.inc)", cmd_bat = "set SOURCE_DATE_EPOCH=0 && $(location :update_build_version) $(location CHANGES) $(location build-version.inc)", - local = True, tools = [":update_build_version"], ) From 0c40b591a305942abdcc090ef3fbf39d3326572d Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Wed, 21 Aug 2024 11:05:43 -0400 Subject: [PATCH 496/523] [OPT] Add SPV_KHR_ray_tracing_position_fetch to allow lists (#5757) Fixes https://github.com/microsoft/DirectXShaderCompiler/issues/6844 --- source/opt/aggressive_dead_code_elim_pass.cpp | 3 ++- 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, 8 insertions(+), 4 deletions(-) diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp index 4f5b7230a4..7eb158d5e6 100644 --- a/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/source/opt/aggressive_dead_code_elim_pass.cpp @@ -1011,7 +1011,8 @@ void AggressiveDCEPass::InitExtensions() { "SPV_EXT_fragment_shader_interlock", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", - "SPV_KHR_cooperative_matrix" + "SPV_KHR_cooperative_matrix", + "SPV_KHR_ray_tracing_position_fetch" }); // clang-format on } diff --git a/source/opt/local_access_chain_convert_pass.cpp b/source/opt/local_access_chain_convert_pass.cpp index 174e7d86da..f46c9136fe 100644 --- a/source/opt/local_access_chain_convert_pass.cpp +++ b/source/opt/local_access_chain_convert_pass.cpp @@ -429,7 +429,8 @@ void LocalAccessChainConvertPass::InitExtensions() { "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_NV_compute_shader_derivatives", - "SPV_NV_cooperative_matrix", "SPV_KHR_cooperative_matrix"}); + "SPV_NV_cooperative_matrix", "SPV_KHR_cooperative_matrix", + "SPV_KHR_ray_tracing_position_fetch"}); } bool LocalAccessChainConvertPass::AnyIndexIsOutOfBounds( diff --git a/source/opt/local_single_block_elim_pass.cpp b/source/opt/local_single_block_elim_pass.cpp index 3a7d25a4ba..e0e4f06b9d 100644 --- a/source/opt/local_single_block_elim_pass.cpp +++ b/source/opt/local_single_block_elim_pass.cpp @@ -293,7 +293,8 @@ void LocalSingleBlockLoadStoreElimPass::InitExtensions() { "SPV_EXT_fragment_shader_interlock", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", - "SPV_KHR_cooperative_matrix"}); + "SPV_KHR_cooperative_matrix", + "SPV_KHR_ray_tracing_position_fetch"}); } } // namespace opt diff --git a/source/opt/local_single_store_elim_pass.cpp b/source/opt/local_single_store_elim_pass.cpp index 7dfc4adfc8..8bdd0f4ea7 100644 --- a/source/opt/local_single_store_elim_pass.cpp +++ b/source/opt/local_single_store_elim_pass.cpp @@ -143,7 +143,8 @@ void LocalSingleStoreElimPass::InitExtensionAllowList() { "SPV_EXT_fragment_shader_interlock", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", - "SPV_KHR_cooperative_matrix"}); + "SPV_KHR_cooperative_matrix", + "SPV_KHR_ray_tracing_position_fetch"}); } bool LocalSingleStoreElimPass::ProcessVariable(Instruction* var_inst) { std::vector users; From 25b4e42ead9fbea6b74e31aa488dee2e54c23ae8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 16:06:38 +0000 Subject: [PATCH 497/523] roll deps (#5754) * Roll external/googletest/ 5bcb2d78a..ff233bdd4 (3 commits) https://github.com/google/googletest/compare/5bcb2d78a16e...ff233bdd4cac Created with: roll-dep external/googletest * Roll external/abseil_cpp/ 52fad5aa0..bd0c9c58c (11 commits) https://github.com/abseil/abseil-cpp/compare/52fad5aa026b...bd0c9c58cac4 Created with: roll-dep external/abseil_cpp --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 6 +++--- MODULE.bazel | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/DEPS b/DEPS index ff46fea638..929fdc48f0 100644 --- a/DEPS +++ b/DEPS @@ -3,18 +3,18 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': '52fad5aa026b6202dd8dabb5723f2ee3f604048f', + 'abseil_revision': '5a01d0f77e37493570e35aedaa95c4bcf1673c7c', 'effcee_revision': '2c97e5689ed8d7ab6ae5820f884f03a601ae124b', - 'googletest_revision': '5bcb2d78a16edd7110e72ef694d229815aa29542', + 'googletest_revision': 'ff233bdd4cac0a0bf6e5cd45bda3406814cb2796', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', 're2_revision': '6dcd83d60f7944926bfd308cc13979fc53dd69ca', - 'spirv_headers_revision': 'f013f08e4455bcc1f0eed8e3dd5e2009682656d9', + 'spirv_headers_revision': '1b75a4ae0b4289014b4c369301dc925c366f78a6', } deps = { diff --git a/MODULE.bazel b/MODULE.bazel index e11286f345..2e28e9eff0 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -17,3 +17,17 @@ local_path_override( module_name = "effcee", path = "external/effcee", ) + +bazel_dep(name = "rules_python", + version = "0.34.0") + +# https://rules-python.readthedocs.io/en/stable/toolchains.html#library-modules-with-dev-only-python-usage +python = use_extension( + "@rules_python//python/extensions:python.bzl", + "python", + dev_dependency = True +) + +python.toolchain(python_version = "3.12", + is_default = True, + ignore_root_user_error = True) From a85a703e3b025e30094e851b44fe61dff1216ff7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:50:19 +0000 Subject: [PATCH 498/523] roll deps (#5771) * Roll external/abseil_cpp/ 5a01d0f77..fd7713cb9 (1 commit) https://github.com/abseil/abseil-cpp/compare/5a01d0f77e37...fd7713cb9a97 Created with: roll-dep external/abseil_cpp * Roll external/spirv-headers/ 1b75a4ae0..69ab0f32d (1 commit) https://github.com/KhronosGroup/SPIRV-Headers/compare/1b75a4ae0b42...69ab0f32dc63 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 929fdc48f0..af22aaef51 100644 --- a/DEPS +++ b/DEPS @@ -3,7 +3,7 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': '5a01d0f77e37493570e35aedaa95c4bcf1673c7c', + 'abseil_revision': 'fd7713cb9a97c49096211ff40de280b6cebbb21c', 'effcee_revision': '2c97e5689ed8d7ab6ae5820f884f03a601ae124b', @@ -14,7 +14,7 @@ vars = { 're2_revision': '6dcd83d60f7944926bfd308cc13979fc53dd69ca', - 'spirv_headers_revision': '1b75a4ae0b4289014b4c369301dc925c366f78a6', + 'spirv_headers_revision': '69ab0f32dc6376d74b3f5b0b7161c6681478badd', } deps = { From edc68950bf725edc89b3e1974c533454cf2ae37c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 07:23:27 -0400 Subject: [PATCH 499/523] build(deps): bump github/codeql-action in the github-actions group (#5772) Bumps the github-actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action). Updates `github/codeql-action` from 3.26.3 to 3.26.4 - [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/883d8588e56d1753a8a58c1c86e88976f0c23449...f0f3afee809481da311ca3a6ff1ff51d81dbeb24) --- 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 7a636cd97b..edcaa4b4a7 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@883d8588e56d1753a8a58c1c86e88976f0c23449 # v3.26.3 + uses: github/codeql-action/upload-sarif@f0f3afee809481da311ca3a6ff1ff51d81dbeb24 # v3.26.4 with: sarif_file: results.sarif From b21dda0ee7a3ea4e0192a7b2b09db1df1de9d5e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Petit?= Date: Thu, 29 Aug 2024 13:15:31 +0100 Subject: [PATCH 500/523] Validate presence of Stride operand to OpCooperativeMatrix{Load,Store}KHR (#5777) * Validate Stride operand to OpCooperativeMatrix{Load,Store}KHR The specification requires the Stride operand for the RowMajorKHR and ColumnMajorKHR layouts. Signed-off-by: Kevin Petit Change-Id: I51084b9b8dedebf9cab7ae25334ee56b75ef0126 * Update source/val/validate_memory.cpp Co-authored-by: alan-baker * add test to exercise memory layout from spec constant and fix validation Change-Id: I06d7308c4a2b62d26d69e88e03bfa009a7f8fff3 * format fixes Change-Id: I9cbabec0ed2172dcd228cc385551cb7a5b79df1a --------- Signed-off-by: Kevin Petit Co-authored-by: alan-baker --- source/val/validate_memory.cpp | 22 ++-- test/opt/aggressive_dead_code_elim_test.cpp | 5 +- test/val/val_memory_test.cpp | 114 ++++++++++++++++---- 3 files changed, 114 insertions(+), 27 deletions(-) diff --git a/source/val/validate_memory.cpp b/source/val/validate_memory.cpp index beaa79c28e..9bfa3c2158 100644 --- a/source/val/validate_memory.cpp +++ b/source/val/validate_memory.cpp @@ -2115,16 +2115,23 @@ spv_result_t ValidateCooperativeMatrixLoadStoreKHR(ValidationState_t& _, const auto layout_index = (inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) ? 3u : 2u; - const auto colmajor_id = inst->GetOperandAs(layout_index); - const auto colmajor = _.FindDef(colmajor_id); - if (!colmajor || !_.IsIntScalarType(colmajor->type_id()) || - !(spvOpcodeIsConstant(colmajor->opcode()) || - spvOpcodeIsSpecConstant(colmajor->opcode()))) { + const auto layout_id = inst->GetOperandAs(layout_index); + const auto layout_inst = _.FindDef(layout_id); + if (!layout_inst || !_.IsIntScalarType(layout_inst->type_id()) || + !spvOpcodeIsConstant(layout_inst->opcode())) { return _.diag(SPV_ERROR_INVALID_ID, inst) - << "MemoryLayout operand " << _.getIdName(colmajor_id) + << "MemoryLayout operand " << _.getIdName(layout_id) << " must be a 32-bit integer constant instruction."; } + bool stride_required = false; + uint64_t layout; + if (_.EvalConstantValUint64(layout_id, &layout)) { + stride_required = + (layout == (uint64_t)spv::CooperativeMatrixLayout::RowMajorKHR) || + (layout == (uint64_t)spv::CooperativeMatrixLayout::ColumnMajorKHR); + } + const auto stride_index = (inst->opcode() == spv::Op::OpCooperativeMatrixLoadKHR) ? 4u : 3u; if (inst->operands().size() > stride_index) { @@ -2135,6 +2142,9 @@ spv_result_t ValidateCooperativeMatrixLoadStoreKHR(ValidationState_t& _, << "Stride operand " << _.getIdName(stride_id) << " must be a scalar integer type."; } + } else if (stride_required) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "MemoryLayout " << layout << " requires a Stride."; } const auto memory_access_index = diff --git a/test/opt/aggressive_dead_code_elim_test.cpp b/test/opt/aggressive_dead_code_elim_test.cpp index dcce4f5789..d837099fe9 100644 --- a/test/opt/aggressive_dead_code_elim_test.cpp +++ b/test/opt/aggressive_dead_code_elim_test.cpp @@ -8018,6 +8018,7 @@ TEST_F(AggressiveDCETest, StoringAPointer) { %uint_3 = OpConstant %uint 3 %uint_16 = OpConstant %uint 16 %uint_4 = OpConstant %uint 4 +%coop_stride = OpConstant %int 42 %_runtimearr_int = OpTypeRuntimeArray %int %_struct_4 = OpTypeStruct %_runtimearr_int %_ptr_StorageBuffer__struct_4 = OpTypePointer StorageBuffer %_struct_4 @@ -8047,7 +8048,7 @@ TEST_F(AggressiveDCETest, StoringAPointer) { %26 = OpVariable %_ptr_Function__ptr_Function_int Function %27 = OpVariable %_ptr_Function__struct_18 Function %28 = OpAccessChain %_ptr_StorageBuffer_int %2 %int_0 %uint_0 - %29 = OpCooperativeMatrixLoadKHR %17 %28 %int_1 + %29 = OpCooperativeMatrixLoadKHR %17 %28 %int_1 %coop_stride %30 = OpCompositeConstruct %_struct_18 %29 OpStore %27 %30 %31 = OpAccessChain %_ptr_Function_17 %27 %int_0 @@ -8059,7 +8060,7 @@ TEST_F(AggressiveDCETest, StoringAPointer) { OpStore %32 %34 %35 = OpAccessChain %_ptr_StorageBuffer_int %2 %int_0 %uint_64 %36 = OpLoad %17 %31 - OpCooperativeMatrixStoreKHR %35 %36 %int_0 + OpCooperativeMatrixStoreKHR %35 %36 %int_0 %coop_stride OpReturn OpFunctionEnd )"; diff --git a/test/val/val_memory_test.cpp b/test/val/val_memory_test.cpp index b4689f2e9d..df92fff4c0 100644 --- a/test/val/val_memory_test.cpp +++ b/test/val/val_memory_test.cpp @@ -2351,7 +2351,11 @@ OpFunctionEnd)"; } std::string GenCoopMatLoadStoreShaderKHR(const std::string& storeMemoryAccess, - const std::string& loadMemoryAccess) { + const std::string& loadMemoryAccess, + unsigned layout = 0, + bool useSpecConstantLayout = false, + bool useStoreStride = true, + bool useLoadStride = true) { std::string s = R"( OpCapability Shader OpCapability GroupNonUniform @@ -2408,11 +2412,18 @@ OpDecorate %129 BuiltIn WorkgroupSize %33 = OpConstant %6 1024 %34 = OpConstant %6 1 %38 = OpConstant %6 8 -%39 = OpConstant %6 0 +%uint_0 = OpConstant %6 0 +)"; + if (useSpecConstantLayout) { + s += "%layout = OpSpecConstant %6 " + std::to_string(layout); + } else { + s += "%layout = OpConstant %6 " + std::to_string(layout); + } + s += R"( %68 = OpTypeFloat 32 %69 = OpConstant %6 16 %70 = OpConstant %6 3 -%71 = OpTypeCooperativeMatrixKHR %68 %70 %69 %38 %39 +%71 = OpTypeCooperativeMatrixKHR %68 %70 %69 %38 %uint_0 %72 = OpTypePointer Function %71 %74 = OpTypeRuntimeArray %68 %75 = OpTypeStruct %74 @@ -2422,7 +2433,7 @@ OpDecorate %129 BuiltIn WorkgroupSize %79 = OpConstant %78 0 %81 = OpConstant %6 5 %82 = OpTypePointer StorageBuffer %68 -%84 = OpConstant %6 64 +%stride = OpConstant %6 64 %88 = OpTypePointer Private %71 %89 = OpVariable %88 Private %92 = OpTypeRuntimeArray %68 @@ -2478,7 +2489,7 @@ OpStore %18 %30 %35 = OpAccessChain %31 %18 %34 %36 = OpLoad %6 %35 %37 = OpIMul %6 %33 %36 -%40 = OpAccessChain %31 %18 %39 +%40 = OpAccessChain %31 %18 %uint_0 %41 = OpLoad %6 %40 %42 = OpIMul %6 %38 %41 %43 = OpIAdd %6 %37 %42 @@ -2486,7 +2497,7 @@ OpStore %32 %43 %45 = OpAccessChain %31 %18 %34 %46 = OpLoad %6 %45 %47 = OpIMul %6 %33 %46 -%48 = OpAccessChain %31 %18 %39 +%48 = OpAccessChain %31 %18 %uint_0 %49 = OpLoad %6 %48 %50 = OpIMul %6 %38 %49 %51 = OpIAdd %6 %47 %50 @@ -2494,7 +2505,7 @@ OpStore %44 %51 %53 = OpAccessChain %31 %18 %34 %54 = OpLoad %6 %53 %55 = OpIMul %6 %33 %54 -%56 = OpAccessChain %31 %18 %39 +%56 = OpAccessChain %31 %18 %uint_0 %57 = OpLoad %6 %56 %58 = OpIMul %6 %38 %57 %59 = OpIAdd %6 %55 %58 @@ -2502,27 +2513,33 @@ OpStore %52 %59 %61 = OpAccessChain %31 %18 %34 %62 = OpLoad %6 %61 %63 = OpIMul %6 %33 %62 -%64 = OpAccessChain %31 %18 %39 +%64 = OpAccessChain %31 %18 %uint_0 %65 = OpLoad %6 %64 %66 = OpIMul %6 %38 %65 %67 = OpIAdd %6 %63 %66 OpStore %60 %67 %80 = OpLoad %6 %32 %83 = OpAccessChain %82 %77 %79 %80 -%87 = OpCooperativeMatrixLoadKHR %71 %83 %39 %84 )" + - loadMemoryAccess + R"( %81 +)"; + if (useLoadStride) { + s += "%87 = OpCooperativeMatrixLoadKHR %71 %83 %layout %stride " + + loadMemoryAccess + " %81"; + } else { + s += "%87 = OpCooperativeMatrixLoadKHR %71 %83 %layout"; + } + s += R"( OpStore %73 %87 %90 = OpLoad %71 %73 OpStore %89 %90 %96 = OpLoad %6 %44 %97 = OpAccessChain %82 %95 %79 %96 -%98 = OpCooperativeMatrixLoadKHR %71 %97 %39 %84 MakePointerVisibleKHR|NonPrivatePointerKHR %81 +%98 = OpCooperativeMatrixLoadKHR %71 %97 %layout %stride MakePointerVisibleKHR|NonPrivatePointerKHR %81 OpStore %91 %98 %100 = OpLoad %71 %91 OpStore %99 %100 %106 = OpLoad %6 %52 %107 = OpAccessChain %82 %105 %79 %106 -%108 = OpCooperativeMatrixLoadKHR %71 %107 %39 %84 MakePointerVisibleKHR|NonPrivatePointerKHR %81 +%108 = OpCooperativeMatrixLoadKHR %71 %107 %layout %stride MakePointerVisibleKHR|NonPrivatePointerKHR %81 OpStore %101 %108 %110 = OpLoad %71 %101 OpStore %109 %110 @@ -2532,7 +2549,14 @@ OpStore %111 %115 %116 = OpLoad %71 %111 %121 = OpLoad %6 %60 %122 = OpAccessChain %82 %120 %79 %121 -OpCooperativeMatrixStoreKHR %122 %116 %39 %84 )" + storeMemoryAccess + R"( %81 +)"; + if (useStoreStride) { + s += "OpCooperativeMatrixStoreKHR %122 %116 %layout %stride " + + storeMemoryAccess + " %81"; + } else { + s += "OpCooperativeMatrixStoreKHR %122 %116 %layout"; + } + s += R"( OpReturn OpFunctionEnd )"; @@ -2549,6 +2573,54 @@ TEST_F(ValidateMemory, CoopMatKHRLoadStoreSuccess) { EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); } +struct StrideMissingCase { + unsigned layout; + bool useLoadStride; + bool useStoreStride; +}; + +using ValidateCoopMatrixStrideMissing = + spvtest::ValidateBase; + +INSTANTIATE_TEST_SUITE_P( + CoopMatrixStrideMissing, ValidateCoopMatrixStrideMissing, + Values( + StrideMissingCase{(unsigned)spv::CooperativeMatrixLayout::RowMajorKHR, + false, true}, + StrideMissingCase{(unsigned)spv::CooperativeMatrixLayout::RowMajorKHR, + true, false}, + StrideMissingCase{ + (unsigned)spv::CooperativeMatrixLayout::ColumnMajorKHR, false, + true}, + StrideMissingCase{ + (unsigned)spv::CooperativeMatrixLayout::ColumnMajorKHR, true, + false})); + +TEST_P(ValidateCoopMatrixStrideMissing, CoopMatKHRLoadStrideMissingFail) { + const StrideMissingCase& param = GetParam(); + std::string spirv = GenCoopMatLoadStoreShaderKHR( + "MakePointerAvailableKHR|NonPrivatePointerKHR", + "MakePointerVisibleKHR|NonPrivatePointerKHR", param.layout, + false /*useSpecConstantLayout*/, param.useStoreStride, + param.useLoadStride); + CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("MemoryLayout " + std::to_string(param.layout) + + " requires a Stride")); +} + +TEST_F(ValidateMemory, CoopMatKHRMemoryLayoutFromSpecConstantSuccess) { + std::string spirv = GenCoopMatLoadStoreShaderKHR( + "MakePointerAvailableKHR|NonPrivatePointerKHR", + "MakePointerVisibleKHR|NonPrivatePointerKHR", + (unsigned)spv::CooperativeMatrixLayout::RowMajorKHR, + true /*useSpecConstantLayout*/); + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + TEST_F(ValidateMemory, CoopMatKHRStoreMemoryAccessFail) { std::string spirv = GenCoopMatLoadStoreShaderKHR( "MakePointerVisibleKHR|NonPrivatePointerKHR", @@ -6791,11 +6863,12 @@ OpDecorate %array ArrayStride 4 %rows = OpSpecConstant %int 1 %cols = OpSpecConstant %int 1 %matrix_a = OpConstant %int 1 +%stride = OpConstant %int 42 %matrix = OpTypeCooperativeMatrixKHR %float %subgroup %rows %cols %matrix_a %var = OpUntypedVariableKHR %untyped StorageBuffer %block %main = OpFunction %void None %void_fn %entry = OpLabel -%ld = OpCooperativeMatrixLoadKHR %matrix %var %int_0 +%ld = OpCooperativeMatrixLoadKHR %matrix %var %int_0 %stride OpReturn OpFunctionEnd )"; @@ -6832,12 +6905,13 @@ OpDecorate %array ArrayStride 4 %rows = OpSpecConstant %int 1 %cols = OpSpecConstant %int 1 %matrix_a = OpConstant %int 1 +%stride = OpConstant %int 42 %matrix = OpTypeCooperativeMatrixKHR %float %subgroup %rows %cols %matrix_a %var = OpUntypedVariableKHR %untyped StorageBuffer %block %main = OpFunction %void None %void_fn %entry = OpLabel %gep = OpUntypedAccessChainKHR %untyped %block %var %int_0 %int_0 -%ld = OpCooperativeMatrixLoadKHR %matrix %gep %int_0 +%ld = OpCooperativeMatrixLoadKHR %matrix %gep %int_0 %stride OpReturn OpFunctionEnd )"; @@ -6878,14 +6952,15 @@ OpDecorate %array ArrayStride 4 %rows = OpSpecConstant %int 1 %cols = OpSpecConstant %int 1 %matrix_a = OpConstant %int 1 +%stride = OpConstant %int 42 %matrix = OpTypeCooperativeMatrixKHR %float %subgroup %rows %cols %matrix_a %var1 = OpVariable %ptr StorageBuffer %var2 = OpUntypedVariableKHR %untyped StorageBuffer %block %main = OpFunction %void None %void_fn %entry = OpLabel %gep = OpAccessChain %ptr_float %var1 %int_0 %int_0 -%ld = OpCooperativeMatrixLoadKHR %matrix %gep %int_0 -OpCooperativeMatrixStoreKHR %var2 %ld %int_0 +%ld = OpCooperativeMatrixLoadKHR %matrix %gep %int_0 %stride +OpCooperativeMatrixStoreKHR %var2 %ld %int_0 %stride OpReturn OpFunctionEnd )"; @@ -6926,15 +7001,16 @@ OpDecorate %array ArrayStride 4 %rows = OpSpecConstant %int 1 %cols = OpSpecConstant %int 1 %matrix_a = OpConstant %int 1 +%stride = OpConstant %int 42 %matrix = OpTypeCooperativeMatrixKHR %float %subgroup %rows %cols %matrix_a %var1 = OpVariable %ptr StorageBuffer %var2 = OpUntypedVariableKHR %untyped StorageBuffer %block %main = OpFunction %void None %void_fn %entry = OpLabel %gep = OpAccessChain %ptr_float %var1 %int_0 %int_0 -%ld = OpCooperativeMatrixLoadKHR %matrix %gep %int_0 +%ld = OpCooperativeMatrixLoadKHR %matrix %gep %int_0 %stride %gep2 = OpUntypedAccessChainKHR %untyped %block %var2 %int_0 %int_0 -OpCooperativeMatrixStoreKHR %gep2 %ld %int_0 +OpCooperativeMatrixStoreKHR %gep2 %ld %int_0 %stride OpReturn OpFunctionEnd )"; From 88c25a71d9fbb9cc15453728956021187280e4f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:40:03 -0400 Subject: [PATCH 501/523] build(deps): bump the github-actions group across 1 directory with 3 updates (#5780) Bumps the github-actions group with 3 updates in the / directory: [lukka/get-cmake](https://github.com/lukka/get-cmake), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [github/codeql-action](https://github.com/github/codeql-action). Updates `lukka/get-cmake` from 3.30.2 to 3.30.3 - [Release notes](https://github.com/lukka/get-cmake/releases) - [Commits](https://github.com/lukka/get-cmake/compare/a70f1cfa1857a3eecfe0d34962269e1b1e8be56c...070a0507a7abe157ef918deec391da1be197d2d1) Updates `actions/upload-artifact` from 4.3.6 to 4.4.0 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/834a144ee995460fba8ed112a2fc961b36a5ec5a...50769540e7f4bd5e21e526ee35c689e35e0d6874) Updates `github/codeql-action` from 3.26.4 to 3.26.6 - [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/f0f3afee809481da311ca3a6ff1ff51d81dbeb24...4dd16135b69a43b6c8efb853346f8437d92d3c93) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-minor 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/ios.yml | 2 +- .github/workflows/scorecard.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 0f8f693363..9832a31ca2 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@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - uses: lukka/get-cmake@a70f1cfa1857a3eecfe0d34962269e1b1e8be56c # v3.30.2 + - uses: lukka/get-cmake@070a0507a7abe157ef918deec391da1be197d2d1 # v3.30.3 - name: Download dependencies run: python3 utils/git-sync-deps # NOTE: The MacOS SDK ships universal binaries. CI should reflect this. diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index edcaa4b4a7..5861285cf1 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -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@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 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@f0f3afee809481da311ca3a6ff1ff51d81dbeb24 # v3.26.4 + uses: github/codeql-action/upload-sarif@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3.26.6 with: sarif_file: results.sarif From e1782d6675b88225225e331a6318554d473c54db Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 16:56:01 +0000 Subject: [PATCH 502/523] Roll external/abseil_cpp/ fd7713cb9..fd58e18f2 (2 commits) (#5773) * Roll external/googletest/ ff233bdd4..0953a17a4 (1 commit) https://github.com/google/googletest/compare/ff233bdd4cac...0953a17a4281 Created with: roll-dep external/googletest * Roll external/abseil_cpp/ fd7713cb9..e64dd622d (10 commits) https://github.com/abseil/abseil-cpp/compare/fd7713cb9a97...e64dd622d764 Created with: roll-dep external/abseil_cpp * Roll external/spirv-headers/ 69ab0f32d..efb6b4099 (2 commits) https://github.com/KhronosGroup/SPIRV-Headers/compare/69ab0f32dc63...efb6b4099ddb 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 af22aaef51..a7a66c9ed8 100644 --- a/DEPS +++ b/DEPS @@ -3,18 +3,18 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': 'fd7713cb9a97c49096211ff40de280b6cebbb21c', + 'abseil_revision': 'e64dd622d7643b838b4f9c594f3d22a5d33bf58c', 'effcee_revision': '2c97e5689ed8d7ab6ae5820f884f03a601ae124b', - 'googletest_revision': 'ff233bdd4cac0a0bf6e5cd45bda3406814cb2796', + 'googletest_revision': '0953a17a4281fc26831da647ad3fcd5e21e6473b', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', 're2_revision': '6dcd83d60f7944926bfd308cc13979fc53dd69ca', - 'spirv_headers_revision': '69ab0f32dc6376d74b3f5b0b7161c6681478badd', + 'spirv_headers_revision': 'efb6b4099ddb8fa60f62956dee592c4b94ec6a49', } deps = { From 61d6952e2e5db9a71c48091f2eaac6f3519f53a4 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Wed, 4 Sep 2024 14:59:51 -0400 Subject: [PATCH 503/523] Revert "OpSampledImage extra validation (#5695)" (#5785) This reverts commit 70ad4dae7dc2c2d035c288b4e9ada0d7bcc26e9b. Contributes to #5781 SPIR WG 2024-09-04: decision to relax validation requirement in the spec. --- source/val/validate_image.cpp | 8 +------ test/val/val_image_test.cpp | 42 ++--------------------------------- 2 files changed, 3 insertions(+), 47 deletions(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index aadc264e02..faf661afb7 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -1005,8 +1005,7 @@ bool IsAllowedSampledImageOperand(spv::Op opcode, ValidationState_t& _) { spv_result_t ValidateSampledImage(ValidationState_t& _, const Instruction* inst) { - auto type_inst = _.FindDef(inst->type_id()); - if (type_inst->opcode() != spv::Op::OpTypeSampledImage) { + if (_.GetIdOpcode(inst->type_id()) != spv::Op::OpTypeSampledImage) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Result Type to be OpTypeSampledImage."; } @@ -1017,11 +1016,6 @@ spv_result_t ValidateSampledImage(ValidationState_t& _, << "Expected Image to be of type OpTypeImage."; } - if (type_inst->GetOperandAs(1) != image_type) { - return _.diag(SPV_ERROR_INVALID_DATA, inst) - << "Expected Image to have the same type as Result Type Image"; - } - ImageTypeInfo info; if (!GetImageTypeInfo(_, image_type, &info)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index e39ee36f37..77b042f04c 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -4451,7 +4451,7 @@ TEST_F(ValidateImage, QuerySizeNotImage) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler %res1 = OpImageQuerySize %u32vec2 %sampler )"; @@ -4465,7 +4465,7 @@ TEST_F(ValidateImage, QuerySizeSampledImageDirectly) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler %res1 = OpImageQuerySize %u32vec2 %simg )"; @@ -10647,44 +10647,6 @@ TEST_F(ValidateImage, ImageMSArray_ArrayedTypeDoesNotRequireCapability) { EXPECT_THAT(getDiagnosticString(), Eq("")); } -TEST_F(ValidateImage, SampledImageTypeMismatch) { - const std::string code = R"( -OpCapability Shader -OpMemoryModel Logical GLSL450 -OpEntryPoint GLCompute %main "main" -OpExecutionMode %main LocalSize 1 1 1 -OpDecorate %im_var DescriptorSet 0 -OpDecorate %im_var Binding 0 -OpDecorate %s_var DescriptorSet 1 -OpDecorate %s_var Binding 0 -%void = OpTypeVoid -%float = OpTypeFloat 32 -%im1_ty = OpTypeImage %float 2D 0 0 0 1 Unknown -%im2_ty = OpTypeImage %float 2D 1 0 0 1 Unknown -%s_ty = OpTypeSampler -%s_im_ty = OpTypeSampledImage %im2_ty -%ptr_im = OpTypePointer UniformConstant %im1_ty -%ptr_s = OpTypePointer UniformConstant %s_ty -%im_var = OpVariable %ptr_im UniformConstant -%s_var = OpVariable %ptr_s UniformConstant -%void_fn = OpTypeFunction %void -%main = OpFunction %void None %void_fn -%entry = OpLabel -%im_ld = OpLoad %im1_ty %im_var -%s_ld = OpLoad %s_ty %s_var -%sampled_image = OpSampledImage %s_im_ty %im_ld %s_ld -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("Expected Image to have the same type as Result Type Image")); -} - } // namespace } // namespace val } // namespace spvtools From bc4060ed274ad9749c20daced96d6f0518d6418e Mon Sep 17 00:00:00 2001 From: Yoann Congal Date: Thu, 5 Sep 2024 15:06:17 +0200 Subject: [PATCH 504/523] update_build_version.py: support an envvar to force the description (#5758) FORCED_BUILD_VERSION_DESCRIPTION envvar can be used to force a version description instead of resorting to git describe which can change for a given commit if multiple lightweight commits point ot it. Signed-off-by: Yoann Congal --- utils/update_build_version.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/utils/update_build_version.py b/utils/update_build_version.py index bb66e18a5a..9115cab1e9 100755 --- a/utils/update_build_version.py +++ b/utils/update_build_version.py @@ -24,9 +24,10 @@ # - The software version deduced from the given CHANGES file. # - A longer string with the project name, the software version number, and # git commit information for the CHANGES file's directory. The commit -# information is the output of "git describe" if that succeeds, or "git -# rev-parse HEAD" if that succeeds, or otherwise a message containing the -# phrase "unknown hash". +# information is the content of the FORCED_BUILD_VERSION_DESCRIPTION +# environement variable is it exists, else the output of "git describe" if +# that succeeds, or "git rev-parse HEAD" if that succeeds, or otherwise a +# message containing the phrase "unknown hash". # The string contents are escaped as necessary. import datetime @@ -150,7 +151,7 @@ def main(): sys.exit(1) repo_path = os.path.dirname(changes_file_path) - description = describe(repo_path) + description = os.getenv("FORCED_BUILD_VERSION_DESCRIPTION", describe(repo_path)) content = OUTPUT_FORMAT.format(version_tag=version, description=description) # Escape file content. From 2a67ced4331d22f2fc1b17f2d54b2330c5ad8765 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 17:46:13 +0000 Subject: [PATCH 505/523] Roll external/abseil_cpp/ e64dd622d..f7f316824 (2 commits) (#5782) https://github.com/abseil/abseil-cpp/compare/e64dd622d764...f7f316824dfe Created with: roll-dep external/abseil_cpp Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index a7a66c9ed8..4534976f54 100644 --- a/DEPS +++ b/DEPS @@ -3,7 +3,7 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': 'e64dd622d7643b838b4f9c594f3d22a5d33bf58c', + 'abseil_revision': 'f7f316824dfe2c0c0d5e9679970004fd6ac93055', 'effcee_revision': '2c97e5689ed8d7ab6ae5820f884f03a601ae124b', From b31baff4ee91a982941ad2fc3adf973b3f8a2127 Mon Sep 17 00:00:00 2001 From: Laura Hermanns Date: Thu, 5 Sep 2024 15:24:29 -0400 Subject: [PATCH 506/523] [opt] Add struct-packing pass and unit test. (#5778) This pass allows to re-assign offset layout decorations to tightly pack a struct according to its packing rules. --- Android.mk | 1 + include/spirv-tools/optimizer.hpp | 9 + source/opt/CMakeLists.txt | 1 + source/opt/optimizer.cpp | 28 ++ source/opt/passes.h | 1 + source/opt/struct_packing_pass.cpp | 482 +++++++++++++++++++++++++++++ source/opt/struct_packing_pass.h | 81 +++++ test/opt/CMakeLists.txt | 1 + test/opt/struct_packing_test.cpp | 242 +++++++++++++++ tools/opt/opt.cpp | 4 + utils/check_copyright.py | 3 +- 11 files changed, 852 insertions(+), 1 deletion(-) create mode 100644 source/opt/struct_packing_pass.cpp create mode 100644 source/opt/struct_packing_pass.h create mode 100644 test/opt/struct_packing_test.cpp diff --git a/Android.mk b/Android.mk index af3ff30401..c85a595c52 100644 --- a/Android.mk +++ b/Android.mk @@ -183,6 +183,7 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/strip_debug_info_pass.cpp \ source/opt/strip_nonsemantic_info_pass.cpp \ source/opt/struct_cfg_analysis.cpp \ + source/opt/struct_packing_pass.cpp \ source/opt/switch_descriptorset_pass.cpp \ source/opt/trim_capabilities_pass.cpp \ source/opt/type_manager.cpp \ diff --git a/include/spirv-tools/optimizer.hpp b/include/spirv-tools/optimizer.hpp index fe02ec7d70..9677b15d10 100644 --- a/include/spirv-tools/optimizer.hpp +++ b/include/spirv-tools/optimizer.hpp @@ -956,6 +956,15 @@ Optimizer::PassToken CreateFixFuncCallArgumentsPass(); // the unknown capability interacts with one of the trimmed capabilities. Optimizer::PassToken CreateTrimCapabilitiesPass(); +// Creates a struct-packing pass. +// This pass re-assigns all offset layout decorators to tightly pack +// the struct with OpName matching `structToPack` according to the given packing +// rule. Accepted packing rules are: std140, std140EnhancedLayout, std430, +// std430EnhancedLayout, hlslCbuffer, hlslCbufferPackOffset, scalar, +// scalarEnhancedLayout. +Optimizer::PassToken CreateStructPackingPass(const char* structToPack, + const char* packingRule); + // Creates a switch-descriptorset pass. // This pass changes any DescriptorSet decorations with the value |ds_from| to // use the new value |ds_to|. diff --git a/source/opt/CMakeLists.txt b/source/opt/CMakeLists.txt index 51153d7ab6..5e6a5193e6 100644 --- a/source/opt/CMakeLists.txt +++ b/source/opt/CMakeLists.txt @@ -240,6 +240,7 @@ set(SPIRV_TOOLS_OPT_SOURCES strip_debug_info_pass.cpp strip_nonsemantic_info_pass.cpp struct_cfg_analysis.cpp + struct_packing_pass.cpp switch_descriptorset_pass.cpp trim_capabilities_pass.cpp type_manager.cpp diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp index 4523d627e0..22eb24c4fc 100644 --- a/source/opt/optimizer.cpp +++ b/source/opt/optimizer.cpp @@ -571,6 +571,26 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag, pass_args.c_str()); return false; } + } else if (pass_name == "struct-packing") { + if (pass_args.size() == 0) { + Error(consumer(), nullptr, {}, + "--struct-packing requires a name:rule argument."); + return false; + } + + auto separator_pos = pass_args.find(':'); + if (separator_pos == std::string::npos || separator_pos == 0 || + separator_pos + 1 == pass_args.size()) { + Errorf(consumer(), nullptr, {}, + "Invalid argument for --struct-packing: %s", pass_args.c_str()); + return false; + } + + const std::string struct_name = pass_args.substr(0, separator_pos); + const std::string rule_name = pass_args.substr(separator_pos + 1); + + RegisterPass( + CreateStructPackingPass(struct_name.c_str(), rule_name.c_str())); } else if (pass_name == "switch-descriptorset") { if (pass_args.size() == 0) { Error(consumer(), nullptr, {}, @@ -1152,6 +1172,14 @@ Optimizer::PassToken CreateTrimCapabilitiesPass() { MakeUnique()); } +Optimizer::PassToken CreateStructPackingPass(const char* structToPack, + const char* packingRule) { + return MakeUnique( + MakeUnique( + structToPack, + opt::StructPackingPass::ParsePackingRuleFromString(packingRule))); +} + Optimizer::PassToken CreateSwitchDescriptorSetPass(uint32_t from, uint32_t to) { return MakeUnique( MakeUnique(from, to)); diff --git a/source/opt/passes.h b/source/opt/passes.h index ac68ccdc8a..f8301526f2 100644 --- a/source/opt/passes.h +++ b/source/opt/passes.h @@ -83,6 +83,7 @@ #include "source/opt/strength_reduction_pass.h" #include "source/opt/strip_debug_info_pass.h" #include "source/opt/strip_nonsemantic_info_pass.h" +#include "source/opt/struct_packing_pass.h" #include "source/opt/switch_descriptorset_pass.h" #include "source/opt/trim_capabilities_pass.h" #include "source/opt/unify_const_pass.h" diff --git a/source/opt/struct_packing_pass.cpp b/source/opt/struct_packing_pass.cpp new file mode 100644 index 0000000000..3bf2b2ab41 --- /dev/null +++ b/source/opt/struct_packing_pass.cpp @@ -0,0 +1,482 @@ +// Copyright (c) 2024 Epic Games, 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 "struct_packing_pass.h" + +#include + +#include "source/opt/instruction.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace opt { + +/* +Std140 packing rules from the original GLSL 140 specification (see +https://registry.khronos.org/OpenGL/extensions/ARB/ARB_uniform_buffer_object.txt) + +When using the "std140" storage layout, structures will be laid out in +buffer storage with its members stored in monotonically increasing order +based on their location in the declaration. A structure and each +structure member have a base offset and a base alignment, from which an +aligned offset is computed by rounding the base offset up to a multiple of +the base alignment. The base offset of the first member of a structure is +taken from the aligned offset of the structure itself. The base offset of +all other structure members is derived by taking the offset of the last +basic machine unit consumed by the previous member and adding one. Each +structure member is stored in memory at its aligned offset. The members +of a top-level uniform block are laid out in buffer storage by treating +the uniform block as a structure with a base offset of zero. + +(1) If the member is a scalar consuming basic machine units, the + base alignment is . + +(2) If the member is a two- or four-component vector with components + consuming basic machine units, the base alignment is 2 or + 4, respectively. + +(3) If the member is a three-component vector with components consuming + basic machine units, the base alignment is 4. + +(4) If the member is an array of scalars or vectors, the base alignment + and array stride are set to match the base alignment of a single + array element, according to rules (1), (2), and (3), and rounded up + to the base alignment of a vec4. The array may have padding at the + end; the base offset of the member following the array is rounded up + to the next multiple of the base alignment. + +(5) If the member is a column-major matrix with columns and + rows, the matrix is stored identically to an array of column + vectors with components each, according to rule (4). + +(6) If the member is an array of column-major matrices with + columns and rows, the matrix is stored identically to a row of + * column vectors with components each, according to rule + (4). + +(7) If the member is a row-major matrix with columns and rows, + the matrix is stored identically to an array of row vectors + with components each, according to rule (4). + +(8) If the member is an array of row-major matrices with columns + and rows, the matrix is stored identically to a row of * + row vectors with components each, according to rule (4). + +(9) If the member is a structure, the base alignment of the structure is + , where is the largest base alignment value of any of its + members, and rounded up to the base alignment of a vec4. The + individual members of this sub-structure are then assigned offsets + by applying this set of rules recursively, where the base offset of + the first member of the sub-structure is equal to the aligned offset + of the structure. The structure may have padding at the end; the + base offset of the member following the sub-structure is rounded up + to the next multiple of the base alignment of the structure. + +(10) If the member is an array of structures, the elements of + the array are laid out in order, according to rule (9). +*/ + +static bool isPackingVec4Padded(StructPackingPass::PackingRules rules) { + switch (rules) { + case StructPackingPass::PackingRules::Std140: + case StructPackingPass::PackingRules::Std140EnhancedLayout: + case StructPackingPass::PackingRules::HlslCbuffer: + case StructPackingPass::PackingRules::HlslCbufferPackOffset: + return true; + default: + return false; + } +} + +static bool isPackingScalar(StructPackingPass::PackingRules rules) { + switch (rules) { + case StructPackingPass::PackingRules::Scalar: + case StructPackingPass::PackingRules::ScalarEnhancedLayout: + return true; + default: + return false; + } +} + +static bool isPackingHlsl(StructPackingPass::PackingRules rules) { + switch (rules) { + case StructPackingPass::PackingRules::HlslCbuffer: + case StructPackingPass::PackingRules::HlslCbufferPackOffset: + return true; + default: + return false; + } +} + +static uint32_t getPackedBaseSize(const analysis::Type& type) { + switch (type.kind()) { + case analysis::Type::kBool: + return 1; + case analysis::Type::kInteger: + return type.AsInteger()->width() / 8; + case analysis::Type::kFloat: + return type.AsFloat()->width() / 8; + case analysis::Type::kVector: + return getPackedBaseSize(*type.AsVector()->element_type()); + case analysis::Type::kMatrix: + return getPackedBaseSize(*type.AsMatrix()->element_type()); + default: + break; // we only expect bool, int, float, vec, and mat here + } + assert(0 && "Unrecognized type to get base size"); + return 0; +} + +static uint32_t getScalarElementCount(const analysis::Type& type) { + switch (type.kind()) { + case analysis::Type::kVector: + return type.AsVector()->element_count(); + case analysis::Type::kMatrix: + return getScalarElementCount(*type.AsMatrix()->element_type()); + case analysis::Type::kStruct: + assert(0 && "getScalarElementCount() does not recognized struct types"); + return 0; + default: + return 1; + } +} + +// Aligns the specified value to a multiple of alignment, whereas the +// alignment must be a power-of-two. +static uint32_t alignPow2(uint32_t value, uint32_t alignment) { + return (value + alignment - 1) & ~(alignment - 1); +} + +void StructPackingPass::buildConstantsMap() { + constantsMap_.clear(); + for (Instruction* instr : context()->module()->GetConstants()) { + constantsMap_[instr->result_id()] = instr; + } +} + +uint32_t StructPackingPass::getPackedAlignment( + const analysis::Type& type) const { + switch (type.kind()) { + case analysis::Type::kArray: { + // Get alignment of base type and round up to minimum alignment + const uint32_t minAlignment = isPackingVec4Padded(packingRules_) ? 16 : 1; + return std::max( + minAlignment, getPackedAlignment(*type.AsArray()->element_type())); + } + case analysis::Type::kStruct: { + // Rule 9. Struct alignment is maximum alignmnet of its members + uint32_t alignment = 1; + + for (const analysis::Type* elementType : + type.AsStruct()->element_types()) { + alignment = + std::max(alignment, getPackedAlignment(*elementType)); + } + + if (isPackingVec4Padded(packingRules_)) + alignment = std::max(alignment, 16u); + + return alignment; + } + default: { + const uint32_t baseAlignment = getPackedBaseSize(type); + + // Scalar block layout always uses alignment for the most basic component + if (isPackingScalar(packingRules_)) return baseAlignment; + + if (const analysis::Matrix* matrixType = type.AsMatrix()) { + // Rule 5/7 + if (isPackingVec4Padded(packingRules_) || + matrixType->element_count() == 3) + return baseAlignment * 4; + else + return baseAlignment * matrixType->element_count(); + } else if (const analysis::Vector* vectorType = type.AsVector()) { + // Rule 1 + if (vectorType->element_count() == 1) return baseAlignment; + + // Rule 2 + if (vectorType->element_count() == 2 || + vectorType->element_count() == 4) + return baseAlignment * vectorType->element_count(); + + // Rule 3 + if (vectorType->element_count() == 3) return baseAlignment * 4; + } else { + // Rule 1 + return baseAlignment; + } + } + } + assert(0 && "Unrecognized type to get packed alignment"); + return 0; +} + +static uint32_t getPadAlignment(const analysis::Type& type, + uint32_t packedAlignment) { + // The next member following a struct member is aligned to the base alignment + // of a previous struct member. + return type.kind() == analysis::Type::kStruct ? packedAlignment : 1; +} + +uint32_t StructPackingPass::getPackedSize(const analysis::Type& type) const { + switch (type.kind()) { + case analysis::Type::kArray: { + if (const analysis::Array* arrayType = type.AsArray()) { + uint32_t size = + getPackedArrayStride(*arrayType) * getArrayLength(*arrayType); + + // For arrays of vector and matrices in HLSL, the last element has a + // size depending on its vector/matrix size to allow packing other + // vectors in the last element. + const analysis::Type* arraySubType = arrayType->element_type(); + if (isPackingHlsl(packingRules_) && + arraySubType->kind() != analysis::Type::kStruct) { + size -= (4 - getScalarElementCount(*arraySubType)) * + getPackedBaseSize(*arraySubType); + } + return size; + } + break; + } + case analysis::Type::kStruct: { + uint32_t size = 0; + uint32_t padAlignment = 1; + for (const analysis::Type* memberType : + type.AsStruct()->element_types()) { + const uint32_t packedAlignment = getPackedAlignment(*memberType); + const uint32_t alignment = + std::max(packedAlignment, padAlignment); + padAlignment = getPadAlignment(*memberType, packedAlignment); + size = alignPow2(size, alignment); + size += getPackedSize(*memberType); + } + return size; + } + default: { + const uint32_t baseAlignment = getPackedBaseSize(type); + if (isPackingScalar(packingRules_)) { + return getScalarElementCount(type) * baseAlignment; + } else { + uint32_t size = 0; + if (const analysis::Matrix* matrixType = type.AsMatrix()) { + const analysis::Vector* matrixSubType = + matrixType->element_type()->AsVector(); + assert(matrixSubType != nullptr && + "Matrix sub-type is expected to be a vector type"); + if (isPackingVec4Padded(packingRules_) || + matrixType->element_count() == 3) + size = matrixSubType->element_count() * baseAlignment * 4; + else + size = matrixSubType->element_count() * baseAlignment * + matrixType->element_count(); + + // For matrices in HLSL, the last element has a size depending on its + // vector size to allow packing other vectors in the last element. + if (isPackingHlsl(packingRules_)) { + size -= (4 - matrixSubType->element_count()) * + getPackedBaseSize(*matrixSubType); + } + } else if (const analysis::Vector* vectorType = type.AsVector()) { + size = vectorType->element_count() * baseAlignment; + } else { + size = baseAlignment; + } + return size; + } + } + } + assert(0 && "Unrecognized type to get packed size"); + return 0; +} + +uint32_t StructPackingPass::getPackedArrayStride( + const analysis::Array& arrayType) const { + // Array stride is equal to aligned size of element type + const uint32_t elementSize = getPackedSize(*arrayType.element_type()); + const uint32_t alignment = getPackedAlignment(arrayType); + return alignPow2(elementSize, alignment); +} + +uint32_t StructPackingPass::getArrayLength( + const analysis::Array& arrayType) const { + return getConstantInt(arrayType.LengthId()); +} + +uint32_t StructPackingPass::getConstantInt(spv::Id id) const { + auto it = constantsMap_.find(id); + assert(it != constantsMap_.end() && + "Failed to map SPIR-V instruction ID to constant value"); + [[maybe_unused]] const analysis::Type* constType = + context()->get_type_mgr()->GetType(it->second->type_id()); + assert(constType != nullptr && + "Failed to map SPIR-V instruction result type to definition"); + assert(constType->kind() == analysis::Type::kInteger && + "Failed to map SPIR-V instruction result type to integer type"); + return it->second->GetOperand(2).words[0]; +} + +StructPackingPass::PackingRules StructPackingPass::ParsePackingRuleFromString( + const std::string& s) { + if (s == "std140") return PackingRules::Std140; + if (s == "std140EnhancedLayout") return PackingRules::Std140EnhancedLayout; + if (s == "std430") return PackingRules::Std430; + if (s == "std430EnhancedLayout") return PackingRules::Std430EnhancedLayout; + if (s == "hlslCbuffer") return PackingRules::HlslCbuffer; + if (s == "hlslCbufferPackOffset") return PackingRules::HlslCbufferPackOffset; + if (s == "scalar") return PackingRules::Scalar; + if (s == "scalarEnhancedLayout") return PackingRules::ScalarEnhancedLayout; + return PackingRules::Undefined; +} + +StructPackingPass::StructPackingPass(const char* structToPack, + PackingRules rules) + : structToPack_{structToPack != nullptr ? structToPack : ""}, + packingRules_{rules} {} + +Pass::Status StructPackingPass::Process() { + if (packingRules_ == PackingRules::Undefined) { + if (consumer()) { + consumer()(SPV_MSG_ERROR, "", {0, 0, 0}, + "Cannot pack struct with undefined rule"); + } + return Status::Failure; + } + + // Build Id-to-instruction map for easier access + buildConstantsMap(); + + // Find structure of interest + const uint32_t structIdToPack = findStructIdByName(structToPack_.c_str()); + + const Instruction* structDef = + context()->get_def_use_mgr()->GetDef(structIdToPack); + if (structDef == nullptr || structDef->opcode() != spv::Op::OpTypeStruct) { + if (consumer()) { + const std::string message = + "Failed to find struct with name " + structToPack_; + consumer()(SPV_MSG_ERROR, "", {0, 0, 0}, message.c_str()); + } + return Status::Failure; + } + + // Find all struct member types + std::vector structMemberTypes = + findStructMemberTypes(*structDef); + + return assignStructMemberOffsets(structIdToPack, structMemberTypes); +} + +uint32_t StructPackingPass::findStructIdByName(const char* structName) const { + for (Instruction& instr : context()->module()->debugs2()) { + if (instr.opcode() == spv::Op::OpName && + instr.GetOperand(1).AsString() == structName) { + return instr.GetOperand(0).AsId(); + } + } + return 0; +} + +std::vector StructPackingPass::findStructMemberTypes( + const Instruction& structDef) const { + // Found struct type to pack, now collect all types of its members + assert(structDef.NumOperands() > 0 && + "Number of operands in OpTypeStruct instruction must not be zero"); + const uint32_t numMembers = structDef.NumOperands() - 1; + std::vector structMemberTypes; + structMemberTypes.resize(numMembers); + for (uint32_t i = 0; i < numMembers; ++i) { + const spv::Id memberTypeId = structDef.GetOperand(1 + i).AsId(); + if (const analysis::Type* memberType = + context()->get_type_mgr()->GetType(memberTypeId)) { + structMemberTypes[i] = memberType; + } + } + return structMemberTypes; +} + +Pass::Status StructPackingPass::assignStructMemberOffsets( + uint32_t structIdToPack, + const std::vector& structMemberTypes) { + // Returns true if the specified instruction is a OpMemberDecorate for the + // struct we're looking for with an offset decoration + auto isMemberOffsetDecoration = + [structIdToPack](const Instruction& instr) -> bool { + return instr.opcode() == spv::Op::OpMemberDecorate && + instr.GetOperand(0).AsId() == structIdToPack && + static_cast(instr.GetOperand(2).words[0]) == + spv::Decoration::Offset; + }; + + bool modified = false; + + // Find and re-assign all member offset decorations + for (auto it = context()->module()->annotation_begin(), + itEnd = context()->module()->annotation_end(); + it != itEnd; ++it) { + if (isMemberOffsetDecoration(*it)) { + // Found first member decoration with offset, we expect all other + // offsets right after the first one + uint32_t prevMemberIndex = 0; + uint32_t currentOffset = 0; + uint32_t padAlignment = 1; + do { + const uint32_t memberIndex = it->GetOperand(1).words[0]; + if (memberIndex < prevMemberIndex) { + // Failure: we expect all members to appear in consecutive order + return Status::Failure; + } + + // Apply alignment rules to current offset + const analysis::Type& memberType = *structMemberTypes[memberIndex]; + uint32_t packedAlignment = getPackedAlignment(memberType); + uint32_t packedSize = getPackedSize(memberType); + + if (isPackingHlsl(packingRules_)) { + // If a member crosses vec4 boundaries, alignment is size of vec4 + if (currentOffset / 16 != (currentOffset + packedSize - 1) / 16) + packedAlignment = std::max(packedAlignment, 16u); + } + + const uint32_t alignment = + std::max(packedAlignment, padAlignment); + currentOffset = alignPow2(currentOffset, alignment); + padAlignment = getPadAlignment(memberType, packedAlignment); + + // Override packed offset in instruction + if (it->GetOperand(3).words[0] < currentOffset) { + // Failure: packing resulted in higher offset for member than + // previously generated + return Status::Failure; + } + + it->GetOperand(3).words[0] = currentOffset; + modified = true; + + // Move to next member + ++it; + prevMemberIndex = memberIndex; + currentOffset += packedSize; + } while (it != itEnd && isMemberOffsetDecoration(*it)); + + // We're done with all decorations for the struct of interest + break; + } + } + + return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange; +} + +} // namespace opt +} // namespace spvtools diff --git a/source/opt/struct_packing_pass.h b/source/opt/struct_packing_pass.h new file mode 100644 index 0000000000..3f30f98a5d --- /dev/null +++ b/source/opt/struct_packing_pass.h @@ -0,0 +1,81 @@ +// Copyright (c) 2024 Epic Games, 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_STRUCT_PACKING_PASS_ +#define SOURCE_OPT_STRUCT_PACKING_PASS_ + +#include + +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// This pass re-assigns all field offsets under the specified packing rules. +class StructPackingPass final : public Pass { + public: + enum class PackingRules { + Undefined, + Std140, + Std140EnhancedLayout, + Std430, + Std430EnhancedLayout, + HlslCbuffer, + HlslCbufferPackOffset, + Scalar, + ScalarEnhancedLayout, + }; + + static PackingRules ParsePackingRuleFromString(const std::string& s); + + StructPackingPass(const char* structToPack, PackingRules rules); + const char* name() const override { return "struct-packing"; } + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisCombinators | IRContext::kAnalysisCFG | + IRContext::kAnalysisDominatorAnalysis | + IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisScalarEvolution | + IRContext::kAnalysisStructuredCFG | IRContext::kAnalysisConstants | + IRContext::kAnalysisDebugInfo | IRContext::kAnalysisLiveness; + } + + private: + void buildConstantsMap(); + uint32_t findStructIdByName(const char* structName) const; + std::vector findStructMemberTypes( + const Instruction& structDef) const; + Status assignStructMemberOffsets( + uint32_t structIdToPack, + const std::vector& structMemberTypes); + + uint32_t getPackedAlignment(const analysis::Type& type) const; + uint32_t getPackedSize(const analysis::Type& type) const; + uint32_t getPackedArrayStride(const analysis::Array& arrayType) const; + uint32_t getArrayLength(const analysis::Array& arrayType) const; + uint32_t getConstantInt(spv::Id id) const; + + private: + std::string structToPack_; + PackingRules packingRules_ = PackingRules::Undefined; + std::unordered_map constantsMap_; +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_STRUCT_PACKING_PASS_ diff --git a/test/opt/CMakeLists.txt b/test/opt/CMakeLists.txt index 4126452d5e..2569976231 100644 --- a/test/opt/CMakeLists.txt +++ b/test/opt/CMakeLists.txt @@ -104,6 +104,7 @@ add_spvtools_unittest(TARGET opt strip_debug_info_test.cpp strip_nonsemantic_info_test.cpp struct_cfg_analysis_test.cpp + struct_packing_test.cpp switch_descriptorset_test.cpp trim_capabilities_pass_test.cpp type_manager_test.cpp diff --git a/test/opt/struct_packing_test.cpp b/test/opt/struct_packing_test.cpp new file mode 100644 index 0000000000..1b8e8d1a08 --- /dev/null +++ b/test/opt/struct_packing_test.cpp @@ -0,0 +1,242 @@ +// Copyright (c) 2024 Epic Games, 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 + +#include "gmock/gmock.h" +#include "source/opt/struct_packing_pass.h" +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +using StructPackingTest = PassTest<::testing::Test>; + +TEST_F(StructPackingTest, PackSimpleStructStd140) { + // #version 420 + // + // layout(std140, binding = 0) uniform Globals { + // layout(offset = 16) vec3 a_xyz; + // float a_w; + // layout(offset = 128) vec3 b_xyz; + // int b_w; + // }; + // + // void main() {} + const std::string spirv = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginLowerLeft +OpSource GLSL 420 +OpName %main "main" +OpName %Globals "Globals" +OpMemberName %Globals 0 "a_xyz" +OpMemberName %Globals 1 "a_w" +OpMemberName %Globals 2 "b_xyz" +OpMemberName %Globals 3 "b_w" +OpName %_ "" +; CHECK: OpMemberDecorate %Globals 0 Offset 0 +OpMemberDecorate %Globals 0 Offset 16 +; CHECK: OpMemberDecorate %Globals 1 Offset 12 +OpMemberDecorate %Globals 1 Offset 28 +; CHECK: OpMemberDecorate %Globals 2 Offset 16 +OpMemberDecorate %Globals 2 Offset 128 +; CHECK: OpMemberDecorate %Globals 3 Offset 28 +OpMemberDecorate %Globals 3 Offset 140 +OpDecorate %Globals Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v3float = OpTypeVector %float 3 +%int = OpTypeInt 32 1 +%Globals = OpTypeStruct %v3float %float %v3float %int +%_ptr_Uniform_Globals = OpTypePointer Uniform %Globals +%_ = OpVariable %_ptr_Uniform_Globals Uniform +%main = OpFunction %void None %3 +%5 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch( + spirv, true, "Globals", StructPackingPass::PackingRules::Std140); +} + +TEST_F(StructPackingTest, PackSimpleStructWithPaddingStd140) { + // #version 420 + // + // layout(std140, binding = 0) uniform Globals { + // layout(offset = 16) vec3 a_xyz; + // float a_w; + // float b_x_padding_yzw; + // layout(offset = 128) vec3 c_xyz; + // int c_w; + // }; + // + // void main() {} + const std::string spirv = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginLowerLeft +OpSource GLSL 420 +OpName %main "main" +OpName %Globals "Globals" +OpMemberName %Globals 0 "a_xyz" +OpMemberName %Globals 1 "a_w" +OpMemberName %Globals 2 "b_x_padding_yzw" +OpMemberName %Globals 3 "c_xyz" +OpMemberName %Globals 4 "c_w" +OpName %_ "" +; CHECK: OpMemberDecorate %Globals 0 Offset 0 +OpMemberDecorate %Globals 0 Offset 16 +; CHECK: OpMemberDecorate %Globals 1 Offset 12 +OpMemberDecorate %Globals 1 Offset 28 +; CHECK: OpMemberDecorate %Globals 2 Offset 16 +OpMemberDecorate %Globals 2 Offset 32 +; CHECK: OpMemberDecorate %Globals 3 Offset 32 +OpMemberDecorate %Globals 3 Offset 128 +; CHECK: OpMemberDecorate %Globals 4 Offset 44 +OpMemberDecorate %Globals 4 Offset 140 +OpDecorate %Globals Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v3float = OpTypeVector %float 3 +%int = OpTypeInt 32 1 +%Globals = OpTypeStruct %v3float %float %float %v3float %int +%_ptr_Uniform_Globals = OpTypePointer Uniform %Globals +%_ = OpVariable %_ptr_Uniform_Globals Uniform +%main = OpFunction %void None %3 +%5 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch( + spirv, true, "Globals", StructPackingPass::PackingRules::Std140); +} + +TEST_F(StructPackingTest, PackSimpleScalarArrayStd140) { + // #version 420 + // + // layout(std140, binding = 0) uniform Globals { + // layout(offset = 16) float a[2]; + // layout(offset = 128) float b[2]; // Must become offset 32 with std140 + // }; + // + // void main() {} + const std::string spirv = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginLowerLeft +OpSource GLSL 420 +OpName %main "main" +OpName %Globals "Globals" +OpMemberName %Globals 0 "a" +OpMemberName %Globals 1 "b" +OpName %_ "" +OpDecorate %_arr_float_uint_2 ArrayStride 16 +OpDecorate %_arr_float_uint_2_0 ArrayStride 16 +; CHECK: OpMemberDecorate %Globals 0 Offset 0 +OpMemberDecorate %Globals 0 Offset 16 +; CHECK: OpMemberDecorate %Globals 1 Offset 32 +OpMemberDecorate %Globals 1 Offset 128 +OpDecorate %Globals Block +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%uint = OpTypeInt 32 0 +%uint_2 = OpConstant %uint 2 +%_arr_float_uint_2 = OpTypeArray %float %uint_2 +%_arr_float_uint_2_0 = OpTypeArray %float %uint_2 +%Globals = OpTypeStruct %_arr_float_uint_2 %_arr_float_uint_2_0 +%_ptr_Uniform_Globals = OpTypePointer Uniform %Globals +%_ = OpVariable %_ptr_Uniform_Globals Uniform +%main = OpFunction %void None %3 +%5 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch( + spirv, true, "Globals", StructPackingPass::PackingRules::Std140); +} + +TEST_F(StructPackingTest, PackSimpleScalarArrayStd430) { + // #version 430 + // + // layout(std430, binding = 0) buffer Globals { + // layout(offset = 16) float a[2]; + // layout(offset = 128) float b[2]; // Must become offset 8 with std430 + // }; + // + // void main() {} + const std::string spirv = R"( +OpCapability Shader +%1 = OpExtInstImport "GLSL.std.450" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginLowerLeft +OpSource GLSL 430 +OpName %main "main" +OpName %Globals "Globals" +OpMemberName %Globals 0 "a" +OpMemberName %Globals 1 "b" +OpName %_ "" +OpDecorate %_arr_float_uint_2 ArrayStride 4 +OpDecorate %_arr_float_uint_2_0 ArrayStride 4 +; CHECK: OpMemberDecorate %Globals 0 Offset 0 +OpMemberDecorate %Globals 0 Offset 16 +; CHECK: OpMemberDecorate %Globals 1 Offset 8 +OpMemberDecorate %Globals 1 Offset 128 +OpDecorate %Globals BufferBlock +OpDecorate %_ DescriptorSet 0 +OpDecorate %_ Binding 0 +%void = OpTypeVoid +%3 = OpTypeFunction %void +%float = OpTypeFloat 32 +%uint = OpTypeInt 32 0 +%uint_2 = OpConstant %uint 2 +%_arr_float_uint_2 = OpTypeArray %float %uint_2 +%_arr_float_uint_2_0 = OpTypeArray %float %uint_2 +%Globals = OpTypeStruct %_arr_float_uint_2 %_arr_float_uint_2_0 +%_ptr_Uniform_Globals = OpTypePointer Uniform %Globals +%_ = OpVariable %_ptr_Uniform_Globals Uniform +%main = OpFunction %void None %3 +%5 = OpLabel +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch( + spirv, true, "Globals", StructPackingPass::PackingRules::Std430); +} + +} // namespace +} // namespace opt +} // namespace spvtools diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 3b8d5fc236..52e5448989 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -515,6 +515,10 @@ Options (in lexicographical order):)", covers reflection information defined by SPV_GOOGLE_hlsl_functionality1 and SPV_KHR_non_semantic_info)"); printf(R"( + --struct-packing=name:rule + Re-assign layout offsets to a given struct according to + its packing rules.)"); + printf(R"( --switch-descriptorset=: Switch any DescriptoSet decorations using the value to the new value .)"); diff --git a/utils/check_copyright.py b/utils/check_copyright.py index a849d04672..a6459233a5 100755 --- a/utils/check_copyright.py +++ b/utils/check_copyright.py @@ -42,7 +42,8 @@ 'Mostafa Ashraf', 'Shiyu Liu', 'ZHOU He', - 'Nintendo'] + 'Nintendo', + 'Epic Games, Inc.'] CURRENT_YEAR = 2023 FIRST_YEAR = 2014 From f914d9c8a4bdcffb736bac206fbd858fe9bd424d Mon Sep 17 00:00:00 2001 From: Viktoria Maximova Date: Fri, 6 Sep 2024 16:59:59 +0200 Subject: [PATCH 507/523] [SPV_KHR_untyped_pointers] Fix verification of vload/vstore OpenCL.std instructions (#5788) * [SPV_KHR_untyped_pointers] Fix verification of vload/vstore OpenCL.std instructions Allow `p` to be untyped pointer. ``` operand must be a pointer(p1, ...).If it is a typed pointer, it must point to data types. ``` https://htmlpreview.github.io/?https://github.com/KhronosGroup/SPIRV-Registry/blob/main/extensions/KHR/SPV_KHR_untyped_pointers.html#_modifications_to_the_opencl_std_extended_instruction_set * relax printf check as well --- source/val/validate_extensions.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/source/val/validate_extensions.cpp b/source/val/validate_extensions.cpp index 49ba236fcb..e26df28807 100644 --- a/source/val/validate_extensions.cpp +++ b/source/val/validate_extensions.cpp @@ -2701,8 +2701,9 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { "Generic, CrossWorkgroup, Workgroup or Function"; } - if (!_.IsFloatScalarType(p_data_type) || - _.GetBitWidth(p_data_type) != 16) { + if ((!_.IsFloatScalarType(p_data_type) || + _.GetBitWidth(p_data_type) != 16) && + !_.ContainsUntypedPointer(p_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": " << "expected operand P data type to be 16-bit float scalar"; @@ -2763,8 +2764,9 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { "Generic, CrossWorkgroup, Workgroup or Function"; } - if (!_.IsFloatScalarType(p_data_type) || - _.GetBitWidth(p_data_type) != 16) { + if ((!_.IsFloatScalarType(p_data_type) || + _.GetBitWidth(p_data_type) != 16) && + !_.ContainsUntypedPointer(p_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": " << "expected operand P data type to be 16-bit float scalar"; @@ -2855,8 +2857,9 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { "CrossWorkgroup, Workgroup or Function"; } - if (!_.IsFloatScalarType(p_data_type) || - _.GetBitWidth(p_data_type) != 16) { + if ((!_.IsFloatScalarType(p_data_type) || + _.GetBitWidth(p_data_type) != 16) && + !_.ContainsUntypedPointer(p_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": " << "expected operand P data type to be 16-bit float scalar"; @@ -2994,8 +2997,9 @@ spv_result_t ValidateExtInst(ValidationState_t& _, const Instruction* inst) { if (_.IsIntArrayType(format_data_type)) format_data_type = _.GetComponentType(format_data_type); - if (!_.IsIntScalarType(format_data_type) || - _.GetBitWidth(format_data_type) != 8) { + if ((!_.IsIntScalarType(format_data_type) || + _.GetBitWidth(format_data_type) != 8) && + !_.ContainsUntypedPointer(format_type)) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << ext_inst_name() << ": " << "expected Format data type to be 8-bit int"; From 07f49ce65d350ba585ac0696ad5c868163928789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nathan=20Gau=C3=ABr?= Date: Mon, 9 Sep 2024 14:59:51 +0200 Subject: [PATCH 508/523] spirv-opt: make traversal deterministic (#5790) Related to https://github.com/microsoft/DirectXShaderCompiler/issues/6804 --- source/opt/remove_unused_interface_variables_pass.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source/opt/remove_unused_interface_variables_pass.cpp b/source/opt/remove_unused_interface_variables_pass.cpp index d4df1b2efd..c3a4b775a1 100644 --- a/source/opt/remove_unused_interface_variables_pass.cpp +++ b/source/opt/remove_unused_interface_variables_pass.cpp @@ -21,6 +21,8 @@ class RemoveUnusedInterfaceVariablesContext { RemoveUnusedInterfaceVariablesPass& parent_; Instruction& entry_; std::unordered_set used_variables_; + std::vector operands_to_add_; + IRContext::ProcessFunction pfn_ = std::bind(&RemoveUnusedInterfaceVariablesContext::processFunction, this, std::placeholders::_1); @@ -38,8 +40,10 @@ class RemoveUnusedInterfaceVariablesContext { (parent_.get_module()->version() >= SPV_SPIRV_VERSION_WORD(1, 4) || storage_class == spv::StorageClass::Input || - storage_class == spv::StorageClass::Output)) + storage_class == spv::StorageClass::Output)) { used_variables_.insert(*id); + operands_to_add_.push_back(*id); + } }); return false; } @@ -71,7 +75,7 @@ class RemoveUnusedInterfaceVariablesContext { void Modify() { for (int i = entry_.NumInOperands() - 1; i >= 3; --i) entry_.RemoveInOperand(i); - for (auto id : used_variables_) { + for (auto id : operands_to_add_) { entry_.AddOperand(Operand(SPV_OPERAND_TYPE_ID, {id})); } } From e9915cea8d7da75fba6eaca2b02db219252c1e89 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Mon, 9 Sep 2024 13:09:19 -0400 Subject: [PATCH 509/523] Update sampled image validation (#5789) Fixes #5781 * Requires all image operands to match except for depth between operand and result --- source/val/validate_image.cpp | 24 +++- test/val/val_image_test.cpp | 229 +++++++++++++++++++++++++++++++++- 2 files changed, 248 insertions(+), 5 deletions(-) diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp index faf661afb7..e77fc12994 100644 --- a/source/val/validate_image.cpp +++ b/source/val/validate_image.cpp @@ -1005,7 +1005,8 @@ bool IsAllowedSampledImageOperand(spv::Op opcode, ValidationState_t& _) { spv_result_t ValidateSampledImage(ValidationState_t& _, const Instruction* inst) { - if (_.GetIdOpcode(inst->type_id()) != spv::Op::OpTypeSampledImage) { + auto type_inst = _.FindDef(inst->type_id()); + if (type_inst->opcode() != spv::Op::OpTypeSampledImage) { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected Result Type to be OpTypeSampledImage."; } @@ -1022,8 +1023,25 @@ spv_result_t ValidateSampledImage(ValidationState_t& _, << "Corrupt image type definition"; } - // TODO(atgoo@github.com) Check compatibility of result type and received - // image. + // Image operands must match except for depth. + auto sampled_image_id = type_inst->GetOperandAs(1); + if (sampled_image_id != image_type) { + ImageTypeInfo sampled_info; + if (!GetImageTypeInfo(_, sampled_image_id, &sampled_info)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Corrupt image type definition"; + } + if (info.sampled_type != sampled_info.sampled_type || + info.dim != sampled_info.dim || info.arrayed != sampled_info.arrayed || + info.multisampled != sampled_info.multisampled || + info.sampled != sampled_info.sampled || + info.format != sampled_info.format || + info.access_qualifier != sampled_info.access_qualifier) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Image operands must match result image operands except for " + "depth"; + } + } if (spvIsVulkanEnv(_.context()->target_env)) { if (info.sampled != 1) { diff --git a/test/val/val_image_test.cpp b/test/val/val_image_test.cpp index 77b042f04c..07f0200e21 100644 --- a/test/val/val_image_test.cpp +++ b/test/val/val_image_test.cpp @@ -4451,7 +4451,7 @@ TEST_F(ValidateImage, QuerySizeNotImage) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler %res1 = OpImageQuerySize %u32vec2 %sampler )"; @@ -4465,7 +4465,7 @@ TEST_F(ValidateImage, QuerySizeSampledImageDirectly) { const std::string body = R"( %img = OpLoad %type_image_f32_2d_0011 %uniform_image_f32_2d_0011 %sampler = OpLoad %type_sampler %uniform_sampler -%simg = OpSampledImage %type_sampled_image_f32_2d_0001 %img %sampler +%simg = OpSampledImage %type_sampled_image_f32_2d_0011 %img %sampler %res1 = OpImageQuerySize %u32vec2 %simg )"; @@ -10647,6 +10647,231 @@ TEST_F(ValidateImage, ImageMSArray_ArrayedTypeDoesNotRequireCapability) { EXPECT_THAT(getDiagnosticString(), Eq("")); } +TEST_F(ValidateImage, SampledImageTypeDepthMismatch) { + const std::string code = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %im_var DescriptorSet 0 +OpDecorate %im_var Binding 0 +OpDecorate %s_var DescriptorSet 1 +OpDecorate %s_var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%im1_ty = OpTypeImage %float 2D 0 0 0 1 Unknown +%im2_ty = OpTypeImage %float 2D 1 0 0 1 Unknown +%s_ty = OpTypeSampler +%s_im_ty = OpTypeSampledImage %im2_ty +%ptr_im = OpTypePointer UniformConstant %im1_ty +%ptr_s = OpTypePointer UniformConstant %s_ty +%im_var = OpVariable %ptr_im UniformConstant +%s_var = OpVariable %ptr_s UniformConstant +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%im_ld = OpLoad %im1_ty %im_var +%s_ld = OpLoad %s_ty %s_var +%sampled_image = OpSampledImage %s_im_ty %im_ld %s_ld +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(env)); +} + +TEST_F(ValidateImage, SampledImageTypeArrayedMismatch) { + const std::string code = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %im_var DescriptorSet 0 +OpDecorate %im_var Binding 0 +OpDecorate %s_var DescriptorSet 1 +OpDecorate %s_var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%im1_ty = OpTypeImage %float 2D 0 0 0 1 Unknown +%im2_ty = OpTypeImage %float 2D 0 1 0 1 Unknown +%s_ty = OpTypeSampler +%s_im_ty = OpTypeSampledImage %im2_ty +%ptr_im = OpTypePointer UniformConstant %im1_ty +%ptr_s = OpTypePointer UniformConstant %s_ty +%im_var = OpVariable %ptr_im UniformConstant +%s_var = OpVariable %ptr_s UniformConstant +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%im_ld = OpLoad %im1_ty %im_var +%s_ld = OpLoad %s_ty %s_var +%sampled_image = OpSampledImage %s_im_ty %im_ld %s_ld +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Image operands must match result image operands except for depth")); +} + +TEST_F(ValidateImage, SampledImageTypeMultisampledMismatch) { + const std::string code = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %im_var DescriptorSet 0 +OpDecorate %im_var Binding 0 +OpDecorate %s_var DescriptorSet 1 +OpDecorate %s_var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%im1_ty = OpTypeImage %float 2D 0 0 0 1 Unknown +%im2_ty = OpTypeImage %float 2D 0 0 1 1 Unknown +%s_ty = OpTypeSampler +%s_im_ty = OpTypeSampledImage %im2_ty +%ptr_im = OpTypePointer UniformConstant %im1_ty +%ptr_s = OpTypePointer UniformConstant %s_ty +%im_var = OpVariable %ptr_im UniformConstant +%s_var = OpVariable %ptr_s UniformConstant +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%im_ld = OpLoad %im1_ty %im_var +%s_ld = OpLoad %s_ty %s_var +%sampled_image = OpSampledImage %s_im_ty %im_ld %s_ld +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_VULKAN_1_0; + CompileSuccessfully(code, env); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Image operands must match result image operands except for depth")); +} + +TEST_F(ValidateImage, SampledImageTypeSampledMismatch) { + const std::string code = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %im_var DescriptorSet 0 +OpDecorate %im_var Binding 0 +OpDecorate %s_var DescriptorSet 1 +OpDecorate %s_var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%im1_ty = OpTypeImage %float 2D 0 0 0 1 Unknown +%im2_ty = OpTypeImage %float 2D 0 0 0 0 Unknown +%s_ty = OpTypeSampler +%s_im_ty = OpTypeSampledImage %im2_ty +%ptr_im = OpTypePointer UniformConstant %im1_ty +%ptr_s = OpTypePointer UniformConstant %s_ty +%im_var = OpVariable %ptr_im UniformConstant +%s_var = OpVariable %ptr_s UniformConstant +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%im_ld = OpLoad %im1_ty %im_var +%s_ld = OpLoad %s_ty %s_var +%sampled_image = OpSampledImage %s_im_ty %im_ld %s_ld +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_UNIVERSAL_1_0; + CompileSuccessfully(code, env); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Image operands must match result image operands except for depth")); +} + +TEST_F(ValidateImage, SampledImageTypeFormatMismatch) { + const std::string code = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %im_var DescriptorSet 0 +OpDecorate %im_var Binding 0 +OpDecorate %s_var DescriptorSet 1 +OpDecorate %s_var Binding 0 +%void = OpTypeVoid +%float = OpTypeFloat 32 +%im1_ty = OpTypeImage %float 2D 0 0 0 1 Unknown +%im2_ty = OpTypeImage %float 2D 0 0 0 1 R32f +%s_ty = OpTypeSampler +%s_im_ty = OpTypeSampledImage %im2_ty +%ptr_im = OpTypePointer UniformConstant %im1_ty +%ptr_s = OpTypePointer UniformConstant %s_ty +%im_var = OpVariable %ptr_im UniformConstant +%s_var = OpVariable %ptr_s UniformConstant +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%im_ld = OpLoad %im1_ty %im_var +%s_ld = OpLoad %s_ty %s_var +%sampled_image = OpSampledImage %s_im_ty %im_ld %s_ld +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_UNIVERSAL_1_0; + CompileSuccessfully(code, env); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Image operands must match result image operands except for depth")); +} + +TEST_F(ValidateImage, SampledImageTypeAccessQualifierMismatch) { + const std::string code = R"( +OpCapability Kernel +OpCapability Linkage +OpMemoryModel Logical OpenCL +%void = OpTypeVoid +%float = OpTypeFloat 32 +%im1_ty = OpTypeImage %float 2D 0 0 0 0 Unknown ReadWrite +%im2_ty = OpTypeImage %float 2D 0 0 0 0 Unknown ReadOnly +%s_ty = OpTypeSampler +%s_im_ty = OpTypeSampledImage %im2_ty +%ptr_im = OpTypePointer UniformConstant %im1_ty +%ptr_s = OpTypePointer UniformConstant %s_ty +%im_var = OpVariable %ptr_im UniformConstant +%s_var = OpVariable %ptr_s UniformConstant +%void_fn = OpTypeFunction %void +%main = OpFunction %void None %void_fn +%entry = OpLabel +%im_ld = OpLoad %im1_ty %im_var +%s_ld = OpLoad %s_ty %s_var +%sampled_image = OpSampledImage %s_im_ty %im_ld %s_ld +OpReturn +OpFunctionEnd +)"; + + const spv_target_env env = SPV_ENV_UNIVERSAL_1_0; + CompileSuccessfully(code, env); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(env)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Image operands must match result image operands except for depth")); +} + } // namespace } // namespace val } // namespace spvtools From 05be5b2466b67317caaaed0d5369fd7f99af05a8 Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Mon, 9 Sep 2024 16:05:32 -0400 Subject: [PATCH 510/523] Fix build.gn build. (#5791) --- BUILD.gn | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BUILD.gn b/BUILD.gn index 8648043afa..89fac745e1 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -793,6 +793,8 @@ static_library("spvtools_opt") { "source/opt/strip_debug_info_pass.h", "source/opt/strip_nonsemantic_info_pass.cpp", "source/opt/strip_nonsemantic_info_pass.h", + "source/opt/struct_packing_pass.cpp", + "source/opt/struct_packing_pass.h", "source/opt/struct_cfg_analysis.cpp", "source/opt/struct_cfg_analysis.h", "source/opt/switch_descriptorset_pass.cpp", From 6209efd77c1ac5cac9548ffca159d6fe804dc533 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Mon, 9 Sep 2024 18:47:40 -0400 Subject: [PATCH 511/523] Update SPIRV-Headers (#5793) * Fix capability trimming tests to use KHR names for compute derivatives --- DEPS | 2 +- test/opt/trim_capabilities_pass_test.cpp | 28 ++++++++++++------------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/DEPS b/DEPS index 4534976f54..e38043421c 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 're2_revision': '6dcd83d60f7944926bfd308cc13979fc53dd69ca', - 'spirv_headers_revision': 'efb6b4099ddb8fa60f62956dee592c4b94ec6a49', + 'spirv_headers_revision': '2a9b6f951c7d6b04b6c21fe1bf3f475b68b84801', } deps = { diff --git a/test/opt/trim_capabilities_pass_test.cpp b/test/opt/trim_capabilities_pass_test.cpp index 9b2d767d59..b155f2e311 100644 --- a/test/opt/trim_capabilities_pass_test.cpp +++ b/test/opt/trim_capabilities_pass_test.cpp @@ -63,8 +63,8 @@ TEST_F(TrimCapabilitiesPassTest, CheckKnownAliasTransformations) { OpCapability DotProductInput4x8BitKHR OpCapability DotProductInput4x8BitPackedKHR OpCapability DotProductKHR - OpCapability ComputeDerivativeGroupQuadsNV - OpCapability ComputeDerivativeGroupLinearNV + OpCapability ComputeDerivativeGroupQuadsKHR + OpCapability ComputeDerivativeGroupLinearKHR ; CHECK: OpCapability Linkage ; CHECK-NOT: OpCapability StorageUniform16 ; CHECK-NOT: OpCapability StorageUniformBufferBlock16 @@ -91,8 +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-NOT: OpCapability ComputeDerivativeGroupQuadsKHR +; CHECK-NOT: OpCapability ComputeDerivativeGroupLinearKHR ; CHECK: OpCapability UniformAndStorageBuffer16BitAccess ; CHECK: OpCapability StorageBuffer16BitAccess ; CHECK: OpCapability ShaderViewportIndexLayerEXT @@ -2136,11 +2136,11 @@ TEST_F(TrimCapabilitiesPassTest, Float64_RemainsWhenUsed) { 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 ComputeDerivativeGroupQuadsKHR + OpCapability ComputeDerivativeGroupLinearKHR +; CHECK-NOT: OpCapability ComputeDerivativeGroupLinearKHR +; CHECK: OpCapability ComputeDerivativeGroupQuadsKHR +; CHECK-NOT: OpCapability ComputeDerivativeGroupLinearKHR OpCapability Shader ; CHECK: OpExtension "SPV_NV_compute_shader_derivatives" OpExtension "SPV_NV_compute_shader_derivatives" @@ -2162,11 +2162,11 @@ TEST_F(TrimCapabilitiesPassTest, 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 ComputeDerivativeGroupLinearKHR + OpCapability ComputeDerivativeGroupQuadsKHR +; CHECK-NOT: OpCapability ComputeDerivativeGroupQuadsKHR +; CHECK: OpCapability ComputeDerivativeGroupLinearKHR +; CHECK-NOT: OpCapability ComputeDerivativeGroupQuadsKHR OpCapability Shader ; CHECK: OpExtension "SPV_NV_compute_shader_derivatives" OpExtension "SPV_NV_compute_shader_derivatives" From d160e170d74ff45cb2a88dfb365bdfd896016f7c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 23:14:26 -0400 Subject: [PATCH 512/523] Roll external/abseil_cpp/ f7f316824..67d126083 (3 commits) (#5787) https://github.com/abseil/abseil-cpp/compare/f7f316824dfe...67d126083c15 Created with: roll-dep external/abseil_cpp Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index e38043421c..cce5b72349 100644 --- a/DEPS +++ b/DEPS @@ -3,7 +3,7 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': 'f7f316824dfe2c0c0d5e9679970004fd6ac93055', + 'abseil_revision': '67d126083c1584dd7dc584d700f853afaec365ca', 'effcee_revision': '2c97e5689ed8d7ab6ae5820f884f03a601ae124b', From 380275eacdb929f5adc6cc145fad5a60ca9a4b42 Mon Sep 17 00:00:00 2001 From: alan-baker Date: Wed, 11 Sep 2024 14:50:30 -0400 Subject: [PATCH 513/523] Do not check structurally unreachable continue target predecessors (#5800) Fixes #5784 * Rules only apply to structurally reachable blocks --- source/val/validate_cfg.cpp | 3 +++ test/val/val_cfg_test.cpp | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/source/val/validate_cfg.cpp b/source/val/validate_cfg.cpp index d401a2e7b7..77e4f4f2fd 100644 --- a/source/val/validate_cfg.cpp +++ b/source/val/validate_cfg.cpp @@ -839,6 +839,9 @@ spv_result_t StructuredControlFlowChecks( const auto* continue_target = next_inst.block(); if (header->id() != continue_id) { for (auto pred : *continue_target->predecessors()) { + if (!pred->structurally_reachable()) { + continue; + } // Ignore back-edges from within the continue construct. bool is_back_edge = false; for (auto back_edge : back_edges) { diff --git a/test/val/val_cfg_test.cpp b/test/val/val_cfg_test.cpp index 233aee645d..d3b5e90209 100644 --- a/test/val/val_cfg_test.cpp +++ b/test/val/val_cfg_test.cpp @@ -5118,6 +5118,43 @@ OpFunctionEnd EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); } +TEST_F(ValidateCFG, StructurallyUnreachableContinuePredecessor) { + const std::string text = R"( + OpCapability Shader + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %main "main" + OpExecutionMode %main OriginUpperLeft + OpSource ESSL 310 + OpName %main "main" + %void = OpTypeVoid + %3 = OpTypeFunction %void + %int = OpTypeInt 32 1 + %int_1 = OpConstant %int 1 + %int_n7 = OpConstant %int -7 + %bool = OpTypeBool + %main = OpFunction %void None %3 + %8 = OpLabel + OpBranch %9 + %9 = OpLabel + %10 = OpPhi %int %int_1 %8 %int_n7 %15 + %12 = OpSGreaterThan %bool %10 %int_n7 + OpLoopMerge %13 %15 None + OpBranchConditional %12 %14 %13 + %14 = OpLabel + OpBranch %15 + %15 = OpLabel + OpBranch %9 + %17 = OpLabel + OpBranch %15 + %13 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(text); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + } // namespace } // namespace val } // namespace spvtools From 37d2fcb485bf3fcadb18ef90aab6f283dcc4be72 Mon Sep 17 00:00:00 2001 From: cheneym2 Date: Thu, 12 Sep 2024 07:21:12 -0400 Subject: [PATCH 514/523] spirv-opt: fix crash in function declarations (#5796) * spirv-opt: fix crash in function declarations Function declarations contain no blocks, so bail before segfaulting in function optimization passes that operate on blocks. Fixes #5795 * spirv-opt: add test for optimizing declarations --- source/opt/aggressive_dead_code_elim_pass.cpp | 1 + source/opt/mem_pass.cpp | 1 + test/opt/aggressive_dead_code_elim_test.cpp | 36 +++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/source/opt/aggressive_dead_code_elim_pass.cpp b/source/opt/aggressive_dead_code_elim_pass.cpp index 7eb158d5e6..6e86c378b9 100644 --- a/source/opt/aggressive_dead_code_elim_pass.cpp +++ b/source/opt/aggressive_dead_code_elim_pass.cpp @@ -267,6 +267,7 @@ void AggressiveDCEPass::AddBreaksAndContinuesToWorklist( } bool AggressiveDCEPass::AggressiveDCE(Function* func) { + if (func->IsDeclaration()) return false; std::list structured_order; cfg()->ComputeStructuredOrder(func, &*func->begin(), &structured_order); live_local_vars_.clear(); diff --git a/source/opt/mem_pass.cpp b/source/opt/mem_pass.cpp index 80ec8da18e..65f45ec3b8 100644 --- a/source/opt/mem_pass.cpp +++ b/source/opt/mem_pass.cpp @@ -415,6 +415,7 @@ void MemPass::RemoveBlock(Function::iterator* bi) { } bool MemPass::RemoveUnreachableBlocks(Function* func) { + if (func->IsDeclaration()) return false; bool modified = false; // Mark reachable all blocks reachable from the function's entry block. diff --git a/test/opt/aggressive_dead_code_elim_test.cpp b/test/opt/aggressive_dead_code_elim_test.cpp index d837099fe9..a4353b1b88 100644 --- a/test/opt/aggressive_dead_code_elim_test.cpp +++ b/test/opt/aggressive_dead_code_elim_test.cpp @@ -8070,6 +8070,42 @@ TEST_F(AggressiveDCETest, StoringAPointer) { SinglePassRunAndMatch(text, true); } +TEST_F(AggressiveDCETest, FunctionDeclaration) { + // Ensure the optimizer can handle traversing over a function declaration + // 'myfunc' which has no blocks + + const std::string text = R"(OpCapability Linkage +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %PSMain "main" %entryPointParam_PSMain +OpExecutionMode %PSMain OriginUpperLeft +OpSource Slang 1 +OpName %myfunc "myfunc" +OpName %entryPointParam_PSMain "entryPointParam_PSMain" +OpName %PSMain "PSMain" +OpDecorate %myfunc LinkageAttributes "_S6myfuncp0pv4f" Import +OpDecorate %entryPointParam_PSMain Location 0 +%void = OpTypeVoid +%5 = OpTypeFunction %void +%float = OpTypeFloat 32 +%v4float = OpTypeVector %float 4 +%8 = OpTypeFunction %v4float +%_ptr_Output_v4float = OpTypePointer Output %v4float +%entryPointParam_PSMain = OpVariable %_ptr_Output_v4float Output +%myfunc = OpFunction %v4float None %8 +OpFunctionEnd +%PSMain = OpFunction %void None %5 +%10 = OpLabel +%11 = OpFunctionCall %v4float %myfunc +OpStore %entryPointParam_PSMain %11 +OpReturn +OpFunctionEnd +)"; + + SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck(text, text, true, true); +} + } // namespace } // namespace opt } // namespace spvtools From 7c9210cc1d82e8bf0ca969a88db069c83d838398 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 15:04:34 +0000 Subject: [PATCH 515/523] Roll external/abseil_cpp/ 67d126083..1d4466e8d (2 commits) (#5801) https://github.com/abseil/abseil-cpp/compare/67d126083c15...1d4466e8d3fd Created with: roll-dep external/abseil_cpp Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index cce5b72349..2b2b80e5c9 100644 --- a/DEPS +++ b/DEPS @@ -3,7 +3,7 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': '67d126083c1584dd7dc584d700f853afaec365ca', + 'abseil_revision': '1d4466e8d3fdc153ad053f2ffd18f898e516f8f0', 'effcee_revision': '2c97e5689ed8d7ab6ae5820f884f03a601ae124b', From 4451f6ab13dda98bf255a7cd7b4d120132dc0dfd Mon Sep 17 00:00:00 2001 From: David Neto Date: Thu, 12 Sep 2024 14:30:18 -0700 Subject: [PATCH 516/523] Implement to_string(uint32_t) without using the locale (#5805) Using the locale takes a mutex deep in the C++ library. Avoid this on hot compilation paths, e.g. in the validator. Fixed: #5802 --- Android.mk | 1 + BUILD.gn | 3 ++ source/CMakeLists.txt | 2 ++ source/name_mapper.cpp | 15 ++------- source/opt/inst_debug_printf_pass.cpp | 3 +- source/to_string.cpp | 44 +++++++++++++++++++++++++++ source/to_string.h | 29 ++++++++++++++++++ test/CMakeLists.txt | 1 + test/to_string_test.cpp | 28 +++++++++++++++++ 9 files changed, 113 insertions(+), 13 deletions(-) create mode 100644 source/to_string.cpp create mode 100644 source/to_string.h create mode 100644 test/to_string_test.cpp diff --git a/Android.mk b/Android.mk index c85a595c52..04d21c5578 100644 --- a/Android.mk +++ b/Android.mk @@ -27,6 +27,7 @@ SPVTOOLS_SRC_FILES := \ source/table.cpp \ source/text.cpp \ source/text_handler.cpp \ + source/to_string.cpp \ source/util/bit_vector.cpp \ source/util/parse_number.cpp \ source/util/string_utils.cpp \ diff --git a/BUILD.gn b/BUILD.gn index 89fac745e1..a6e885806e 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -475,6 +475,8 @@ static_library("spvtools") { "source/text.h", "source/text_handler.cpp", "source/text_handler.h", + "source/to_string.cpp", + "source/to_string.h", "source/util/bit_vector.cpp", "source/util/bit_vector.h", "source/util/bitutils.h", @@ -1416,6 +1418,7 @@ if (build_with_chromium && spvtools_build_executables) { "test/text_to_binary.type_declaration_test.cpp", "test/text_to_binary_test.cpp", "test/text_word_get_test.cpp", + "test/to_string_test.cpp", "test/unit_spirv.cpp", "test/unit_spirv.h", ] diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index d0454c6c70..cb6026ad50 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -266,6 +266,7 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/table.h ${CMAKE_CURRENT_SOURCE_DIR}/text.h ${CMAKE_CURRENT_SOURCE_DIR}/text_handler.h + ${CMAKE_CURRENT_SOURCE_DIR}/to_string.h ${CMAKE_CURRENT_SOURCE_DIR}/val/validate.h ${CMAKE_CURRENT_SOURCE_DIR}/util/bit_vector.cpp @@ -294,6 +295,7 @@ set(SPIRV_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/table.cpp ${CMAKE_CURRENT_SOURCE_DIR}/text.cpp ${CMAKE_CURRENT_SOURCE_DIR}/text_handler.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/to_string.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_adjacency.cpp ${CMAKE_CURRENT_SOURCE_DIR}/val/validate_annotation.cpp diff --git a/source/name_mapper.cpp b/source/name_mapper.cpp index b0debde9d2..7e5f091740 100644 --- a/source/name_mapper.cpp +++ b/source/name_mapper.cpp @@ -25,24 +25,15 @@ #include "source/binary.h" #include "source/latest_version_spirv_header.h" #include "source/parsed_operand.h" +#include "source/to_string.h" #include "spirv-tools/libspirv.h" namespace spvtools { -namespace { -// Converts a uint32_t to its string decimal representation. -std::string to_string(uint32_t id) { - // Use stringstream, since some versions of Android compilers lack - // std::to_string. - std::stringstream os; - os << id; - return os.str(); +NameMapper GetTrivialNameMapper() { + return [](uint32_t i) { return spvtools::to_string(i); }; } -} // anonymous namespace - -NameMapper GetTrivialNameMapper() { return to_string; } - FriendlyNameMapper::FriendlyNameMapper(const spv_const_context context, const uint32_t* code, const size_t wordCount) diff --git a/source/opt/inst_debug_printf_pass.cpp b/source/opt/inst_debug_printf_pass.cpp index abd25e9396..916db7ce2e 100644 --- a/source/opt/inst_debug_printf_pass.cpp +++ b/source/opt/inst_debug_printf_pass.cpp @@ -17,6 +17,7 @@ #include "inst_debug_printf_pass.h" #include "source/spirv_constant.h" +#include "source/to_string.h" #include "source/util/string_utils.h" #include "spirv/unified1/NonSemanticDebugPrintf.h" @@ -396,7 +397,7 @@ uint32_t InstDebugPrintfPass::GetStreamWriteFunctionId(uint32_t param_cnt) { context()->AddFunction(std::move(output_func)); std::string name("stream_write_"); - name += std::to_string(param_cnt); + name += spvtools::to_string(param_cnt); context()->AddDebug2Inst( NewGlobalName(param2output_func_id_[param_cnt], name)); diff --git a/source/to_string.cpp b/source/to_string.cpp new file mode 100644 index 0000000000..b707070b3f --- /dev/null +++ b/source/to_string.cpp @@ -0,0 +1,44 @@ +// Copyright (c) 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/to_string.h" + +#include + +namespace spvtools { + +std::string to_string(uint32_t n) { + // This implementation avoids using standard library features that access + // the locale. Using the locale requires taking a mutex which causes + // annoying serialization. + + constexpr int max_digits = 10; // max uint has 10 digits + // Contains the resulting digits, with least significant digit in the last + // entry. + char buf[max_digits]; + int write_index = max_digits - 1; + if (n == 0) { + buf[write_index] = '0'; + } else { + while (n > 0) { + int units = n % 10; + buf[write_index--] = "0123456789"[units]; + n = (n - units) / 10; + } + write_index++; + } + assert(write_index >= 0); + return std::string(buf + write_index, max_digits - write_index); +} +} // namespace spvtools diff --git a/source/to_string.h b/source/to_string.h new file mode 100644 index 0000000000..83702f92ad --- /dev/null +++ b/source/to_string.h @@ -0,0 +1,29 @@ +// Copyright (c) 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_TO_STRING_H_ +#define SOURCE_TO_STRING_H_ + +#include +#include + +namespace spvtools { + +// Returns the decimal representation of a number as a string, +// without using the locale. +std::string to_string(uint32_t n); + +} // namespace spvtools + +#endif // SOURCE_TO_STRING_H_ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 40c64f8066..76940ce1f2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -151,6 +151,7 @@ set(TEST_SOURCES text_to_binary.subgroup_dispatch_test.cpp text_to_binary.reserved_sampling_test.cpp text_word_get_test.cpp + to_string_test.cpp unit_spirv.cpp ) diff --git a/test/to_string_test.cpp b/test/to_string_test.cpp new file mode 100644 index 0000000000..5973318e53 --- /dev/null +++ b/test/to_string_test.cpp @@ -0,0 +1,28 @@ +// Copyright (c) 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/to_string.h" + +#include "gmock/gmock.h" + +namespace { + +TEST(ToString, Uint32) { + EXPECT_EQ(spvtools::to_string(0u), "0"); + EXPECT_EQ(spvtools::to_string(1u), "1"); + EXPECT_EQ(spvtools::to_string(1234567890u), "1234567890"); + EXPECT_EQ(spvtools::to_string(0xffffffffu), "4294967295"); +} + +} // namespace From 4c2094ee9b9b8ceeb8038c5555fcefffc4a077b4 Mon Sep 17 00:00:00 2001 From: Nielsbishere Date: Sat, 14 Sep 2024 16:36:17 +0200 Subject: [PATCH 517/523] Made libspirv include relative to allow better portability (#5807) --- include/spirv-tools/libspirv.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/spirv-tools/libspirv.hpp b/include/spirv-tools/libspirv.hpp index 59ff82b17c..6a64e9362f 100644 --- a/include/spirv-tools/libspirv.hpp +++ b/include/spirv-tools/libspirv.hpp @@ -20,7 +20,7 @@ #include #include -#include "spirv-tools/libspirv.h" +#include "libspirv.h" namespace spvtools { From a2c9c2387e97ac47ec3b1f508dd1f9f354e023cc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 15 Sep 2024 12:57:18 +0000 Subject: [PATCH 518/523] Roll external/abseil_cpp/ 1d4466e8d..f7c22f52a (3 commits) (#5806) https://github.com/abseil/abseil-cpp/compare/1d4466e8d3fd...f7c22f52a748 Created with: roll-dep external/abseil_cpp Co-authored-by: GitHub Actions[bot] <> --- DEPS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DEPS b/DEPS index 2b2b80e5c9..44199fbd64 100644 --- a/DEPS +++ b/DEPS @@ -3,7 +3,7 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': '1d4466e8d3fdc153ad053f2ffd18f898e516f8f0', + 'abseil_revision': 'f7c22f52a748761b93c50a27b06afef000b26f95', 'effcee_revision': '2c97e5689ed8d7ab6ae5820f884f03a601ae124b', From d85446fd7eec314e50ed373bf91a7661653bc49a Mon Sep 17 00:00:00 2001 From: Steven Perron Date: Mon, 16 Sep 2024 10:11:22 -0400 Subject: [PATCH 519/523] [OPT] Fix generating debugLocalVariable from debugGlobalVariable (#5803) The code converting the global to local was generating an extra operand that was incorrect. Fixed the code, and added a unit test. Fixes #5776 --- source/opt/debug_info_manager.cpp | 20 +++++-- test/opt/debug_info_manager_test.cpp | 78 ++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/source/opt/debug_info_manager.cpp b/source/opt/debug_info_manager.cpp index 1e614c6ff3..24094b36ef 100644 --- a/source/opt/debug_info_manager.cpp +++ b/source/opt/debug_info_manager.cpp @@ -768,15 +768,29 @@ void DebugInfoManager::ConvertDebugGlobalToLocalVariable( local_var->opcode() == spv::Op::OpFunctionParameter); // Convert |dbg_global_var| to DebugLocalVariable + // All of the operands up to the scope operand are the same for the type + // instructions. The flag operand needs to move from operand + // kDebugGlobalVariableOperandFlagsIndex to + // kDebugLocalVariableOperandFlagsIndex. No other operands are needed to + // define the DebugLocalVariable. + + // Modify the opcode. dbg_global_var->SetInOperand(kExtInstInstructionInIdx, {CommonDebugInfoDebugLocalVariable}); + + // Move the flags operand. auto flags = dbg_global_var->GetSingleWordOperand( kDebugGlobalVariableOperandFlagsIndex); - for (uint32_t i = dbg_global_var->NumInOperands() - 1; - i >= kDebugLocalVariableOperandFlagsIndex; --i) { + dbg_global_var->SetOperand(kDebugLocalVariableOperandFlagsIndex, {flags}); + + // Remove the extra operands. Starting at the end to avoid copying too much + // data. + for (uint32_t i = dbg_global_var->NumOperands() - 1; + i > kDebugLocalVariableOperandFlagsIndex; --i) { dbg_global_var->RemoveOperand(i); } - dbg_global_var->SetOperand(kDebugLocalVariableOperandFlagsIndex, {flags}); + + // Update the def-use manager. context()->ForgetUses(dbg_global_var); context()->AnalyzeUses(dbg_global_var); diff --git a/test/opt/debug_info_manager_test.cpp b/test/opt/debug_info_manager_test.cpp index 3df26a9765..9c75728030 100644 --- a/test/opt/debug_info_manager_test.cpp +++ b/test/opt/debug_info_manager_test.cpp @@ -799,6 +799,84 @@ void main(float in_var_color : COLOR) { 7); } +TEST(DebugInfoManager, ConvertGlobalToLocal) { + const std::string text = R"( + OpCapability Shader + %1 = OpExtInstImport "NonSemantic.Shader.DebugInfo.100" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "PSMain" %3 + OpExecutionMode %2 OriginUpperLeft + %4 = OpString "C:\\local\\Temp\\2528091a-6811-4e62-9ed5-02f1547c2016.hlsl" + %5 = OpString "float" + %6 = OpString "Pi" + %float = OpTypeFloat 32 +%float_3_1415 = OpConstant %float 3.1415 + %uint = OpTypeInt 32 0 + %uint_32 = OpConstant %uint 32 +%_ptr_Private_float = OpTypePointer Private %float +%_ptr_Function_float = OpTypePointer Function %float + %void = OpTypeVoid + %uint_3 = OpConstant %uint 3 + %uint_0 = OpConstant %uint 0 + %uint_4 = OpConstant %uint 4 + %uint_1 = OpConstant %uint 1 + %uint_5 = OpConstant %uint 5 + %uint_8 = OpConstant %uint 8 + %uint_6 = OpConstant %uint 6 + %uint_20 = OpConstant %uint 20 + %25 = OpTypeFunction %void + %uint_11 = OpConstant %uint 11 + %3 = OpVariable %_ptr_Private_float Private + %8 = OpExtInst %void %1 DebugTypeBasic %5 %uint_32 %uint_3 %uint_0 + %12 = OpExtInst %void %1 DebugSource %4 + %13 = OpExtInst %void %1 DebugCompilationUnit %uint_1 %uint_4 %12 %uint_5 + %17 = OpExtInst %void %1 DebugGlobalVariable %6 %8 %12 %uint_6 %uint_20 %13 %6 %3 %uint_8 + %2 = OpFunction %void None %25 + %27 = OpLabel + %29 = OpVariable %_ptr_Function_float Function + OpStore %3 %float_3_1415 + %28 = OpExtInst %void %1 DebugLine %12 %uint_11 %uint_11 %uint_1 %uint_1 + OpReturn + OpFunctionEnd + )"; + + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + auto* def_use_mgr = context->get_def_use_mgr(); + auto* dbg_var = def_use_mgr->GetDef(17); + EXPECT_EQ(dbg_var->GetCommonDebugOpcode(), + OpenCLDebugInfo100DebugGlobalVariable); + EXPECT_EQ(dbg_var->NumInOperands(), 11); + + std::vector originalOperands; + for (uint32_t i = 0; i < dbg_var->NumInOperands(); ++i) { + originalOperands.emplace_back(dbg_var->GetInOperand((i))); + } + + auto* local_var = def_use_mgr->GetDef(29); + auto* dbg_info_mgr = context->get_debug_info_mgr(); + dbg_info_mgr->ConvertDebugGlobalToLocalVariable(dbg_var, local_var); + + EXPECT_EQ(dbg_var->NumInOperands(), 9); + + // This checks that the first two inoperands are correct. + EXPECT_EQ(dbg_var->GetCommonDebugOpcode(), + OpenCLDebugInfo100DebugLocalVariable); + + // Then next 6 operands should be the same as the original instruction. + EXPECT_EQ(dbg_var->GetInOperand(2), originalOperands[2]); + EXPECT_EQ(dbg_var->GetInOperand(3), originalOperands[3]); + EXPECT_EQ(dbg_var->GetInOperand(4), originalOperands[4]); + EXPECT_EQ(dbg_var->GetInOperand(5), originalOperands[5]); + EXPECT_EQ(dbg_var->GetInOperand(6), originalOperands[6]); + EXPECT_EQ(dbg_var->GetInOperand(7), originalOperands[7]); + + // The flags operand should have shifted because operand 8 and 9 in the global + // instruction are not relevant. + EXPECT_EQ(dbg_var->GetInOperand(8), originalOperands[10]); +} + } // namespace } // namespace analysis } // namespace opt From 04ad1e1ce39358064e1026adf8b5bb2e346290b1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 10:20:42 -0400 Subject: [PATCH 520/523] build(deps): bump github/codeql-action in the github-actions group (#5808) Bumps the github-actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action). Updates `github/codeql-action` from 3.26.6 to 3.26.7 - [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/4dd16135b69a43b6c8efb853346f8437d92d3c93...8214744c546c1e5c8f03dde8fab3a7353211988d) --- 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 5861285cf1..7424d86489 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@4dd16135b69a43b6c8efb853346f8437d92d3c93 # v3.26.6 + uses: github/codeql-action/upload-sarif@8214744c546c1e5c8f03dde8fab3a7353211988d # v3.26.7 with: sarif_file: results.sarif From 20788a4c5fd3cd22b5b1a00c8f53767f115fa400 Mon Sep 17 00:00:00 2001 From: Ben Ashbaugh Date: Tue, 17 Sep 2024 09:31:29 -0700 Subject: [PATCH 521/523] add support for SPV_INTEL_global_variable_host_access (#5786) --- source/binary.cpp | 1 + test/binary_to_text_test.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/source/binary.cpp b/source/binary.cpp index 19098aa130..772e98c0a2 100644 --- a/source/binary.cpp +++ b/source/binary.cpp @@ -673,6 +673,7 @@ spv_result_t Parser::parseOperand(size_t inst_offset, case SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT: case SPV_OPERAND_TYPE_FPENCODING: case SPV_OPERAND_TYPE_OPTIONAL_FPENCODING: + case SPV_OPERAND_TYPE_HOST_ACCESS_QUALIFIER: case SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL: case SPV_OPERAND_TYPE_STORE_CACHE_CONTROL: case SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS: { diff --git a/test/binary_to_text_test.cpp b/test/binary_to_text_test.cpp index 4630a985f8..ecf4d1e092 100644 --- a/test/binary_to_text_test.cpp +++ b/test/binary_to_text_test.cpp @@ -418,6 +418,16 @@ INSTANTIATE_TEST_SUITE_P( "OpDecorate %1 CacheControlStoreINTEL 3 StreamingINTEL\n", }))); +INSTANTIATE_TEST_SUITE_P( + HostAccessINTEL, RoundTripInstructionsTest, + Combine(::testing::Values(SPV_ENV_UNIVERSAL_1_0), + ::testing::ValuesIn(std::vector{ + "OpDecorate %1 HostAccessINTEL NoneINTEL \"none\"\n", + "OpDecorate %1 HostAccessINTEL ReadINTEL \"read\"\n", + "OpDecorate %1 HostAccessINTEL WriteINTEL \"write\"\n", + "OpDecorate %1 HostAccessINTEL ReadWriteINTEL \"readwrite\"\n", + }))); + using MaskSorting = TextToBinaryTest; TEST_F(MaskSorting, MasksAreSortedFromLSBToMSB) { From 04bdb6c7c9df5fd76a0f4aae1f669c92ea1fa6e8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 18 Sep 2024 10:53:02 +0000 Subject: [PATCH 522/523] roll deps (#5809) * Roll external/googletest/ 0953a17a4..6dae7eb4a (1 commit) https://github.com/google/googletest/compare/0953a17a4281...6dae7eb4a5c3 Created with: roll-dep external/googletest * Roll external/abseil_cpp/ f7c22f52a..0df567400 (10 commits) https://github.com/abseil/abseil-cpp/compare/f7c22f52a748...0df56740031c Created with: roll-dep external/abseil_cpp --------- Co-authored-by: GitHub Actions[bot] <> --- DEPS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 44199fbd64..06460ca1a5 100644 --- a/DEPS +++ b/DEPS @@ -3,11 +3,11 @@ use_relative_paths = True vars = { 'github': 'https://github.com', - 'abseil_revision': 'f7c22f52a748761b93c50a27b06afef000b26f95', + 'abseil_revision': '0df56740031c3882c3b3f93bef15698a30f3a1f6', 'effcee_revision': '2c97e5689ed8d7ab6ae5820f884f03a601ae124b', - 'googletest_revision': '0953a17a4281fc26831da647ad3fcd5e21e6473b', + 'googletest_revision': '6dae7eb4a5c3a169f3e298392bff4680224aa94a', # Use protobufs before they gained the dependency on abseil 'protobuf_revision': 'v21.12', From 6dcc7e350a0b9871a825414d42329e44b0eb8109 Mon Sep 17 00:00:00 2001 From: Cassandra Beckley Date: Thu, 19 Sep 2024 12:28:18 -0700 Subject: [PATCH 523/523] Prepare release v2024.4 (#5811) --- CHANGES | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGES b/CHANGES index 36a2290939..c671ceb03c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,19 @@ Revision history for SPIRV-Tools +v2024.4 2024-09-19 + - General + - Add FPEncoding operand type. (#5726) + - Support SPV_KHR_untyped_pointers (#5736) + - add support for SPV_INTEL_global_variable_host_access (#5786) + - Optimizer + - Add knowledge of cooperative matrices (#5720) + - Add struct-packing pass and unit test. (#5778) + - Validator + - Validate presence of Stride operand to OpCooperativeMatrix{Load,Store}KHR (#5777) + - Update sampled image validation (#5789) + - Linker + - allow linking functions with different pointer arguments (#5534) + v2024.3 2024-06-20 - General - Optimizer