diff --git a/3rdparty/spirv-tools/README.md b/3rdparty/spirv-tools/README.md index a9b70c1d5..377d9731a 100644 --- a/3rdparty/spirv-tools/README.md +++ b/3rdparty/spirv-tools/README.md @@ -47,7 +47,7 @@ version. An API call reports the software version as a C-style string. * Support for SPIR-V 1.0, 1.1, 1.2, and 1.3 * Based on SPIR-V syntax described by JSON grammar files in the - [SPIRV-Headers](spirv-headers) repository. + [SPIRV-Headers](https://github.com/KhronosGroup/SPIRV-Headers) repository. * Support for extended instruction sets: * GLSL std450 version 1.0 Rev 3 * OpenCL version 1.0 Rev 2 diff --git a/3rdparty/spirv-tools/examples/cpp-interface/main.cpp b/3rdparty/spirv-tools/examples/cpp-interface/main.cpp index c5354b8bd..a1e22c736 100644 --- a/3rdparty/spirv-tools/examples/cpp-interface/main.cpp +++ b/3rdparty/spirv-tools/examples/cpp-interface/main.cpp @@ -28,6 +28,7 @@ int main() { const std::string source = + " OpCapability Linkage " " OpCapability Shader " " OpMemoryModel Logical GLSL450 " " OpSource GLSL 450 " @@ -36,8 +37,8 @@ int main() { " %spec = OpSpecConstant %int 0 " "%const = OpConstant %int 42"; - spvtools::SpirvTools core(SPV_ENV_VULKAN_1_0); - spvtools::Optimizer opt(SPV_ENV_VULKAN_1_0); + spvtools::SpirvTools core(SPV_ENV_UNIVERSAL_1_3); + spvtools::Optimizer opt(SPV_ENV_UNIVERSAL_1_3); auto print_msg_to_stderr = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) { diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index 6a12433c7..70e65484f 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2019.3-dev", "SPIRV-Tools v2019.3-dev v2019.1-147-g7aad9653" +"v2019.3-dev", "SPIRV-Tools v2019.3-dev v2019.1-154-g64faf6d9" diff --git a/3rdparty/spirv-tools/source/opt/decompose_initialized_variables_pass.cpp b/3rdparty/spirv-tools/source/opt/decompose_initialized_variables_pass.cpp index b2471cad2..875bf7e85 100644 --- a/3rdparty/spirv-tools/source/opt/decompose_initialized_variables_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/decompose_initialized_variables_pass.cpp @@ -34,43 +34,78 @@ bool HasInitializer(Instruction* inst) { Pass::Status DecomposeInitializedVariablesPass::Process() { auto* module = context()->module(); - bool changed = false; + std::unordered_set changed; - // TODO(zoddicus): Handle 'Output' variables - // TODO(zoddicus): Handle 'Private' variables + std::vector> global_stores; + for (auto iter = module->types_values_begin(); + iter != module->types_values_end(); ++iter) { + Instruction* inst = &(*iter); + if (!HasInitializer(inst)) continue; + + auto var_id = inst->result_id(); + auto val_id = inst->GetOperand(3).words[0]; + global_stores.push_back(std::make_tuple(var_id, val_id)); + iter->RemoveOperand(3); + changed.insert(&*iter); + } + + std::unordered_set entry_ids; + for (auto entry = module->entry_points().begin(); + entry != module->entry_points().end(); ++entry) { + entry_ids.insert(entry->GetSingleWordInOperand(1)); + } - // Handle 'Function' variables for (auto func = module->begin(); func != module->end(); ++func) { - auto block = func->entry().get(); - std::vector new_stores; - - auto last_var = block->begin(); - for (auto iter = block->begin(); - iter != block->end() && iter->opcode() == SpvOpVariable; ++iter) { - last_var = iter; + std::vector function_stores; + auto first_block = func->entry().get(); + inst_iterator insert_point = first_block->begin(); + for (auto iter = first_block->begin(); + iter != first_block->end() && iter->opcode() == SpvOpVariable; + ++iter) { + // For valid SPIRV-V, there is guaranteed to be at least one instruction + // after the OpVariable instructions. + insert_point = (*iter).NextNode(); Instruction* inst = &(*iter); if (!HasInitializer(inst)) continue; - changed = true; auto var_id = inst->result_id(); auto val_id = inst->GetOperand(3).words[0]; Instruction* store_inst = new Instruction( context(), SpvOpStore, 0, 0, {{SPV_OPERAND_TYPE_ID, {var_id}}, {SPV_OPERAND_TYPE_ID, {val_id}}}); - new_stores.push_back(store_inst); + function_stores.push_back(store_inst); iter->RemoveOperand(3); - get_def_use_mgr()->UpdateDefUse(&*iter); + changed.insert(&*iter); } - for (auto store = new_stores.begin(); store != new_stores.end(); ++store) { - context()->AnalyzeDefUse(*store); - context()->set_instr_block(*store, block); - (*store)->InsertAfter(&*last_var); - last_var = *store; + if (entry_ids.find(func->result_id()) != entry_ids.end()) { + for (auto store_ids : global_stores) { + uint32_t var_id; + uint32_t val_id; + std::tie(var_id, val_id) = store_ids; + auto* store_inst = new Instruction( + context(), SpvOpStore, 0, 0, + {{SPV_OPERAND_TYPE_ID, {var_id}}, {SPV_OPERAND_TYPE_ID, {val_id}}}); + context()->set_instr_block(store_inst, &*first_block); + first_block->AddInstruction(std::unique_ptr(store_inst)); + store_inst->InsertBefore(&*insert_point); + changed.insert(store_inst); + } + } + + for (auto store = function_stores.begin(); store != function_stores.end(); + ++store) { + context()->set_instr_block(*store, first_block); + (*store)->InsertBefore(&*insert_point); + changed.insert(*store); } } - return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange; + auto* def_use_mgr = get_def_use_mgr(); + for (auto* inst : changed) def_use_mgr->UpdateDefUse(inst); + + return !changed.empty() ? Pass::Status::SuccessWithChange + : Pass::Status::SuccessWithoutChange; } } // namespace opt diff --git a/3rdparty/spirv-tools/source/opt/scalar_replacement_pass.cpp b/3rdparty/spirv-tools/source/opt/scalar_replacement_pass.cpp index 2b2397d38..bfa859860 100644 --- a/3rdparty/spirv-tools/source/opt/scalar_replacement_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/scalar_replacement_pass.cpp @@ -225,12 +225,12 @@ bool ScalarReplacementPass::ReplaceAccessChain( // indexes) or a direct use of the replacement variable. uint32_t indexId = chain->GetSingleWordInOperand(1u); const Instruction* index = get_def_use_mgr()->GetDef(indexId); - size_t indexValue = GetConstantInteger(index); + uint64_t indexValue = GetConstantInteger(index); if (indexValue > replacements.size()) { // Out of bounds access, this is illegal IR. return false; } else { - const Instruction* var = replacements[indexValue]; + const Instruction* var = replacements[static_cast(indexValue)]; if (chain->NumInOperands() > 2) { // Replace input access chain with another access chain. BasicBlock::iterator chainIter(chain); @@ -457,16 +457,16 @@ void ScalarReplacementPass::GetOrCreateInitialValue(Instruction* source, } } -size_t ScalarReplacementPass::GetIntegerLiteral(const Operand& op) const { +uint64_t ScalarReplacementPass::GetIntegerLiteral(const Operand& op) const { assert(op.words.size() <= 2); - size_t len = 0; + uint64_t len = 0; for (uint32_t i = 0; i != op.words.size(); ++i) { len |= (op.words[i] << (32 * i)); } return len; } -size_t ScalarReplacementPass::GetConstantInteger( +uint64_t ScalarReplacementPass::GetConstantInteger( const Instruction* constant) const { assert(get_def_use_mgr()->GetDef(constant->type_id())->opcode() == SpvOpTypeInt); @@ -480,7 +480,7 @@ size_t ScalarReplacementPass::GetConstantInteger( return GetIntegerLiteral(op); } -size_t ScalarReplacementPass::GetArrayLength( +uint64_t ScalarReplacementPass::GetArrayLength( const Instruction* arrayType) const { assert(arrayType->opcode() == SpvOpTypeArray); const Instruction* length = @@ -488,14 +488,14 @@ size_t ScalarReplacementPass::GetArrayLength( return GetConstantInteger(length); } -size_t ScalarReplacementPass::GetNumElements(const Instruction* type) const { +uint64_t ScalarReplacementPass::GetNumElements(const Instruction* type) const { assert(type->opcode() == SpvOpTypeVector || type->opcode() == SpvOpTypeMatrix); const Operand& op = type->GetInOperand(1u); assert(op.words.size() <= 2); - size_t len = 0; - for (uint32_t i = 0; i != op.words.size(); ++i) { - len |= (op.words[i] << (32 * i)); + uint64_t len = 0; + for (size_t i = 0; i != op.words.size(); ++i) { + len |= (static_cast(op.words[i]) << (32ull * i)); } return len; } @@ -717,7 +717,7 @@ bool ScalarReplacementPass::CheckStore(const Instruction* inst, return false; return true; } -bool ScalarReplacementPass::IsLargerThanSizeLimit(size_t length) const { +bool ScalarReplacementPass::IsLargerThanSizeLimit(uint64_t length) const { if (max_num_elements_ == 0) { return false; } diff --git a/3rdparty/spirv-tools/source/opt/scalar_replacement_pass.h b/3rdparty/spirv-tools/source/opt/scalar_replacement_pass.h index f5d761278..0ff994745 100644 --- a/3rdparty/spirv-tools/source/opt/scalar_replacement_pass.h +++ b/3rdparty/spirv-tools/source/opt/scalar_replacement_pass.h @@ -157,18 +157,18 @@ class ScalarReplacementPass : public Pass { // Returns the value of an OpConstant of integer type. // // |constant| must use two or fewer words to generate the value. - size_t GetConstantInteger(const Instruction* constant) const; + uint64_t GetConstantInteger(const Instruction* constant) const; // Returns the integer literal for |op|. - size_t GetIntegerLiteral(const Operand& op) const; + uint64_t GetIntegerLiteral(const Operand& op) const; // Returns the array length for |arrayInst|. - size_t GetArrayLength(const Instruction* arrayInst) const; + uint64_t GetArrayLength(const Instruction* arrayInst) const; // Returns the number of elements in |type|. // // |type| must be a vector or matrix type. - size_t GetNumElements(const Instruction* type) const; + uint64_t GetNumElements(const Instruction* type) const; // Returns true if |id| is a specialization constant. // @@ -228,7 +228,7 @@ class ScalarReplacementPass : public Pass { // Limit on the number of members in an object that will be replaced. // 0 means there is no limit. uint32_t max_num_elements_; - bool IsLargerThanSizeLimit(size_t length) const; + bool IsLargerThanSizeLimit(uint64_t length) const; char name_[55]; }; diff --git a/3rdparty/spirv-tools/source/val/validate_decorations.cpp b/3rdparty/spirv-tools/source/val/validate_decorations.cpp index 193b170e9..1eef64d56 100644 --- a/3rdparty/spirv-tools/source/val/validate_decorations.cpp +++ b/3rdparty/spirv-tools/source/val/validate_decorations.cpp @@ -548,6 +548,9 @@ spv_result_t checkLayout(uint32_t struct_id, const char* storage_class_str, typeId, storage_class_str, decoration_str, blockRules, next_offset, constraints, vstate))) return recursive_status; + // If offsets accumulate up to a 16-byte multiple stop checking since + // it will just repeat. + if (i > 0 && (next_offset % 16 == 0)) break; } // Proceed to the element in case it is an array. diff --git a/3rdparty/spirv-tools/source/val/validate_memory_semantics.cpp b/3rdparty/spirv-tools/source/val/validate_memory_semantics.cpp index 5dece3f65..31154f5d4 100644 --- a/3rdparty/spirv-tools/source/val/validate_memory_semantics.cpp +++ b/3rdparty/spirv-tools/source/val/validate_memory_semantics.cpp @@ -55,9 +55,7 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _, SpvMemorySemanticsMakeAvailableKHRMask | SpvMemorySemanticsMakeVisibleKHRMask; if (!spvOpcodeIsAtomicOp(inst->opcode())) { - valid_bits |= SpvMemorySemanticsAcquireMask | - SpvMemorySemanticsReleaseMask | - SpvMemorySemanticsAcquireReleaseMask; + valid_bits |= SpvMemorySemanticsAcquireReleaseMask; } if (value & ~valid_bits) { @@ -69,11 +67,18 @@ spv_result_t ValidateMemorySemantics(ValidationState_t& _, } else { return _.diag(SPV_ERROR_INVALID_DATA, inst) << "WebGPU spec disallows any bit masks in Memory Semantics " - "that are not Acquire, Release, AcquireRelease, " - "UniformMemory, WorkgroupMemory, ImageMemory, " - "OutputMemoryKHR, MakeAvailableKHR, or MakeVisibleKHR"; + "that are not AcquireRelease, UniformMemory, " + "WorkgroupMemory, ImageMemory, OutputMemoryKHR, " + "MakeAvailableKHR, or MakeVisibleKHR"; } } + + if (!spvOpcodeIsAtomicOp(inst->opcode()) && + !(value & SpvMemorySemanticsAcquireReleaseMask)) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "WebGPU spec requires AcquireRelease to set in Memory " + "Semantics."; + } } const size_t num_memory_order_set_bits = spvtools::utils::CountSetBits( diff --git a/3rdparty/spirv-tools/test/opt/decompose_initialized_variables_test.cpp b/3rdparty/spirv-tools/test/opt/decompose_initialized_variables_test.cpp index 188e8b232..cdebb3f73 100644 --- a/3rdparty/spirv-tools/test/opt/decompose_initialized_variables_test.cpp +++ b/3rdparty/spirv-tools/test/opt/decompose_initialized_variables_test.cpp @@ -23,63 +23,230 @@ namespace { using DecomposeInitializedVariablesTest = PassTest<::testing::Test>; -void operator+=(std::vector& lhs, - const std::vector rhs) { - for (auto elem : rhs) lhs.push_back(elem); -} +std::string single_entry_header = R"(OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Vertex %1 "shader" +%uint = OpTypeInt 32 0 +%uint_1 = OpConstant %uint 1 +%4 = OpConstantNull %uint +%void = OpTypeVoid +%6 = OpTypeFunction %void +)"; -std::vector header = { - "OpCapability Shader", - "OpCapability VulkanMemoryModelKHR", - "OpExtension \"SPV_KHR_vulkan_memory_model\"", - "OpMemoryModel Logical VulkanKHR", - "OpEntryPoint Vertex %1 \"shader\"", - "%uint = OpTypeInt 32 0", - "%uint_1 = OpConstant %uint 1", - "%4 = OpConstantNull %uint", - "%void = OpTypeVoid", - "%6 = OpTypeFunction %void"}; - -std::string GetFunctionTest(std::vector body) { - auto result = header; - result += {"%_ptr_Function_uint = OpTypePointer Function %uint", - "%1 = OpFunction %void None %6", "%8 = OpLabel"}; - result += body; - result += {"OpReturn", "OpFunctionEnd"}; - return JoinAllInsts(result); +std::string GetFunctionTest(std::string body) { + auto result = single_entry_header; + result += "%_ptr_Function_uint = OpTypePointer Function %uint\n"; + result += "%1 = OpFunction %void None %6\n"; + result += "%8 = OpLabel\n"; + result += body + "\n"; + result += "OpReturn\n"; + result += "OpFunctionEnd\n"; + return result; } TEST_F(DecomposeInitializedVariablesTest, FunctionChanged) { - std::string input = - GetFunctionTest({"%9 = OpVariable %_ptr_Function_uint Function %uint_1"}); - std::string expected = GetFunctionTest( - {"%9 = OpVariable %_ptr_Function_uint Function", "OpStore %9 %uint_1"}); + std::string input = "%9 = OpVariable %_ptr_Function_uint Function %uint_1"; + std::string expected = R"(%9 = OpVariable %_ptr_Function_uint Function +OpStore %9 %uint_1)"; + SinglePassRunAndCheck( + GetFunctionTest(input), GetFunctionTest(expected), + /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, FunctionUnchanged) { + std::string input = "%9 = OpVariable %_ptr_Function_uint Function"; + + SinglePassRunAndCheck( + GetFunctionTest(input), GetFunctionTest(input), /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, FunctionMultipleVariables) { + std::string input = R"(%9 = OpVariable %_ptr_Function_uint Function %uint_1 +%10 = OpVariable %_ptr_Function_uint Function %4)"; + std::string expected = R"(%9 = OpVariable %_ptr_Function_uint Function +%10 = OpVariable %_ptr_Function_uint Function +OpStore %9 %uint_1 +OpStore %10 %4)"; + + SinglePassRunAndCheck( + GetFunctionTest(input), GetFunctionTest(expected), + /* skip_nop = */ false); +} + +std::string GetGlobalTest(std::string storage_class, bool initialized, + bool decomposed) { + auto result = single_entry_header; + + result += "%_ptr_" + storage_class + "_uint = OpTypePointer " + + storage_class + " %uint\n"; + if (initialized) { + result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + + storage_class + " %4\n"; + } else { + result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + + storage_class + "\n"; + } + result += R"(%1 = OpFunction %void None %9 +%9 = OpLabel +)"; + if (decomposed) result += "OpStore %8 %4\n"; + result += R"(OpReturn +OpFunctionEnd +)"; + return result; +} + +TEST_F(DecomposeInitializedVariablesTest, PrivateChanged) { + std::string input = GetGlobalTest("Private", true, false); + std::string expected = GetGlobalTest("Private", false, true); SinglePassRunAndCheck( input, expected, /* skip_nop = */ false); } -TEST_F(DecomposeInitializedVariablesTest, FunctionUnchanged) { - std::string input = - GetFunctionTest({"%9 = OpVariable %_ptr_Function_uint Function"}); - +TEST_F(DecomposeInitializedVariablesTest, PrivateUnchanged) { + std::string input = GetGlobalTest("Private", false, false); SinglePassRunAndCheck( input, input, /* skip_nop = */ false); } -TEST_F(DecomposeInitializedVariablesTest, FunctionMultipleVariables) { - std::string input = - GetFunctionTest({"%9 = OpVariable %_ptr_Function_uint Function %uint_1", - "%10 = OpVariable %_ptr_Function_uint Function %4"}); - std::string expected = - GetFunctionTest({"%9 = OpVariable %_ptr_Function_uint Function", - "%10 = OpVariable %_ptr_Function_uint Function", - "OpStore %9 %uint_1", "OpStore %10 %4"}); - +TEST_F(DecomposeInitializedVariablesTest, OutputChanged) { + std::string input = GetGlobalTest("Output", true, false); + std::string expected = GetGlobalTest("Output", false, true); SinglePassRunAndCheck( input, expected, /* skip_nop = */ false); } +TEST_F(DecomposeInitializedVariablesTest, OutputUnchanged) { + std::string input = GetGlobalTest("Output", false, false); + SinglePassRunAndCheck( + input, input, /* skip_nop = */ false); +} + +std::string multiple_entry_header = R"(OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Vertex %1 "vertex" +OpEntryPoint Fragment %2 "fragment" +%uint = OpTypeInt 32 0 +%4 = OpConstantNull %uint +%void = OpTypeVoid +%6 = OpTypeFunction %void +)"; + +std::string GetGlobalMultipleEntryTest(std::string storage_class, + bool initialized, bool decomposed) { + auto result = multiple_entry_header; + result += "%_ptr_" + storage_class + "_uint = OpTypePointer " + + storage_class + " %uint\n"; + if (initialized) { + result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + + storage_class + " %4\n"; + } else { + result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + + storage_class + "\n"; + } + result += R"(%1 = OpFunction %void None %9 +%9 = OpLabel +)"; + if (decomposed) result += "OpStore %8 %4\n"; + result += R"(OpReturn +OpFunctionEnd +%2 = OpFunction %void None %10 +%10 = OpLabel +)"; + if (decomposed) result += "OpStore %8 %4\n"; + result += R"(OpReturn +OpFunctionEnd +)"; + + return result; +} + +TEST_F(DecomposeInitializedVariablesTest, PrivateMultipleEntryChanged) { + std::string input = GetGlobalMultipleEntryTest("Private", true, false); + std::string expected = GetGlobalMultipleEntryTest("Private", false, true); + SinglePassRunAndCheck( + input, expected, /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, PrivateMultipleEntryUnchanged) { + std::string input = GetGlobalMultipleEntryTest("Private", false, false); + SinglePassRunAndCheck( + input, input, /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, OutputMultipleEntryChanged) { + std::string input = GetGlobalMultipleEntryTest("Output", true, false); + std::string expected = GetGlobalMultipleEntryTest("Output", false, true); + SinglePassRunAndCheck( + input, expected, /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, OutputMultipleEntryUnchanged) { + std::string input = GetGlobalMultipleEntryTest("Output", false, false); + SinglePassRunAndCheck( + input, input, /* skip_nop = */ false); +} + +std::string GetGlobalWithNonEntryPointTest(std::string storage_class, + bool initialized, bool decomposed) { + auto result = single_entry_header; + result += "%_ptr_" + storage_class + "_uint = OpTypePointer " + + storage_class + " %uint\n"; + if (initialized) { + result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + + storage_class + " %4\n"; + } else { + result += "%8 = OpVariable %_ptr_" + storage_class + "_uint " + + storage_class + "\n"; + } + result += R"(%1 = OpFunction %void None %9 +%9 = OpLabel +)"; + if (decomposed) result += "OpStore %8 %4\n"; + result += R"(OpReturn +OpFunctionEnd +%10 = OpFunction %void None %11 +%11 = OpLabel +OpReturn +OpFunctionEnd +)"; + + return result; +} + +TEST_F(DecomposeInitializedVariablesTest, PrivateWithNonEntryPointChanged) { + std::string input = GetGlobalWithNonEntryPointTest("Private", true, false); + std::string expected = GetGlobalWithNonEntryPointTest("Private", false, true); + SinglePassRunAndCheck( + input, expected, /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, PrivateWithNonEntryPointUnchanged) { + std::string input = GetGlobalWithNonEntryPointTest("Private", false, false); + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + input, input, /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, OutputWithNonEntryPointChanged) { + std::string input = GetGlobalWithNonEntryPointTest("Output", true, false); + std::string expected = GetGlobalWithNonEntryPointTest("Output", false, true); + SinglePassRunAndCheck( + input, expected, /* skip_nop = */ false); +} + +TEST_F(DecomposeInitializedVariablesTest, OutputWithNonEntryPointUnchanged) { + std::string input = GetGlobalWithNonEntryPointTest("Output", false, false); + // SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + SinglePassRunAndCheck( + input, input, /* skip_nop = */ false); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/val/val_barriers_test.cpp b/3rdparty/spirv-tools/test/val/val_barriers_test.cpp index 264d130bd..0b28c4554 100644 --- a/3rdparty/spirv-tools/test/val/val_barriers_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_barriers_test.cpp @@ -78,9 +78,13 @@ OpCapability Shader %acquire_and_release = OpConstant %u32 6 %sequentially_consistent = OpConstant %u32 16 %acquire_release_uniform_workgroup = OpConstant %u32 328 +%acquire_uniform_workgroup = OpConstant %u32 322 +%release_uniform_workgroup = OpConstant %u32 324 %acquire_and_release_uniform = OpConstant %u32 70 %acquire_release_subgroup = OpConstant %u32 136 %uniform = OpConstant %u32 64 +%uniform_workgroup = OpConstant %u32 320 + %main = OpFunction %void None %func %main_entry = OpLabel @@ -245,9 +249,8 @@ OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); } -TEST_F(ValidateBarriers, OpControlBarrierWebGPUSuccess) { +TEST_F(ValidateBarriers, OpControlBarrierWebGPUAcquireReleaseSuccess) { const std::string body = R"( -OpControlBarrier %workgroup %queuefamily %none OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup )"; @@ -255,6 +258,41 @@ OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); } +TEST_F(ValidateBarriers, OpControlBarrierWebGPURelaxedFailure) { + const std::string body = R"( +OpControlBarrier %workgroup %workgroup %uniform_workgroup +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("WebGPU spec requires AcquireRelease to set")); +} + +TEST_F(ValidateBarriers, OpControlBarrierWebGPUAcquireFailure) { + const std::string body = R"( +OpControlBarrier %workgroup %workgroup %acquire_uniform_workgroup +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("WebGPU spec disallows any bit masks in Memory Semantics")); +} + +TEST_F(ValidateBarriers, OpControlBarrierWebGPUReleaseFailure) { + const std::string body = R"( +OpControlBarrier %workgroup %workgroup %release_uniform_workgroup +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("WebGPU spec disallows any bit masks in Memory Semantics")); +} + TEST_F(ValidateBarriers, OpControlBarrierExecutionModelFragmentSpirv12) { const std::string body = R"( OpControlBarrier %device %device %none @@ -630,6 +668,50 @@ OpMemoryBarrier %workgroup %acquire_release_uniform_workgroup ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0)); } +TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUAcquireReleaseSuccess) { + const std::string body = R"( +OpMemoryBarrier %workgroup %acquire_release_uniform_workgroup +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + +TEST_F(ValidateBarriers, OpMemoryBarrierWebGPURelaxedFailure) { + const std::string body = R"( +OpMemoryBarrier %workgroup %uniform_workgroup +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("WebGPU spec requires AcquireRelease to set")); +} + +TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUAcquireFailure) { + const std::string body = R"( +OpMemoryBarrier %workgroup %acquire_uniform_workgroup +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("WebGPU spec disallows any bit masks in Memory Semantics")); +} + +TEST_F(ValidateBarriers, OpMemoryBarrierWebGPUReleaseFailure) { + const std::string body = R"( +OpMemoryBarrier %workgroup %release_uniform_workgroup +)"; + + CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("WebGPU spec disallows any bit masks in Memory Semantics")); +} + TEST_F(ValidateBarriers, OpMemoryBarrierFloatMemoryScope) { const std::string body = R"( OpMemoryBarrier %f32_1 %acquire_release_uniform_workgroup diff --git a/3rdparty/spirv-tools/test/val/val_decoration_test.cpp b/3rdparty/spirv-tools/test/val/val_decoration_test.cpp index 635afad2b..764ee08bd 100644 --- a/3rdparty/spirv-tools/test/val/val_decoration_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_decoration_test.cpp @@ -5719,6 +5719,41 @@ OpFunctionEnd "improperly straddling vector at offset 28")); } +TEST_F(ValidateDecorations, LargeArray) { + const std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpExecutionMode %main LocalSize 1 1 1 +OpDecorate %struct Block +OpMemberDecorate %struct 0 Offset 0 +OpDecorate %array ArrayStride 24 +OpMemberDecorate %inner 0 Offset 0 +OpMemberDecorate %inner 1 Offset 8 +OpMemberDecorate %inner 2 Offset 16 +OpMemberDecorate %inner 3 Offset 20 +OpDecorate %var DescriptorSet 0 +OpDecorate %var Binding 0 +%void = OpTypeVoid +%int = OpTypeInt 32 0 +%int_2000000 = OpConstant %int 2000000 +%int2 = OpTypeVector %int 2 +%inner = OpTypeStruct %int %int2 %int %int +%array = OpTypeArray %inner %int_2000000 +%struct = OpTypeStruct %array +%ptr_struct = OpTypePointer StorageBuffer %struct +%var = OpVariable %ptr_struct 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_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + // NonWritable // Returns a SPIR-V shader module with variables in various storage classes, diff --git a/3rdparty/spirv-tools/tools/CMakeLists.txt b/3rdparty/spirv-tools/tools/CMakeLists.txt index d42d4cc61..bce6f1bbf 100644 --- a/3rdparty/spirv-tools/tools/CMakeLists.txt +++ b/3rdparty/spirv-tools/tools/CMakeLists.txt @@ -12,7 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -add_subdirectory(lesspipe) +if (NOT ${SPIRV_SKIP_EXECUTABLES}) + add_subdirectory(lesspipe) +endif() add_subdirectory(emacs) # Add a SPIR-V Tools command line tool. Signature: