From 16d7db088dd4fcdf3d0083126f8014517be9f119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=80=D0=B0=D0=BD=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D0=B0=D1=80=D0=B0=D1=9F=D0=B8=D1=9B?= Date: Wed, 16 Jan 2019 21:12:54 -0800 Subject: [PATCH] Updated spirv-tools. --- 3rdparty/spirv-tools/CHANGES | 25 +- 3rdparty/spirv-tools/DEPS | 2 +- .../include/generated/build-version.inc | 2 +- .../include/spirv-tools/instrument.hpp | 4 +- .../kokoro/scripts/windows/build.bat | 25 +- 3rdparty/spirv-tools/source/operand.cpp | 3 + 3rdparty/spirv-tools/source/opt/constants.h | 2 +- 3rdparty/spirv-tools/source/opt/fold.cpp | 24 +- .../source/opt/instrument_pass.cpp | 10 +- 3rdparty/spirv-tools/source/opt/ir_builder.h | 10 + .../spirv-tools/source/opt/ir_context.cpp | 4 +- .../source/opt/upgrade_memory_model.cpp | 75 +- .../source/opt/upgrade_memory_model.h | 5 + 3rdparty/spirv-tools/source/val/validate.cpp | 59 +- .../source/val/validate_atomics.cpp | 1 + .../source/val/validate_constants.cpp | 10 +- .../source/val/validate_conversion.cpp | 34 + .../source/val/validate_decorations.cpp | 58 +- .../source/val/validate_function.cpp | 73 ++ .../source/val/validate_logicals.cpp | 3 +- .../source/val/validate_memory.cpp | 177 +++- .../spirv-tools/source/val/validate_type.cpp | 28 + .../source/val/validation_state.cpp | 17 + .../spirv-tools/source/val/validation_state.h | 29 +- .../spirv-tools/test/binary_parse_test.cpp | 2 + .../spirv-tools/test/binary_to_text_test.cpp | 23 +- .../spirv-tools/test/ext_inst.glsl_test.cpp | 3 +- 3rdparty/spirv-tools/test/opt/CMakeLists.txt | 7 +- 3rdparty/spirv-tools/test/opt/fold_test.cpp | 37 +- .../test/opt/inst_bindless_check_test.cpp | 23 +- 3rdparty/spirv-tools/test/opt/pass_fixture.h | 10 +- .../test/opt/upgrade_memory_model_test.cpp | 379 ++++++-- 3rdparty/spirv-tools/test/test_fixture.h | 13 + .../test/val/val_constants_test.cpp | 14 + .../test/val/val_conversion_test.cpp | 112 +++ .../spirv-tools/test/val/val_data_test.cpp | 169 ++++ .../test/val/val_decoration_test.cpp | 502 ++++++++++- 3rdparty/spirv-tools/test/val/val_fixtures.h | 22 +- 3rdparty/spirv-tools/test/val/val_id_test.cpp | 2 + .../test/val/val_logicals_test.cpp | 30 + .../spirv-tools/test/val/val_memory_test.cpp | 815 ++++++++++++++++++ .../test/val/val_validation_state_test.cpp | 48 ++ 42 files changed, 2725 insertions(+), 166 deletions(-) diff --git a/3rdparty/spirv-tools/CHANGES b/3rdparty/spirv-tools/CHANGES index 7f9008f01..d4c6dffe2 100644 --- a/3rdparty/spirv-tools/CHANGES +++ b/3rdparty/spirv-tools/CHANGES @@ -1,20 +1,39 @@ Revision history for SPIRV-Tools -v2018.7-dev 2018-12-10 +v2019.2-dev 2019-01-07 + - Start v2019.2-dev + +v2019.1 2019-01-07 - General: - Created a new tool called spirv-reduce. - Add cmake option to turn off SPIRV_TIMER_ENABLED (#2103) - New optimization pass to update the memory model from GLSL450 to VulkanKHR. + - Recognize OpTypeAccelerationStructureNV as a type instruction and ray tracing storage classes. + - Fix GCC8 build. + - Add --target-env flag to spirv-opt. + - Add --webgpu-mode flag to run optimizations for webgpu. + - The output disassembled line number stead of byte offset in validation errors. (#2091) - Optimizer - Added the instrumentation passes for bindless validation. - Added passes to help preserve OpLine information (#2027) - Add basic support for EXT_fragment_invocation_density (#2100) - Fix invalid OpPhi generated by merge-return. (#2172) + - Constant and type manager have been turned into analysies. (#2251) Fixes: - #2018: Don't inline functions with a return in a structured CFG contstruct. - #2047: Fix bug in folding when volatile stores are present. - #2053: Fix check for when folding floating pointer values is allowed. - #2130: Don't inline recursive functions. + - #2202: Handle multiple edges between two basic blocks in SSA-rewriter. + - #2205: Don't unswitch a latch condition during loop unswitch. + - #2245: Don't fold branch in loop unswitch. Run dead branch elimination to fold them. + - #2204: Fix eliminate common uniform to place OpPhi instructions correctly. + - #2247: Fix type mismatches caused by scalar replacement. + - #2248: Fix missing OpPhi after merge return. + - #2211: After merge return, fix invalid continue target. + - #2210: Fix loop invariant code motion to not place code between merge instruction and branch. + - #2258: Handle CompositeInsert with no indices in VDCE. + - #2261: Have replace load size handle extact with no index. - Validator - Changed the naming convention of outputing ids with names in diagnostic messages. - Added validation rules for UniformConstant variables in Vulkan. @@ -32,12 +51,14 @@ v2018.7-dev 2018-12-10 - Allow Float16/Int8 for Vulkan 1.0 (#2153) - Check binding annotations in resource variables (#2151, #2167) - Validate OpForwardPointer (#2156) + - Validate operation for OpSpecConstantOp (#2260) Fixes: - #2049: Allow InstanceId for NV ray tracing - Reduce - Initial commit wit a few passes to reduce test cases. + - Validation is run after each reduction step. Fixes: - + v2018.6 2018-11-07 - General: diff --git a/3rdparty/spirv-tools/DEPS b/3rdparty/spirv-tools/DEPS index f7bac6d1c..5668c6602 100644 --- a/3rdparty/spirv-tools/DEPS +++ b/3rdparty/spirv-tools/DEPS @@ -11,7 +11,7 @@ vars = { 'googletest_revision': '98a0d007d7092b72eea0e501bb9ad17908a1a036', 'testing_revision': '340252637e2e7c72c0901dcbeeacfff419e19b59', 're2_revision': '6cf8ccd82dbaab2668e9b13596c68183c9ecd13f', - 'spirv_headers_revision': 'd5b2e1255f706ce1f88812217e9a554f299848af', + 'spirv_headers_revision': '79b6681aadcb53c27d1052e5f8a0e82a981dbf2f', } deps = { diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index cd8e96fee..1f3cadec2 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2018.7-dev", "SPIRV-Tools v2018.7-dev bc65303576278bfb67295395327dc395a6adbf98" +"v2019.2-dev", "SPIRV-Tools v2019.2-dev 3c8b3c81ef7f378717ef88916c06cb221eea890b" diff --git a/3rdparty/spirv-tools/include/spirv-tools/instrument.hpp b/3rdparty/spirv-tools/include/spirv-tools/instrument.hpp index 69d1ad259..f8068099c 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/instrument.hpp +++ b/3rdparty/spirv-tools/include/spirv-tools/instrument.hpp @@ -75,8 +75,8 @@ static const int kInstCommonOutCnt = 4; // error. // // Vertex Shader Output Record Offsets -static const int kInstVertOutVertexId = kInstCommonOutCnt; -static const int kInstVertOutInstanceId = kInstCommonOutCnt + 1; +static const int kInstVertOutVertexIndex = kInstCommonOutCnt; +static const int kInstVertOutInstanceIndex = kInstCommonOutCnt + 1; // Frag Shader Output Record Offsets static const int kInstFragOutFragCoordX = kInstCommonOutCnt; diff --git a/3rdparty/spirv-tools/kokoro/scripts/windows/build.bat b/3rdparty/spirv-tools/kokoro/scripts/windows/build.bat index a2472fb4f..1985419f0 100644 --- a/3rdparty/spirv-tools/kokoro/scripts/windows/build.bat +++ b/3rdparty/spirv-tools/kokoro/scripts/windows/build.bat @@ -58,33 +58,38 @@ if "%KOKORO_GITHUB_COMMIT%." == "." ( set BUILD_SHA=%KOKORO_GITHUB_COMMIT% ) +set CMAKE_FLAGS=-GNinja -DSPIRV_BUILD_COMPRESSION=ON -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DCMAKE_INSTALL_PREFIX=install -DRE2_BUILD_TESTING=OFF -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe + :: Skip building tests for VS2013 if %VS_VERSION% == 2013 ( - cmake -GNinja -DSPIRV_SKIP_TESTS=ON -DSPIRV_BUILD_COMPRESSION=ON -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DCMAKE_INSTALL_PREFIX=install -DRE2_BUILD_TESTING=OFF -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe .. -) else ( - cmake -GNinja -DSPIRV_BUILD_COMPRESSION=ON -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DCMAKE_INSTALL_PREFIX=install -DRE2_BUILD_TESTING=OFF -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe .. + set CMAKE_FLAGS=%CMAKE_FLAGS% -DSPIRV_SKIP_TESTS=ON ) -if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL% +cmake %CMAKE_FLAGS% .. + +if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% echo "Build everything... %DATE% %TIME%" ninja -if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL% +if %ERRORLEVEL% NEQ 0 exit /b %ERRORLEVEL% echo "Build Completed %DATE% %TIME%" +:: This lets us use !ERRORLEVEL! inside an IF ... () and get the actual error at that point. +setlocal ENABLEDELAYEDEXPANSION + :: ################################################ :: Run the tests (We no longer run tests on VS2013) :: ################################################ -if NOT %VS_VERSION% == 2013 ( - echo "Running Tests... %DATE% %TIME%" +echo "Running Tests... %DATE% %TIME%" +if %VS_VERSION% NEQ 2013 ( ctest -C %BUILD_TYPE% --output-on-failure --timeout 300 - if %ERRORLEVEL% GEQ 1 exit /b %ERRORLEVEL% - echo "Tests Completed %DATE% %TIME%" + if !ERRORLEVEL! NEQ 0 exit /b !ERRORLEVEL! ) +echo "Tests Completed %DATE% %TIME%" :: Clean up some directories. rm -rf %SRC%\build rm -rf %SRC%\external -exit /b %ERRORLEVEL% +exit /b 0 diff --git a/3rdparty/spirv-tools/source/operand.cpp b/3rdparty/spirv-tools/source/operand.cpp index 923074e45..00dc53d1d 100644 --- a/3rdparty/spirv-tools/source/operand.cpp +++ b/3rdparty/spirv-tools/source/operand.cpp @@ -481,6 +481,9 @@ std::function spvOperandCanBeForwardDeclaredFunction( case SpvOpTypeForwardPointer: out = [](unsigned index) { return index == 0; }; break; + case SpvOpTypeArray: + out = [](unsigned index) { return index == 1; }; + break; default: out = [](unsigned) { return false; }; break; diff --git a/3rdparty/spirv-tools/source/opt/constants.h b/3rdparty/spirv-tools/source/opt/constants.h index 5baeaebe8..de2dfc3d0 100644 --- a/3rdparty/spirv-tools/source/opt/constants.h +++ b/3rdparty/spirv-tools/source/opt/constants.h @@ -15,7 +15,7 @@ #ifndef SOURCE_OPT_CONSTANTS_H_ #define SOURCE_OPT_CONSTANTS_H_ -#include +#include #include #include #include diff --git a/3rdparty/spirv-tools/source/opt/fold.cpp b/3rdparty/spirv-tools/source/opt/fold.cpp index d6b583f91..0604da2a1 100644 --- a/3rdparty/spirv-tools/source/opt/fold.cpp +++ b/3rdparty/spirv-tools/source/opt/fold.cpp @@ -115,8 +115,10 @@ uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a, // Shifting case SpvOp::SpvOpShiftRightLogical: - if (b > 32) { - // This is undefined behaviour. Choose 0 for consistency. + if (b >= 32) { + // This is undefined behaviour when |b| > 32. Choose 0 for consistency. + // When |b| == 32, doing the shift in C++ in undefined, but the result + // will be 0, so just return that value. return 0; } return a >> b; @@ -125,10 +127,21 @@ uint32_t InstructionFolder::BinaryOperate(SpvOp opcode, uint32_t a, // This is undefined behaviour. Choose 0 for consistency. return 0; } + if (b == 32) { + // Doing the shift in C++ is undefined, but the result is defined in the + // spir-v spec. Find that value another way. + if (static_cast(a) >= 0) { + return 0; + } else { + return static_cast(-1); + } + } return (static_cast(a)) >> b; case SpvOp::SpvOpShiftLeftLogical: - if (b > 32) { - // This is undefined behaviour. Choose 0 for consistency. + if (b >= 32) { + // This is undefined behaviour when |b| > 32. Choose 0 for consistency. + // When |b| == 32, doing the shift in C++ in undefined, but the result + // will be 0, so just return that value. return 0; } return a << b; @@ -307,7 +320,8 @@ bool InstructionFolder::FoldBinaryIntegerOpToConstant( if (constants[1] != nullptr) { // When shifting by a value larger than the size of the result, the // result is undefined. We are setting the undefined behaviour to a - // result of 0. + // result of 0. If the shift amount is the same as the size of the + // result, then the result is defined, and it 0. uint32_t shift_amount = constants[1]->GetU32BitValue(); if (shift_amount >= 32) { *result = 0; diff --git a/3rdparty/spirv-tools/source/opt/instrument_pass.cpp b/3rdparty/spirv-tools/source/opt/instrument_pass.cpp index 7f56a1e0d..6935a43dc 100644 --- a/3rdparty/spirv-tools/source/opt/instrument_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/instrument_pass.cpp @@ -168,10 +168,10 @@ void InstrumentPass::GenStageStreamWriteCode(uint32_t stage_idx, switch (stage_idx) { case SpvExecutionModelVertex: { // Load and store VertexId and InstanceId - GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInVertexId), - kInstVertOutVertexId, base_offset_id, builder); - GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInInstanceId), - kInstVertOutInstanceId, base_offset_id, builder); + GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInVertexIndex), + kInstVertOutVertexIndex, base_offset_id, builder); + GenBuiltinOutputCode(context()->GetBuiltinVarId(SpvBuiltInInstanceIndex), + kInstVertOutInstanceIndex, base_offset_id, builder); } break; case SpvExecutionModelGLCompute: { // Load and store GlobalInvocationId. Second word is unused; store zero. @@ -309,6 +309,8 @@ uint32_t InstrumentPass::GetOutputBufferId() { analysis::RuntimeArray uint_rarr_ty(reg_uint_ty); analysis::Type* reg_uint_rarr_ty = type_mgr->GetRegisteredType(&uint_rarr_ty); + uint32_t uint_arr_ty_id = type_mgr->GetTypeInstruction(reg_uint_rarr_ty); + deco_mgr->AddDecorationVal(uint_arr_ty_id, SpvDecorationArrayStride, 4u); analysis::Struct obuf_ty({reg_uint_ty, reg_uint_rarr_ty}); analysis::Type* reg_obuf_ty = type_mgr->GetRegisteredType(&obuf_ty); uint32_t obufTyId = type_mgr->GetTypeInstruction(reg_obuf_ty); diff --git a/3rdparty/spirv-tools/source/opt/ir_builder.h b/3rdparty/spirv-tools/source/opt/ir_builder.h index 2f741d88e..da7405512 100644 --- a/3rdparty/spirv-tools/source/opt/ir_builder.h +++ b/3rdparty/spirv-tools/source/opt/ir_builder.h @@ -455,6 +455,16 @@ class InstructionBuilder { return AddInstruction(std::move(new_inst)); } + Instruction* AddStore(uint32_t ptr_id, uint32_t obj_id) { + std::vector operands; + operands.push_back({SPV_OPERAND_TYPE_ID, {ptr_id}}); + operands.push_back({SPV_OPERAND_TYPE_ID, {obj_id}}); + + std::unique_ptr new_inst( + new Instruction(GetContext(), SpvOpStore, 0, 0, operands)); + return AddInstruction(std::move(new_inst)); + } + // Inserts the new instruction before the insertion point. Instruction* AddInstruction(std::unique_ptr&& insn) { Instruction* insn_ptr = &*insert_before_.InsertBefore(std::move(insn)); diff --git a/3rdparty/spirv-tools/source/opt/ir_context.cpp b/3rdparty/spirv-tools/source/opt/ir_context.cpp index a2f207c0c..fe69027f8 100644 --- a/3rdparty/spirv-tools/source/opt/ir_context.cpp +++ b/3rdparty/spirv-tools/source/opt/ir_context.cpp @@ -669,8 +669,8 @@ uint32_t IRContext::GetBuiltinVarId(uint32_t builtin) { reg_type = type_mgr->GetRegisteredType(&v4float_ty); break; } - case SpvBuiltInVertexId: - case SpvBuiltInInstanceId: + case SpvBuiltInVertexIndex: + case SpvBuiltInInstanceIndex: case SpvBuiltInPrimitiveId: case SpvBuiltInInvocationId: case SpvBuiltInGlobalInvocationId: { diff --git a/3rdparty/spirv-tools/source/opt/upgrade_memory_model.cpp b/3rdparty/spirv-tools/source/opt/upgrade_memory_model.cpp index 8def55f5a..d8836a408 100644 --- a/3rdparty/spirv-tools/source/opt/upgrade_memory_model.cpp +++ b/3rdparty/spirv-tools/source/opt/upgrade_memory_model.cpp @@ -16,6 +16,7 @@ #include +#include "source/opt/ir_builder.h" #include "source/opt/ir_context.h" #include "source/util/make_unique.h" @@ -68,6 +69,22 @@ void UpgradeMemoryModel::UpgradeInstructions() { // instructions. Additionally, Workgroup storage class variables and function // parameters are implicitly coherent in GLSL450. + // Upgrade modf and frexp first since they generate new stores. + for (auto& func : *get_module()) { + func.ForEachInst([this](Instruction* inst) { + if (inst->opcode() == SpvOpExtInst) { + auto ext_inst = inst->GetSingleWordInOperand(1u); + if (ext_inst == GLSLstd450Modf || ext_inst == GLSLstd450Frexp) { + auto import = + get_def_use_mgr()->GetDef(inst->GetSingleWordInOperand(0u)); + if (reinterpret_cast(import->GetInOperand(0u).words.data()) == + std::string("GLSL.std.450")) { + UpgradeExtInst(inst); + } + } + } + }); + } for (auto& func : *get_module()) { func.ForEachInst([this](Instruction* inst) { bool is_coherent = false; @@ -104,11 +121,11 @@ void UpgradeMemoryModel::UpgradeInstructions() { switch (inst->opcode()) { case SpvOpLoad: - UpgradeFlags(inst, 1u, is_coherent, is_volatile, kAvailability, + UpgradeFlags(inst, 1u, is_coherent, is_volatile, kVisibility, kMemory); break; case SpvOpStore: - UpgradeFlags(inst, 2u, is_coherent, is_volatile, kVisibility, + UpgradeFlags(inst, 2u, is_coherent, is_volatile, kAvailability, kMemory); break; case SpvOpCopyMemory: @@ -125,11 +142,11 @@ void UpgradeMemoryModel::UpgradeInstructions() { break; case SpvOpImageRead: case SpvOpImageSparseRead: - UpgradeFlags(inst, 2u, is_coherent, is_volatile, kAvailability, - kImage); + UpgradeFlags(inst, 2u, is_coherent, is_volatile, kVisibility, kImage); break; case SpvOpImageWrite: - UpgradeFlags(inst, 3u, is_coherent, is_volatile, kVisibility, kImage); + UpgradeFlags(inst, 3u, is_coherent, is_volatile, kAvailability, + kImage); break; default: break; @@ -143,15 +160,15 @@ void UpgradeMemoryModel::UpgradeInstructions() { } // According to SPV_KHR_vulkan_memory_model, if both available and // visible flags are used the first scope operand is for availability - // (reads) and the second is for visibiity (writes). - if (src_coherent) { - inst->AddOperand( - {SPV_OPERAND_TYPE_SCOPE_ID, {GetScopeConstant(src_scope)}}); - } + // (writes) and the second is for visibility (reads). if (dst_coherent) { inst->AddOperand( {SPV_OPERAND_TYPE_SCOPE_ID, {GetScopeConstant(dst_scope)}}); } + if (src_coherent) { + inst->AddOperand( + {SPV_OPERAND_TYPE_SCOPE_ID, {GetScopeConstant(src_scope)}}); + } }); } } @@ -581,5 +598,43 @@ bool UpgradeMemoryModel::IsDeviceScope(uint32_t scope_id) { return false; } +void UpgradeMemoryModel::UpgradeExtInst(Instruction* ext_inst) { + const bool is_modf = ext_inst->GetSingleWordInOperand(1u) == GLSLstd450Modf; + auto ptr_id = ext_inst->GetSingleWordInOperand(3u); + auto ptr_type_id = get_def_use_mgr()->GetDef(ptr_id)->type_id(); + auto pointee_type_id = + get_def_use_mgr()->GetDef(ptr_type_id)->GetSingleWordInOperand(1u); + auto element_type_id = ext_inst->type_id(); + std::vector element_types(2); + element_types[0] = context()->get_type_mgr()->GetType(element_type_id); + element_types[1] = context()->get_type_mgr()->GetType(pointee_type_id); + analysis::Struct struct_type(element_types); + uint32_t struct_id = + context()->get_type_mgr()->GetTypeInstruction(&struct_type); + // Change the operation + GLSLstd450 new_op = is_modf ? GLSLstd450ModfStruct : GLSLstd450FrexpStruct; + ext_inst->SetOperand(3u, {static_cast(new_op)}); + // Remove the pointer argument + ext_inst->RemoveOperand(5u); + // Set the type id to the new struct. + ext_inst->SetResultType(struct_id); + + // The result is now a struct of the original result. The zero'th element is + // old result and should replace the old result. The one'th element needs to + // be stored via a new instruction. + auto where = ext_inst->NextNode(); + InstructionBuilder builder( + context(), where, + IRContext::kAnalysisDefUse | IRContext::kAnalysisInstrToBlockMapping); + auto extract_0 = + builder.AddCompositeExtract(element_type_id, ext_inst->result_id(), {0}); + context()->ReplaceAllUsesWith(ext_inst->result_id(), extract_0->result_id()); + // The extract's input was just changed to itself, so fix that. + extract_0->SetInOperand(0u, {ext_inst->result_id()}); + auto extract_1 = + builder.AddCompositeExtract(pointee_type_id, ext_inst->result_id(), {1}); + builder.AddStore(ptr_id, extract_1->result_id()); +} + } // namespace opt } // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/upgrade_memory_model.h b/3rdparty/spirv-tools/source/opt/upgrade_memory_model.h index 29c801c4f..9adc33b68 100644 --- a/3rdparty/spirv-tools/source/opt/upgrade_memory_model.h +++ b/3rdparty/spirv-tools/source/opt/upgrade_memory_model.h @@ -118,6 +118,11 @@ class UpgradeMemoryModel : public Pass { // Returns true if |scope_id| is SpvScopeDevice. bool IsDeviceScope(uint32_t scope_id); + // Upgrades GLSL.std.450 modf and frexp. Both instructions are replaced with + // their struct versions. New extracts and a store are added in order to + // facilitate adding memory model flags. + void UpgradeExtInst(Instruction* modf); + // Caches the result of TraceInstruction. For a given result id and set of // indices, stores whether that combination is coherent and/or volatile. std::unordered_map>, diff --git a/3rdparty/spirv-tools/source/val/validate.cpp b/3rdparty/spirv-tools/source/val/validate.cpp index 5d0c6243f..9797d31ad 100644 --- a/3rdparty/spirv-tools/source/val/validate.cpp +++ b/3rdparty/spirv-tools/source/val/validate.cpp @@ -169,6 +169,57 @@ spv_result_t ValidateForwardDecls(ValidationState_t& _) { << id_str.substr(0, id_str.size() - 1); } +std::vector CalculateNamesForEntryPoint(ValidationState_t& _, + const uint32_t id) { + auto id_descriptions = _.entry_point_descriptions(id); + auto id_names = std::vector(); + id_names.reserve((id_descriptions.size())); + + for (auto description : id_descriptions) id_names.push_back(description.name); + + return id_names; +} + +spv_result_t ValidateEntryPointNameUnique(ValidationState_t& _, + const uint32_t id) { + auto id_names = CalculateNamesForEntryPoint(_, id); + const auto names = + std::unordered_set(id_names.begin(), id_names.end()); + + if (id_names.size() != names.size()) { + std::sort(id_names.begin(), id_names.end()); + for (size_t i = 0; i < id_names.size() - 1; i++) { + if (id_names[i] == id_names[i + 1]) { + return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(id)) + << "Entry point name \"" << id_names[i] + << "\" is not unique, which is not allow in WebGPU env."; + } + } + } + + for (const auto other_id : _.entry_points()) { + if (other_id == id) continue; + const auto other_id_names = CalculateNamesForEntryPoint(_, other_id); + for (const auto other_id_name : other_id_names) { + if (names.find(other_id_name) != names.end()) { + return _.diag(SPV_ERROR_INVALID_BINARY, _.FindDef(id)) + << "Entry point name \"" << other_id_name + << "\" is not unique, which is not allow in WebGPU env."; + } + } + } + + return SPV_SUCCESS; +} + +spv_result_t ValidateEntryPointNamesUnique(ValidationState_t& _) { + for (const auto id : _.entry_points()) { + auto result = ValidateEntryPointNameUnique(_, id); + if (result != SPV_SUCCESS) return result; + } + return SPV_SUCCESS; +} + // Entry point validation. Based on 2.16.1 (Universal Validation Rules) of the // SPIRV spec: // * There is at least one OpEntryPoint instruction, unless the Linkage @@ -177,7 +228,7 @@ spv_result_t ValidateForwardDecls(ValidationState_t& _) { // OpFunctionCall instruction. // // Additionally enforces that entry points for Vulkan and WebGPU should not have -// recursion. +// recursion. And that entry names should be unique for WebGPU. spv_result_t ValidateEntryPoints(ValidationState_t& _) { _.ComputeFunctionToEntryPointMapping(); _.ComputeRecursiveEntryPoints(); @@ -206,6 +257,12 @@ spv_result_t ValidateEntryPoints(ValidationState_t& _) { << "Entry points may not have a call graph with cycles."; } } + + // For WebGPU all entry point names must be unique. + if (spvIsWebGPUEnv(_.context()->target_env)) { + const auto result = ValidateEntryPointNamesUnique(_); + if (result != SPV_SUCCESS) return result; + } } return SPV_SUCCESS; diff --git a/3rdparty/spirv-tools/source/val/validate_atomics.cpp b/3rdparty/spirv-tools/source/val/validate_atomics.cpp index 6bfd06d4e..38c7053b9 100644 --- a/3rdparty/spirv-tools/source/val/validate_atomics.cpp +++ b/3rdparty/spirv-tools/source/val/validate_atomics.cpp @@ -127,6 +127,7 @@ spv_result_t AtomicsPass(ValidationState_t& _, const Instruction* inst) { case SpvStorageClassAtomicCounter: case SpvStorageClassImage: case SpvStorageClassStorageBuffer: + case SpvStorageClassPhysicalStorageBufferEXT: break; default: if (spvIsOpenCLEnv(_.context()->target_env)) { diff --git a/3rdparty/spirv-tools/source/val/validate_constants.cpp b/3rdparty/spirv-tools/source/val/validate_constants.cpp index eab25ec1c..e2f20f672 100644 --- a/3rdparty/spirv-tools/source/val/validate_constants.cpp +++ b/3rdparty/spirv-tools/source/val/validate_constants.cpp @@ -329,11 +329,19 @@ spv_result_t ValidateSpecConstantOp(ValidationState_t& _, } break; + case SpvOpUConvert: + if (!_.features().uconvert_spec_constant_op && + !_.HasCapability(SpvCapabilityKernel)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "UConvert requires Kernel capability or extension " + "SPV_AMD_gpu_shader_int16"; + } + break; + case SpvOpConvertFToS: case SpvOpConvertSToF: case SpvOpConvertFToU: case SpvOpConvertUToF: - case SpvOpUConvert: case SpvOpConvertPtrToU: case SpvOpConvertUToPtr: case SpvOpGenericCastToPtr: diff --git a/3rdparty/spirv-tools/source/val/validate_conversion.cpp b/3rdparty/spirv-tools/source/val/validate_conversion.cpp index b51eec9a4..73da58255 100644 --- a/3rdparty/spirv-tools/source/val/validate_conversion.cpp +++ b/3rdparty/spirv-tools/source/val/validate_conversion.cpp @@ -217,6 +217,23 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) { if (!_.IsPointerType(input_type)) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected input to be a pointer: " << spvOpcodeString(opcode); + + if (_.addressing_model() == SpvAddressingModelLogical) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Logical addressing not supported: " + << spvOpcodeString(opcode); + + if (_.addressing_model() == + SpvAddressingModelPhysicalStorageBuffer64EXT) { + uint32_t input_storage_class = 0; + uint32_t input_data_type = 0; + _.GetPointerTypeInfo(input_type, &input_data_type, + &input_storage_class); + if (input_storage_class != SpvStorageClassPhysicalStorageBufferEXT) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Pointer storage class must be PhysicalStorageBufferEXT: " + << spvOpcodeString(opcode); + } break; } @@ -251,6 +268,23 @@ spv_result_t ConversionPass(ValidationState_t& _, const Instruction* inst) { if (!input_type || !_.IsIntScalarType(input_type)) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Expected int scalar as input: " << spvOpcodeString(opcode); + + if (_.addressing_model() == SpvAddressingModelLogical) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Logical addressing not supported: " + << spvOpcodeString(opcode); + + if (_.addressing_model() == + SpvAddressingModelPhysicalStorageBuffer64EXT) { + uint32_t result_storage_class = 0; + uint32_t result_data_type = 0; + _.GetPointerTypeInfo(result_type, &result_data_type, + &result_storage_class); + if (result_storage_class != SpvStorageClassPhysicalStorageBufferEXT) + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Pointer storage class must be PhysicalStorageBufferEXT: " + << spvOpcodeString(opcode); + } break; } diff --git a/3rdparty/spirv-tools/source/val/validate_decorations.cpp b/3rdparty/spirv-tools/source/val/validate_decorations.cpp index 582d11cc7..7f150aafa 100644 --- a/3rdparty/spirv-tools/source/val/validate_decorations.cpp +++ b/3rdparty/spirv-tools/source/val/validate_decorations.cpp @@ -218,6 +218,9 @@ uint32_t getBaseAlignment(uint32_t member_id, bool roundUp, if (roundUp) baseAlignment = align(baseAlignment, 16u); break; } + case SpvOpTypePointer: + baseAlignment = vstate.pointer_size_and_alignment(); + break; default: assert(0); break; @@ -254,6 +257,8 @@ uint32_t getScalarAlignment(uint32_t type_id, ValidationState_t& vstate) { } return max_member_alignment; } break; + case SpvOpTypePointer: + return vstate.pointer_size_and_alignment(); default: assert(0); break; @@ -331,6 +336,8 @@ uint32_t getSize(uint32_t member_id, const LayoutConstraints& inherited, const auto& constraint = constraints[std::make_pair(lastMember, lastIdx)]; return offset + getSize(lastMember, constraint, constraints, vstate); } + case SpvOpTypePointer: + return vstate.pointer_size_and_alignment(); default: assert(0); return 0; @@ -847,7 +854,9 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { } } - if (uniform || push_constant || storage_buffer) { + const bool phys_storage_buffer = + storageClass == SpvStorageClassPhysicalStorageBufferEXT; + if (uniform || push_constant || storage_buffer || phys_storage_buffer) { const auto ptrInst = vstate.FindDef(words[1]); assert(SpvOpTypePointer == ptrInst->opcode()); const auto id = ptrInst->words()[3]; @@ -899,9 +908,9 @@ spv_result_t CheckDecorationsOfBuffers(ValidationState_t& vstate) { const bool blockDeco = SpvDecorationBlock == dec.dec_type(); const bool bufferDeco = SpvDecorationBufferBlock == dec.dec_type(); const bool blockRules = uniform && blockDeco; - const bool bufferRules = (uniform && bufferDeco) || - (push_constant && blockDeco) || - (storage_buffer && blockDeco); + const bool bufferRules = + (uniform && bufferDeco) || (push_constant && blockDeco) || + ((storage_buffer || phys_storage_buffer) && blockDeco); if (blockRules || bufferRules) { const char* deco_str = blockDeco ? "Block" : "BufferBlock"; spv_result_t recursive_status = SPV_SUCCESS; @@ -1127,12 +1136,13 @@ spv_result_t CheckFPRoundingModeForShaders(ValidationState_t& vstate, if (storage != SpvStorageClassStorageBuffer && storage != SpvStorageClassUniform && storage != SpvStorageClassPushConstant && - storage != SpvStorageClassInput && storage != SpvStorageClassOutput) { + storage != SpvStorageClassInput && storage != SpvStorageClassOutput && + storage != SpvStorageClassPhysicalStorageBufferEXT) { return vstate.diag(SPV_ERROR_INVALID_ID, &inst) << "FPRoundingMode decoration can be applied only to the " "Object operand of an OpStore in the StorageBuffer, " - "Uniform, PushConstant, Input, or Output Storage " - "Classes."; + "PhysicalStorageBufferEXT, Uniform, PushConstant, Input, or " + "Output Storage Classes."; } } return SPV_SUCCESS; @@ -1170,6 +1180,36 @@ spv_result_t CheckUniformDecoration(ValidationState_t& vstate, return SPV_SUCCESS; } +// Returns SPV_SUCCESS if validation rules are satisfied for NoSignedWrap or +// NoUnsignedWrap decorations. Otherwise emits a diagnostic and returns +// something other than SPV_SUCCESS. Assumes each decoration on a group has been +// propagated down to the group members. +spv_result_t CheckIntegerWrapDecoration(ValidationState_t& vstate, + const Instruction& inst, + const Decoration& decoration) { + switch (inst.opcode()) { + case SpvOpIAdd: + case SpvOpISub: + case SpvOpIMul: + case SpvOpShiftLeftLogical: + case SpvOpSNegate: + return SPV_SUCCESS; + case SpvOpExtInst: + // TODO(dneto): Only certain extended instructions allow these + // decorations. For now allow anything. + return SPV_SUCCESS; + default: + break; + } + + return vstate.diag(SPV_ERROR_INVALID_ID, &inst) + << (decoration.dec_type() == SpvDecorationNoSignedWrap + ? "NoSignedWrap" + : "NoUnsignedWrap") + << " decoration may not be applied to " + << spvOpcodeString(inst.opcode()); +} + #define PASS_OR_BAIL_AT_LINE(X, LINE) \ { \ spv_result_t e##LINE = (X); \ @@ -1206,6 +1246,10 @@ spv_result_t CheckDecorationsFromDecoration(ValidationState_t& vstate) { case SpvDecorationUniform: PASS_OR_BAIL(CheckUniformDecoration(vstate, *inst, decoration)); break; + case SpvDecorationNoSignedWrap: + case SpvDecorationNoUnsignedWrap: + PASS_OR_BAIL(CheckIntegerWrapDecoration(vstate, *inst, decoration)); + break; default: break; } diff --git a/3rdparty/spirv-tools/source/val/validate_function.cpp b/3rdparty/spirv-tools/source/val/validate_function.cpp index 39f00fedc..de41b27c3 100644 --- a/3rdparty/spirv-tools/source/val/validate_function.cpp +++ b/3rdparty/spirv-tools/source/val/validate_function.cpp @@ -111,6 +111,79 @@ spv_result_t ValidateFunctionParameter(ValidationState_t& _, << "' does not match the OpTypeFunction parameter " "type of the same index."; } + + // Validate that PhysicalStorageBufferEXT have one of Restrict, Aliased, + // RestrictPointerEXT, or AliasedPointerEXT. + auto param_nonarray_type_id = param_type->id(); + while (_.GetIdOpcode(param_nonarray_type_id) == SpvOpTypeArray) { + param_nonarray_type_id = + _.FindDef(param_nonarray_type_id)->GetOperandAs(1u); + } + if (_.GetIdOpcode(param_nonarray_type_id) == SpvOpTypePointer) { + auto param_nonarray_type = _.FindDef(param_nonarray_type_id); + if (param_nonarray_type->GetOperandAs(1u) == + SpvStorageClassPhysicalStorageBufferEXT) { + // check for Aliased or Restrict + const auto& decorations = _.id_decorations(inst->id()); + + bool foundAliased = std::any_of( + decorations.begin(), decorations.end(), [](const Decoration& d) { + return SpvDecorationAliased == d.dec_type(); + }); + + bool foundRestrict = std::any_of( + decorations.begin(), decorations.end(), [](const Decoration& d) { + return SpvDecorationRestrict == d.dec_type(); + }); + + if (!foundAliased && !foundRestrict) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpFunctionParameter " << inst->id() + << ": expected Aliased or Restrict for PhysicalStorageBufferEXT " + "pointer."; + } + if (foundAliased && foundRestrict) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpFunctionParameter " << inst->id() + << ": can't specify both Aliased and Restrict for " + "PhysicalStorageBufferEXT pointer."; + } + } else { + const auto pointee_type_id = + param_nonarray_type->GetOperandAs(2); + const auto pointee_type = _.FindDef(pointee_type_id); + if (SpvOpTypePointer == pointee_type->opcode() && + pointee_type->GetOperandAs(1u) == + SpvStorageClassPhysicalStorageBufferEXT) { + // check for AliasedPointerEXT/RestrictPointerEXT + const auto& decorations = _.id_decorations(inst->id()); + + bool foundAliased = std::any_of( + decorations.begin(), decorations.end(), [](const Decoration& d) { + return SpvDecorationAliasedPointerEXT == d.dec_type(); + }); + + bool foundRestrict = std::any_of( + decorations.begin(), decorations.end(), [](const Decoration& d) { + return SpvDecorationRestrictPointerEXT == d.dec_type(); + }); + + if (!foundAliased && !foundRestrict) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpFunctionParameter " << inst->id() + << ": expected AliasedPointerEXT or RestrictPointerEXT for " + "PhysicalStorageBufferEXT pointer."; + } + if (foundAliased && foundRestrict) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpFunctionParameter " << inst->id() + << ": can't specify both AliasedPointerEXT and " + "RestrictPointerEXT for PhysicalStorageBufferEXT pointer."; + } + } + } + } + return SPV_SUCCESS; } diff --git a/3rdparty/spirv-tools/source/val/validate_logicals.cpp b/3rdparty/spirv-tools/source/val/validate_logicals.cpp index 9c637c423..a25460b51 100644 --- a/3rdparty/spirv-tools/source/val/validate_logicals.cpp +++ b/3rdparty/spirv-tools/source/val/validate_logicals.cpp @@ -154,7 +154,8 @@ spv_result_t LogicalsPass(ValidationState_t& _, const Instruction* inst) { const SpvOp type_opcode = type_inst->opcode(); switch (type_opcode) { case SpvOpTypePointer: { - if (!_.features().variable_pointers && + if (_.addressing_model() == SpvAddressingModelLogical && + !_.features().variable_pointers && !_.features().variable_pointers_storage_buffer) return _.diag(SPV_ERROR_INVALID_DATA, inst) << "Using pointers with OpSelect requires capability " diff --git a/3rdparty/spirv-tools/source/val/validate_memory.cpp b/3rdparty/spirv-tools/source/val/validate_memory.cpp index d1a64428c..2b0db56a1 100644 --- a/3rdparty/spirv-tools/source/val/validate_memory.cpp +++ b/3rdparty/spirv-tools/source/val/validate_memory.cpp @@ -277,7 +277,20 @@ uint32_t GetMakeVisibleScope(const Instruction* inst, uint32_t mask) { } spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst, - uint32_t mask) { + uint32_t index) { + SpvStorageClass dst_sc, src_sc; + std::tie(dst_sc, src_sc) = GetStorageClass(_, inst); + if (inst->operands().size() <= index) { + if (src_sc == SpvStorageClassPhysicalStorageBufferEXT || + dst_sc == SpvStorageClassPhysicalStorageBufferEXT) { + return _.diag(SPV_ERROR_INVALID_ID, inst) << "Memory accesses with " + "PhysicalStorageBufferEXT " + "must use Aligned."; + } + return SPV_SUCCESS; + } + + uint32_t mask = inst->GetOperandAs(index); if (mask & SpvMemoryAccessMakePointerAvailableKHRMask) { if (inst->opcode() == SpvOpLoad) { return _.diag(SPV_ERROR_INVALID_ID, inst) @@ -314,13 +327,12 @@ spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst, } if (mask & SpvMemoryAccessNonPrivatePointerKHRMask) { - SpvStorageClass dst_sc, src_sc; - std::tie(dst_sc, src_sc) = GetStorageClass(_, inst); if (dst_sc != SpvStorageClassUniform && dst_sc != SpvStorageClassWorkgroup && dst_sc != SpvStorageClassCrossWorkgroup && dst_sc != SpvStorageClassGeneric && dst_sc != SpvStorageClassImage && - dst_sc != SpvStorageClassStorageBuffer) { + dst_sc != SpvStorageClassStorageBuffer && + dst_sc != SpvStorageClassPhysicalStorageBufferEXT) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "NonPrivatePointerKHR requires a pointer in Uniform, " "Workgroup, CrossWorkgroup, Generic, Image or StorageBuffer " @@ -330,7 +342,8 @@ spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst, src_sc != SpvStorageClassWorkgroup && src_sc != SpvStorageClassCrossWorkgroup && src_sc != SpvStorageClassGeneric && src_sc != SpvStorageClassImage && - src_sc != SpvStorageClassStorageBuffer) { + src_sc != SpvStorageClassStorageBuffer && + src_sc != SpvStorageClassPhysicalStorageBufferEXT) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "NonPrivatePointerKHR requires a pointer in Uniform, " "Workgroup, CrossWorkgroup, Generic, Image or StorageBuffer " @@ -338,6 +351,15 @@ spv_result_t CheckMemoryAccess(ValidationState_t& _, const Instruction* inst, } } + if (!(mask & SpvMemoryAccessAlignedMask)) { + if (src_sc == SpvStorageClassPhysicalStorageBufferEXT || + dst_sc == SpvStorageClassPhysicalStorageBufferEXT) { + return _.diag(SPV_ERROR_INVALID_ID, inst) << "Memory accesses with " + "PhysicalStorageBufferEXT " + "must use Aligned."; + } + } + return SPV_SUCCESS; } @@ -414,7 +436,7 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } // Variable pointer related restrictions. - auto pointee = _.FindDef(result_type->word(3)); + const auto pointee = _.FindDef(result_type->word(3)); if (_.addressing_model() == SpvAddressingModelLogical && !_.options()->relax_logical_pointer) { // VariablePointersStorageBuffer is implied by VariablePointers. @@ -507,6 +529,125 @@ spv_result_t ValidateVariable(ValidationState_t& _, const Instruction* inst) { } } + // WebGPU: All variables with storage class Output, Private, or Function MUST + // have an initializer. + if (spvIsWebGPUEnv(_.context()->target_env) && inst->operands().size() <= 3 && + (storage_class == SpvStorageClassOutput || + storage_class == SpvStorageClassPrivate || + storage_class == SpvStorageClassFunction)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpVariable, '" << _.getIdName(inst->id()) + << "', must have an initializer.\n" + << "From WebGPU execution environment spec:\n" + << "All variables in the following storage classes must have an " + << "initializer: Output, Private, or Function"; + } + + if (storage_class == SpvStorageClassPhysicalStorageBufferEXT) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "PhysicalStorageBufferEXT must not be used with OpVariable."; + } + + auto pointee_base = pointee; + while (pointee_base->opcode() == SpvOpTypeArray) { + pointee_base = _.FindDef(pointee_base->GetOperandAs(1u)); + } + if (pointee_base->opcode() == SpvOpTypePointer) { + if (pointee_base->GetOperandAs(1u) == + SpvStorageClassPhysicalStorageBufferEXT) { + // check for AliasedPointerEXT/RestrictPointerEXT + bool foundAliased = + _.HasDecoration(inst->id(), SpvDecorationAliasedPointerEXT); + bool foundRestrict = + _.HasDecoration(inst->id(), SpvDecorationRestrictPointerEXT); + if (!foundAliased && !foundRestrict) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpVariable " << inst->id() + << ": expected AliasedPointerEXT or RestrictPointerEXT for " + "PhysicalStorageBufferEXT pointer."; + } + if (foundAliased && foundRestrict) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpVariable " << inst->id() + << ": can't specify both AliasedPointerEXT and " + "RestrictPointerEXT for PhysicalStorageBufferEXT pointer."; + } + } + } + + // Vulkan specific validation rules for OpTypeRuntimeArray + if (spvIsVulkanEnv(_.context()->target_env)) { + const auto type_index = 2; + const auto value_id = result_type->GetOperandAs(type_index); + auto value_type = _.FindDef(value_id); + // OpTypeRuntimeArray should only ever be in a container like OpTypeStruct, + // so should never appear as a bare variable. + // Unless the module has the RuntimeDescriptorArrayEXT capability. + if (value_type && value_type->opcode() == SpvOpTypeRuntimeArray) { + if (!_.HasCapability(SpvCapabilityRuntimeDescriptorArrayEXT)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpVariable, '" << _.getIdName(inst->id()) + << "', is attempting to create memory for an illegal type, " + "OpTypeRuntimeArray.\nFor Vulkan OpTypeRuntimeArray can only " + "appear as the final member of an OpTypeStruct, thus cannot " + "be instantiated via OpVariable"; + } else { + // A bare variable OpTypeRuntimeArray is allowed in this context, but + // still need to check the storage class. + if (storage_class != SpvStorageClassStorageBuffer && + storage_class != SpvStorageClassUniform && + storage_class != SpvStorageClassUniformConstant) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "For Vulkan with RuntimeDescriptorArrayEXT, a variable " + "containing OpTypeRuntimeArray must have storage class of " + "StorageBuffer, Uniform, or UniformConstant."; + } + } + } + + // If an OpStruct has an OpTypeRuntimeArray somewhere within it, then it + // must either have the storage class StorageBuffer and be decorated + // with Block, or it must be in the Uniform storage class and be decorated + // as BufferBlock. + if (value_type && value_type->opcode() == SpvOpTypeStruct) { + bool contains_RTA = false; + for (size_t member_type_index = 1; + member_type_index < value_type->operands().size(); + ++member_type_index) { + const auto member_type_id = + value_type->GetOperandAs(member_type_index); + const auto member_type = _.FindDef(member_type_id); + if (member_type->opcode() == SpvOpTypeRuntimeArray) { + contains_RTA = true; + break; + } + } + + if (contains_RTA) { + if (storage_class == SpvStorageClassStorageBuffer) { + if (!_.HasDecoration(value_id, SpvDecorationBlock)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "For Vulkan, an OpTypeStruct variable containing an " + "OpTypeRuntimeArray must be decorated with Block if it " + "has storage class StorageBuffer."; + } + } else if (storage_class == SpvStorageClassUniform) { + if (!_.HasDecoration(value_id, SpvDecorationBufferBlock)) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "For Vulkan, an OpTypeStruct variable containing an " + "OpTypeRuntimeArray must be decorated with BufferBlock " + "if it has storage class Uniform."; + } + } else { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "For Vulkan, OpTypeStruct variables containing " + "OpTypeRuntimeArray must have storage class of " + "StorageBuffer or Uniform."; + } + } + } + } + return SPV_SUCCESS; } @@ -550,11 +691,7 @@ spv_result_t ValidateLoad(ValidationState_t& _, const Instruction* inst) { << "'s type."; } - if (inst->operands().size() > 3) { - if (auto error = - CheckMemoryAccess(_, inst, inst->GetOperandAs(3))) - return error; - } + if (auto error = CheckMemoryAccess(_, inst, 3)) return error; return SPV_SUCCESS; } @@ -642,11 +779,7 @@ spv_result_t ValidateStore(ValidationState_t& _, const Instruction* inst) { } } - if (inst->operands().size() > 2) { - if (auto error = - CheckMemoryAccess(_, inst, inst->GetOperandAs(2))) - return error; - } + if (auto error = CheckMemoryAccess(_, inst, 2)) return error; return SPV_SUCCESS; } @@ -710,11 +843,7 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction* inst) { << _.getIdName(source_type->id()) << "'s type."; } - if (inst->operands().size() > 2) { - if (auto error = - CheckMemoryAccess(_, inst, inst->GetOperandAs(2))) - return error; - } + if (auto error = CheckMemoryAccess(_, inst, 2)) return error; } else { const auto size_id = inst->GetOperandAs(2); const auto size = _.FindDef(size_id); @@ -758,11 +887,7 @@ spv_result_t ValidateCopyMemory(ValidationState_t& _, const Instruction* inst) { break; } - if (inst->operands().size() > 3) { - if (auto error = - CheckMemoryAccess(_, inst, inst->GetOperandAs(3))) - return error; - } + if (auto error = CheckMemoryAccess(_, inst, 3)) return error; } return SPV_SUCCESS; } diff --git a/3rdparty/spirv-tools/source/val/validate_type.cpp b/3rdparty/spirv-tools/source/val/validate_type.cpp index e0f278636..6dbca3946 100644 --- a/3rdparty/spirv-tools/source/val/validate_type.cpp +++ b/3rdparty/spirv-tools/source/val/validate_type.cpp @@ -17,6 +17,7 @@ #include "source/val/validate.h" #include "source/opcode.h" +#include "source/spirv_target_env.h" #include "source/val/instruction.h" #include "source/val/validation_state.h" @@ -106,6 +107,13 @@ spv_result_t ValidateTypeArray(ValidationState_t& _, const Instruction* inst) { << "' is a void type."; } + if (spvIsVulkanEnv(_.context()->target_env) && + element_type->opcode() == SpvOpTypeRuntimeArray) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpTypeArray Element Type '" << _.getIdName(element_type_id) + << "' is not valid in Vulkan environment."; + } + const auto length_index = 2; const auto length_id = inst->GetOperandAs(length_index); const auto length = _.FindDef(length_id); @@ -161,6 +169,14 @@ spv_result_t ValidateTypeRuntimeArray(ValidationState_t& _, << _.getIdName(element_id) << "' is a void type."; } + if (spvIsVulkanEnv(_.context()->target_env) && + element_type->opcode() == SpvOpTypeRuntimeArray) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "OpTypeRuntimeArray Element Type '" + << _.getIdName(element_id) + << "' is not valid in Vulkan environment."; + } + return SPV_SUCCESS; } @@ -206,7 +222,19 @@ spv_result_t ValidateTypeStruct(ValidationState_t& _, const Instruction* inst) { << "."; } } + + if (spvIsVulkanEnv(_.context()->target_env) && + member_type->opcode() == SpvOpTypeRuntimeArray) { + const bool is_last_member = + member_type_index == inst->operands().size() - 1; + if (!is_last_member) { + return _.diag(SPV_ERROR_INVALID_ID, inst) + << "In Vulkan, OpTypeRuntimeArray must only be used for the " + "last member of an OpTypeStruct"; + } + } } + std::unordered_set built_in_members; for (auto decoration : _.id_decorations(struct_id)) { if (decoration.dec_type() == SpvDecorationBuiltIn && diff --git a/3rdparty/spirv-tools/source/val/validation_state.cpp b/3rdparty/spirv-tools/source/val/validation_state.cpp index a10186fb5..4a4293546 100644 --- a/3rdparty/spirv-tools/source/val/validation_state.cpp +++ b/3rdparty/spirv-tools/source/val/validation_state.cpp @@ -171,6 +171,7 @@ ValidationState_t::ValidationState_t(const spv_const_context ctx, grammar_(ctx), addressing_model_(SpvAddressingModelMax), memory_model_(SpvMemoryModelMax), + pointer_size_and_alignment_(0), in_function_(false), num_of_warnings_(0), max_num_of_warnings_(max_warnings) { @@ -411,6 +412,11 @@ void ValidationState_t::RegisterExtension(Extension ext) { // https://github.com/KhronosGroup/SPIRV-Tools/issues/1375 features_.declare_float16_type = true; break; + case kSPV_AMD_gpu_shader_int16: + // This is not yet in the extension, but it's recommended for it. + // See https://github.com/KhronosGroup/glslang/issues/848 + features_.uconvert_spec_constant_op = true; + break; case kSPV_AMD_shader_ballot: // The grammar doesn't encode the fact that SPV_AMD_shader_ballot // enables the use of group operations Reduce, InclusiveScan, @@ -435,6 +441,17 @@ bool ValidationState_t::HasAnyOfExtensions( void ValidationState_t::set_addressing_model(SpvAddressingModel am) { addressing_model_ = am; + switch (am) { + case SpvAddressingModelPhysical32: + pointer_size_and_alignment_ = 4; + break; + default: + // fall through + case SpvAddressingModelPhysical64: + case SpvAddressingModelPhysicalStorageBuffer64EXT: + pointer_size_and_alignment_ = 8; + break; + } } SpvAddressingModel ValidationState_t::addressing_model() const { diff --git a/3rdparty/spirv-tools/source/val/validation_state.h b/3rdparty/spirv-tools/source/val/validation_state.h index 85229f2da..2c94906b9 100644 --- a/3rdparty/spirv-tools/source/val/validation_state.h +++ b/3rdparty/spirv-tools/source/val/validation_state.h @@ -15,6 +15,7 @@ #ifndef SOURCE_VAL_VALIDATION_STATE_H_ #define SOURCE_VAL_VALIDATION_STATE_H_ +#include #include #include #include @@ -104,6 +105,10 @@ class ValidationState_t { // - ArrayStride and MatrixStride are multiples of scalar alignment // Members need not be listed in offset order bool scalar_block_layout = false; + + // Permit UConvert as an OpSpecConstantOp operation. + // The Kernel capability already enables it, separately from this flag. + bool uconvert_spec_constant_op = false; }; ValidationState_t(const spv_const_context context, @@ -339,6 +344,11 @@ class ValidationState_t { /// Returns the addressing model of this module, or Logical if uninitialized. SpvAddressingModel addressing_model() const; + /// Returns the addressing model of this module, or Logical if uninitialized. + uint32_t pointer_size_and_alignment() const { + return pointer_size_and_alignment_; + } + /// Sets the memory model of this module. void set_memory_model(SpvMemoryModel mm); @@ -387,17 +397,23 @@ class ValidationState_t { std::vector& id_decorations(uint32_t id) { return id_decorations_[id]; } - const std::vector& id_decorations(uint32_t id) const { - // TODO: This would throw or generate SIGABRT if id has no - // decorations. Remove/refactor this function. - return id_decorations_.at(id); - } // Returns const pointer to the internal decoration container. const std::map>& id_decorations() const { return id_decorations_; } + /// Returns true if the given id has the given decoration , + /// otherwise returns false. + bool HasDecoration(uint32_t id, SpvDecoration dec) { + const auto& decorations = id_decorations_.find(id); + if (decorations == id_decorations_.end()) return false; + + return std::any_of( + decorations->second.begin(), decorations->second.end(), + [dec](const Decoration& d) { return dec == d.dec_type(); }); + } + /// Finds id's def, if it exists. If found, returns the definition otherwise /// nullptr const Instruction* FindDef(uint32_t id) const; @@ -656,6 +672,9 @@ class ValidationState_t { SpvAddressingModel addressing_model_; SpvMemoryModel memory_model_; + // pointer size derived from addressing model. Assumes all storage classes + // have the same pointer size (for physical pointer types). + uint32_t pointer_size_and_alignment_; /// NOTE: See correspoding getter functions bool in_function_; diff --git a/3rdparty/spirv-tools/test/binary_parse_test.cpp b/3rdparty/spirv-tools/test/binary_parse_test.cpp index dfff79df4..749e12fd6 100644 --- a/3rdparty/spirv-tools/test/binary_parse_test.cpp +++ b/3rdparty/spirv-tools/test/binary_parse_test.cpp @@ -197,6 +197,8 @@ ParsedInstruction MakeParsedInt32TypeInstruction(uint32_t result_id) { class BinaryParseTest : public spvtest::TextToBinaryTestBase<::testing::Test> { protected: + ~BinaryParseTest() { spvDiagnosticDestroy(diagnostic_); } + void Parse(const SpirvVector& words, spv_result_t expected_result, bool flip_words = false) { SpirvVector flipped_words(words); diff --git a/3rdparty/spirv-tools/test/binary_to_text_test.cpp b/3rdparty/spirv-tools/test/binary_to_text_test.cpp index 016041f49..00ac86bbd 100644 --- a/3rdparty/spirv-tools/test/binary_to_text_test.cpp +++ b/3rdparty/spirv-tools/test/binary_to_text_test.cpp @@ -34,8 +34,12 @@ using ::testing::HasSubstr; class BinaryToText : public ::testing::Test { public: - BinaryToText() : context(spvContextCreate(SPV_ENV_UNIVERSAL_1_0)) {} - ~BinaryToText() { spvContextDestroy(context); } + BinaryToText() + : context(spvContextCreate(SPV_ENV_UNIVERSAL_1_0)), binary(nullptr) {} + ~BinaryToText() { + spvBinaryDestroy(binary); + spvContextDestroy(context); + } virtual void SetUp() { const char* textStr = R"( @@ -63,17 +67,20 @@ class BinaryToText : public ::testing::Test { spv_diagnostic diagnostic = nullptr; spv_result_t error = spvTextToBinary(context, text.str, text.length, &binary, &diagnostic); - if (error) { - spvDiagnosticPrint(diagnostic); - spvDiagnosticDestroy(diagnostic); - ASSERT_EQ(SPV_SUCCESS, error); - } + spvDiagnosticPrint(diagnostic); + spvDiagnosticDestroy(diagnostic); + ASSERT_EQ(SPV_SUCCESS, error); } - virtual void TearDown() { spvBinaryDestroy(binary); } + virtual void TearDown() { + spvBinaryDestroy(binary); + binary = nullptr; + } // Compiles the given assembly text, and saves it into 'binary'. void CompileSuccessfully(std::string text) { + spvBinaryDestroy(binary); + binary = nullptr; spv_diagnostic diagnostic = nullptr; EXPECT_EQ(SPV_SUCCESS, spvTextToBinary(context, text.c_str(), text.size(), &binary, &diagnostic)); diff --git a/3rdparty/spirv-tools/test/ext_inst.glsl_test.cpp b/3rdparty/spirv-tools/test/ext_inst.glsl_test.cpp index 991c487f1..f52337c61 100644 --- a/3rdparty/spirv-tools/test/ext_inst.glsl_test.cpp +++ b/3rdparty/spirv-tools/test/ext_inst.glsl_test.cpp @@ -61,7 +61,7 @@ OpFunctionEnd ; Generator: Khronos SPIR-V Tools Assembler; 0 ; Bound: 9 ; Schema: 0)"; - spv_binary binary; + spv_binary binary = nullptr; spv_diagnostic diagnostic; spv_result_t error = spvTextToBinary(context, spirv.c_str(), spirv.size(), &binary, &diagnostic); @@ -102,6 +102,7 @@ OpFunctionEnd } EXPECT_EQ(spirv_header + spirv, output_text->str); spvTextDestroy(output_text); + spvBinaryDestroy(binary); spvContextDestroy(context); } diff --git a/3rdparty/spirv-tools/test/opt/CMakeLists.txt b/3rdparty/spirv-tools/test/opt/CMakeLists.txt index 1e32df38c..827f5011d 100644 --- a/3rdparty/spirv-tools/test/opt/CMakeLists.txt +++ b/3rdparty/spirv-tools/test/opt/CMakeLists.txt @@ -81,6 +81,7 @@ add_spvtools_unittest(TARGET opt type_manager_test.cpp types_test.cpp unify_const_test.cpp + upgrade_memory_model_test.cpp utils_test.cpp pass_utils.cpp value_table_test.cpp vector_dce_test.cpp @@ -88,9 +89,3 @@ add_spvtools_unittest(TARGET opt LIBS SPIRV-Tools-opt PCH_FILE pch_test_opt ) - -add_spvtools_unittest(TARGET upgrade_memory_model - SRCS upgrade_memory_model_test.cpp pass_utils.cpp - LIBS SPIRV-Tools-opt - PCH_FILE pch_test_opt -) diff --git a/3rdparty/spirv-tools/test/opt/fold_test.cpp b/3rdparty/spirv-tools/test/opt/fold_test.cpp index 1a5442181..88248ba79 100644 --- a/3rdparty/spirv-tools/test/opt/fold_test.cpp +++ b/3rdparty/spirv-tools/test/opt/fold_test.cpp @@ -168,6 +168,7 @@ OpName %main "main" %int_2 = OpConstant %int 2 %int_3 = OpConstant %int 3 %int_4 = OpConstant %int 4 +%int_n24 = OpConstant %int -24 %int_min = OpConstant %int -2147483648 %int_max = OpConstant %int 2147483647 %long_0 = OpConstant %long 0 @@ -486,7 +487,7 @@ INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, 0), - // Test case 21: fold signed n >> 42 (undefined, so set to zero). + // Test case 23: fold signed n >> 42 (undefined, so set to zero). InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -496,7 +497,7 @@ INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTest, "OpReturn\n" + "OpFunctionEnd", 2, 0), - // Test case 22: fold n << 42 (undefined, so set to zero). + // Test case 24: fold n << 42 (undefined, so set to zero). InstructionFoldingCase( Header() + "%main = OpFunction %void None %void_func\n" + "%main_lab = OpLabel\n" + @@ -505,6 +506,38 @@ INSTANTIATE_TEST_CASE_P(TestCase, IntegerInstructionFoldingTest, "%2 = OpShiftLeftLogical %int %load %uint_42\n" + "OpReturn\n" + "OpFunctionEnd", + 2, 0), + // Test case 25: fold -24 >> 32 (defined as -1) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpShiftRightArithmetic %int %int_n24 %uint_32\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, -1), + // Test case 26: fold 2 >> 32 (signed) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpShiftRightArithmetic %int %int_2 %uint_32\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 27: fold 2 >> 32 (unsigned) + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpShiftRightLogical %int %int_2 %uint_32\n" + + "OpReturn\n" + + "OpFunctionEnd", + 2, 0), + // Test case 28: fold 2 << 32 + InstructionFoldingCase( + Header() + "%main = OpFunction %void None %void_func\n" + + "%main_lab = OpLabel\n" + + "%2 = OpShiftLeftLogical %int %int_2 %uint_32\n" + + "OpReturn\n" + + "OpFunctionEnd", 2, 0) )); // clang-format on diff --git a/3rdparty/spirv-tools/test/opt/inst_bindless_check_test.cpp b/3rdparty/spirv-tools/test/opt/inst_bindless_check_test.cpp index 1a1a19478..a426ce04c 100644 --- a/3rdparty/spirv-tools/test/opt/inst_bindless_check_test.cpp +++ b/3rdparty/spirv-tools/test/opt/inst_bindless_check_test.cpp @@ -92,7 +92,8 @@ OpDecorate %_entryPointOutput_vColor Location 0 )"; const std::string new_annots = - R"(OpDecorate %_struct_55 Block + R"(OpDecorate %_runtimearr_uint ArrayStride 4 +OpDecorate %_struct_55 Block OpMemberDecorate %_struct_55 0 Offset 0 OpMemberDecorate %_struct_55 1 Offset 4 OpDecorate %57 DescriptorSet 7 @@ -441,6 +442,7 @@ OpDecorate %PerViewConstantBuffer_t Block OpDecorate %g_sAniso DescriptorSet 0 OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 OpDecorate %_struct_63 Block OpMemberDecorate %_struct_63 0 Offset 0 OpMemberDecorate %_struct_63 1 Offset 4 @@ -735,6 +737,7 @@ OpDecorate %_entryPointOutput_vColor Location 0 OpDecorate %10 DescriptorSet 7 OpDecorate %10 Binding 0 OpDecorate %gl_FragCoord BuiltIn FragCoord +OpDecorate %_runtimearr_uint ArrayStride 4 OpDecorate %_struct_34 Block OpMemberDecorate %_struct_34 0 Offset 0 OpMemberDecorate %_struct_34 1 Offset 4 @@ -968,6 +971,7 @@ OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 OpDecorate %PerViewConstantBuffer_t Block OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 OpDecorate %_struct_51 Block OpMemberDecorate %_struct_51 0 Offset 0 OpMemberDecorate %_struct_51 1 Offset 4 @@ -1193,6 +1197,7 @@ OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 OpDecorate %PerViewConstantBuffer_t Block OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 OpDecorate %_struct_49 Block OpMemberDecorate %_struct_49 0 Offset 0 OpMemberDecorate %_struct_49 1 Offset 4 @@ -1418,6 +1423,7 @@ OpMemberDecorate %PerViewConstantBuffer_t 0 Offset 0 OpDecorate %PerViewConstantBuffer_t Block OpDecorate %i_vTextureCoords Location 0 OpDecorate %_entryPointOutput_vColor Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 OpDecorate %_struct_48 Block OpMemberDecorate %_struct_48 0 Offset 0 OpMemberDecorate %_struct_48 1 Offset 4 @@ -1644,7 +1650,7 @@ OpCapability Sampled1D OpExtension "SPV_KHR_storage_buffer_storage_class" %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 -OpEntryPoint Vertex %main "main" %_ %coords2D %gl_VertexID %gl_InstanceID +OpEntryPoint Vertex %main "main" %_ %coords2D %gl_VertexIndex %gl_InstanceIndex OpSource GLSL 450 OpName %main "main" OpName %lod "lod" @@ -1672,13 +1678,14 @@ OpDecorate %foo Block OpDecorate %__0 DescriptorSet 0 OpDecorate %__0 Binding 5 OpDecorate %coords2D Location 0 +OpDecorate %_runtimearr_uint ArrayStride 4 OpDecorate %_struct_61 Block OpMemberDecorate %_struct_61 0 Offset 0 OpMemberDecorate %_struct_61 1 Offset 4 OpDecorate %63 DescriptorSet 7 OpDecorate %63 Binding 0 -OpDecorate %gl_VertexID BuiltIn VertexId -OpDecorate %gl_InstanceID BuiltIn InstanceId +OpDecorate %gl_VertexIndex BuiltIn VertexIndex +OpDecorate %gl_InstanceIndex BuiltIn InstanceIndex %void = OpTypeVoid %12 = OpTypeFunction %void %float = OpTypeFloat 32 @@ -1723,8 +1730,8 @@ OpDecorate %gl_InstanceID BuiltIn InstanceId %uint_2 = OpConstant %uint 2 %uint_3 = OpConstant %uint 3 %_ptr_Input_uint = OpTypePointer Input %uint -%gl_VertexID = OpVariable %_ptr_Input_uint Input -%gl_InstanceID = OpVariable %_ptr_Input_uint Input +%gl_VertexIndex = OpVariable %_ptr_Input_uint Input +%gl_InstanceIndex = OpVariable %_ptr_Input_uint Input %uint_5 = OpConstant %uint 5 %uint_6 = OpConstant %uint 6 %uint_7 = OpConstant %uint 7 @@ -1812,11 +1819,11 @@ OpStore %81 %55 %83 = OpIAdd %uint %68 %uint_3 %84 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %83 OpStore %84 %uint_0 -%87 = OpLoad %uint %gl_VertexID +%87 = OpLoad %uint %gl_VertexIndex %88 = OpIAdd %uint %68 %uint_4 %89 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %88 OpStore %89 %87 -%91 = OpLoad %uint %gl_InstanceID +%91 = OpLoad %uint %gl_InstanceIndex %93 = OpIAdd %uint %68 %uint_5 %94 = OpAccessChain %_ptr_StorageBuffer_uint %63 %uint_1 %93 OpStore %94 %91 diff --git a/3rdparty/spirv-tools/test/opt/pass_fixture.h b/3rdparty/spirv-tools/test/opt/pass_fixture.h index da2e00ee8..117bc3126 100644 --- a/3rdparty/spirv-tools/test/opt/pass_fixture.h +++ b/3rdparty/spirv-tools/test/opt/pass_fixture.h @@ -49,7 +49,7 @@ class PassTest : public TestT { [](spv_message_level_t, const char*, const spv_position_t&, const char* message) { std::cerr << message << std::endl; }), context_(nullptr), - tools_(SPV_ENV_UNIVERSAL_1_1), + tools_(SPV_ENV_UNIVERSAL_1_3), manager_(new PassManager()), assemble_options_(SpirvTools::kDefaultAssembleOption), disassemble_options_(SpirvTools::kDefaultDisassembleOption) {} @@ -59,7 +59,7 @@ class PassTest : public TestT { // from pass Process() function. std::tuple, Pass::Status> OptimizeToBinary( Pass* pass, const std::string& original, bool skip_nop) { - context_ = std::move(BuildModule(SPV_ENV_UNIVERSAL_1_1, consumer_, original, + context_ = std::move(BuildModule(SPV_ENV_UNIVERSAL_1_3, consumer_, original, assemble_options_)); EXPECT_NE(nullptr, context()) << "Assembling failed for shader:\n" << original << std::endl; @@ -97,7 +97,7 @@ class PassTest : public TestT { std::tie(optimized_bin, status) = SinglePassRunToBinary( assembly, skip_nop, std::forward(args)...); if (do_validation) { - spv_target_env target_env = SPV_ENV_UNIVERSAL_1_1; + spv_target_env target_env = SPV_ENV_UNIVERSAL_1_3; spv_context spvContext = spvContextCreate(target_env); spv_diagnostic diagnostic = nullptr; spv_const_binary_t binary = {optimized_bin.data(), optimized_bin.size()}; @@ -134,7 +134,7 @@ class PassTest : public TestT { EXPECT_EQ(original == expected, status == Pass::Status::SuccessWithoutChange); if (do_validation) { - spv_target_env target_env = SPV_ENV_UNIVERSAL_1_1; + spv_target_env target_env = SPV_ENV_UNIVERSAL_1_3; spv_context spvContext = spvContextCreate(target_env); spv_diagnostic diagnostic = nullptr; spv_const_binary_t binary = {optimized_bin.data(), optimized_bin.size()}; @@ -202,7 +202,7 @@ class PassTest : public TestT { void RunAndCheck(const std::string& original, const std::string& expected) { assert(manager_->NumPasses()); - context_ = std::move(BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, original, + context_ = std::move(BuildModule(SPV_ENV_UNIVERSAL_1_3, nullptr, original, assemble_options_)); ASSERT_NE(nullptr, context()); diff --git a/3rdparty/spirv-tools/test/opt/upgrade_memory_model_test.cpp b/3rdparty/spirv-tools/test/opt/upgrade_memory_model_test.cpp index 90ad601d7..9d2d7627d 100644 --- a/3rdparty/spirv-tools/test/opt/upgrade_memory_model_test.cpp +++ b/3rdparty/spirv-tools/test/opt/upgrade_memory_model_test.cpp @@ -23,7 +23,6 @@ using namespace spvtools; using UpgradeMemoryModelTest = opt::PassTest<::testing::Test>; -#ifdef SPIRV_EFFCEE TEST_F(UpgradeMemoryModelTest, InvalidMemoryModelOpenCL) { const std::string text = R"( ; CHECK: OpMemoryModel Logical OpenCL @@ -80,8 +79,8 @@ OpDecorate %var Coherent TEST_F(UpgradeMemoryModelTest, WorkgroupVariable) { const std::string text = R"( ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 2 -; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpMemoryModel Logical GLSL450 @@ -104,8 +103,8 @@ OpFunctionEnd TEST_F(UpgradeMemoryModelTest, WorkgroupFunctionParameter) { const std::string text = R"( ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 2 -; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpMemoryModel Logical GLSL450 @@ -129,8 +128,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformVariable) { const std::string text = R"( ; CHECK-NOT: OpDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpMemoryModel Logical GLSL450 @@ -156,8 +155,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformFunctionParameter) { const std::string text = R"( ; CHECK-NOT: OpDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpMemoryModel Logical GLSL450 @@ -209,8 +208,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformVariableCopied) { const std::string text = R"( ; CHECK-NOT: OpDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpMemoryModel Logical GLSL450 @@ -237,8 +236,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformFunctionParameterCopied) { const std::string text = R"( ; CHECK-NOT: OpDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpMemoryModel Logical GLSL450 @@ -266,8 +265,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformVariableAccessChain) { const std::string text = R"( ; CHECK-NOT: OpDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpMemoryModel Logical GLSL450 @@ -298,8 +297,8 @@ TEST_F(UpgradeMemoryModelTest, SimpleUniformFunctionParameterAccessChain) { const std::string text = R"( ; CHECK-NOT: OpDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpMemoryModel Logical GLSL450 @@ -331,8 +330,8 @@ TEST_F(UpgradeMemoryModelTest, VariablePointerSelect) { const std::string text = R"( ; CHECK-NOT: OpDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpCapability VariablePointers @@ -364,8 +363,8 @@ TEST_F(UpgradeMemoryModelTest, VariablePointerSelectConservative) { const std::string text = R"( ; CHECK-NOT: OpDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} Volatile|MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} Volatile|MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpCapability VariablePointers @@ -397,8 +396,8 @@ TEST_F(UpgradeMemoryModelTest, VariablePointerIncrement) { const std::string text = R"( ; CHECK-NOT: OpDecorate {{%\w+}} Coherent ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpCapability VariablePointers @@ -440,8 +439,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentStructElement) { const std::string text = R"( ; CHECK-NOT: OpMemberDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpExtension "SPV_KHR_storage_buffer_storage_class" @@ -471,8 +470,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentElementFullStructAccess) { const std::string text = R"( ; CHECK-NOT: OpMemberDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpExtension "SPV_KHR_storage_buffer_storage_class" @@ -530,8 +529,8 @@ TEST_F(UpgradeMemoryModelTest, MultiIndexAccessCoherent) { const std::string text = R"( ; CHECK-NOT: OpMemberDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpExtension "SPV_KHR_storage_buffer_storage_class" @@ -600,8 +599,8 @@ TEST_F(UpgradeMemoryModelTest, ConsecutiveAccessChainCoherent) { const std::string text = R"( ; CHECK-NOT: OpMemberDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpExtension "SPV_KHR_storage_buffer_storage_class" @@ -682,8 +681,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentStructElementAccess) { const std::string text = R"( ; CHECK-NOT: OpMemberDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpExtension "SPV_KHR_storage_buffer_storage_class" @@ -723,8 +722,8 @@ TEST_F(UpgradeMemoryModelTest, NonCoherentLoadCoherentStore) { const std::string text = R"( ; CHECK-NOT: OpMemberDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK-NOT: MakePointerAvailableKHR -; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK-NOT: MakePointerVisibleKHR +; CHECK: OpStore {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] OpCapability Shader OpCapability Linkage OpExtension "SPV_KHR_storage_buffer_storage_class" @@ -823,7 +822,7 @@ TEST_F(UpgradeMemoryModelTest, CopyMemoryTwoScopes) { ; CHECK-NOT: OpDecorate ; CHECK-DAG: [[queuefamily:%\w+]] = OpConstant {{%\w+}} 5 ; CHECK-DAG: [[workgroup:%\w+]] = OpConstant {{%\w+}} 2 -; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailableKHR|MakePointerVisibleKHR|NonPrivatePointerKHR [[queuefamily]] [[workgroup]] +; CHECK: OpCopyMemory {{%\w+}} {{%\w+}} MakePointerAvailableKHR|MakePointerVisibleKHR|NonPrivatePointerKHR [[workgroup]] [[queuefamily]] OpCapability Shader OpCapability Linkage OpExtension "SPV_KHR_storage_buffer_storage_class" @@ -883,8 +882,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentImageRead) { const std::string text = R"( ; CHECK-NOT: OpDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]] OpCapability Shader OpCapability Linkage OpCapability StorageImageReadWithoutFormat @@ -917,9 +916,9 @@ TEST_F(UpgradeMemoryModelTest, CoherentImageReadExtractedFromSampledImage) { ; CHECK-NOT: OpDecorate ; CHECK: [[image:%\w+]] = OpTypeImage ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad [[image]] {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad [[image]] {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] ; CHECK-NOT: NonPrivatePointerKHR -; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]] +; CHECK: OpImageRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]] OpCapability Shader OpCapability Linkage OpCapability StorageImageReadWithoutFormat @@ -990,8 +989,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentImageWrite) { const std::string text = R"( ; CHECK-NOT: OpDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR -; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR +; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]] OpCapability Shader OpCapability Linkage OpCapability StorageImageWriteWithoutFormat @@ -1023,9 +1022,9 @@ TEST_F(UpgradeMemoryModelTest, CoherentImageWriteExtractFromSampledImage) { const std::string text = R"( ; CHECK-NOT: OpDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR ; CHECK-NOT: NonPrivatePointerKHR -; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]] +; CHECK: OpImageWrite {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]] OpCapability Shader OpCapability Linkage OpCapability StorageImageWriteWithoutFormat @@ -1098,8 +1097,8 @@ TEST_F(UpgradeMemoryModelTest, CoherentImageSparseRead) { const std::string text = R"( ; CHECK-NOT: OpDecorate ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] -; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]] +; CHECK: OpLoad {{%\w+}} {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]] OpCapability Shader OpCapability Linkage OpCapability StorageImageReadWithoutFormat @@ -1135,9 +1134,9 @@ TEST_F(UpgradeMemoryModelTest, ; CHECK-NOT: OpDecorate ; CHECK: [[image:%\w+]] = OpTypeImage ; CHECK: [[scope:%\w+]] = OpConstant {{%\w+}} 5 -; CHECK: OpLoad [[image]] {{%\w+}} MakePointerAvailableKHR|NonPrivatePointerKHR [[scope]] +; CHECK: OpLoad [[image]] {{%\w+}} MakePointerVisibleKHR|NonPrivatePointerKHR [[scope]] ; CHECK-NOT: NonPrivatePointerKHR -; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelAvailableKHR|NonPrivateTexelKHR [[scope]] +; CHECK: OpImageSparseRead {{%\w+}} {{%\w+}} {{%\w+}} MakeTexelVisibleKHR|NonPrivateTexelKHR [[scope]] OpCapability Shader OpCapability Linkage OpCapability StorageImageReadWithoutFormat @@ -1430,6 +1429,288 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } -#endif +TEST_F(UpgradeMemoryModelTest, UpgradeModfNoFlags) { + const std::string text = R"( +; CHECK: [[float:%\w+]] = OpTypeFloat 32 +; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[float]] +; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer +; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[float]] +; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]] +; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0 +; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1 +; CHECK: OpStore [[var]] [[ex1]] +; CHECK-NOT: NonPrivatePointerKHR +; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +%import = OpExtInstImport "GLSL.std.450" +OpEntryPoint GLCompute %func "func" +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%ptr_ssbo_float = OpTypePointer StorageBuffer %float +%ssbo_var = OpVariable %ptr_ssbo_float StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%2 = OpExtInst %float %import Modf %float_0 %ssbo_var +%3 = OpFAdd %float %float_0 %2 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, UpgradeModfWorkgroupCoherent) { + const std::string text = R"( +; CHECK: [[float:%\w+]] = OpTypeFloat 32 +; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer Workgroup [[float]] +; CHECK: [[var:%\w+]] = OpVariable [[ptr]] Workgroup +; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[float]] +; CHECK: [[wg_scope:%\w+]] = OpConstant {{%\w+}} 2 +; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]] +; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0 +; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1 +; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailableKHR|NonPrivatePointerKHR [[wg_scope]] +; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +%import = OpExtInstImport "GLSL.std.450" +OpEntryPoint GLCompute %func "func" +OpDecorate %wg_var Coherent +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%ptr_wg_float = OpTypePointer Workgroup %float +%wg_var = OpVariable %ptr_wg_float Workgroup +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%2 = OpExtInst %float %import Modf %float_0 %wg_var +%3 = OpFAdd %float %float_0 %2 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, UpgradeModfSSBOCoherent) { + const std::string text = R"( +; CHECK: [[float:%\w+]] = OpTypeFloat 32 +; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[float]] +; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer +; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[float]] +; CHECK: [[qf_scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]] +; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0 +; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1 +; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailableKHR|NonPrivatePointerKHR [[qf_scope]] +; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +%import = OpExtInstImport "GLSL.std.450" +OpEntryPoint GLCompute %func "func" +OpDecorate %ssbo_var Coherent +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%ptr_ssbo_float = OpTypePointer StorageBuffer %float +%ssbo_var = OpVariable %ptr_ssbo_float StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%2 = OpExtInst %float %import Modf %float_0 %ssbo_var +%3 = OpFAdd %float %float_0 %2 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, UpgradeModfSSBOVolatile) { + const std::string text = R"( +; CHECK: [[float:%\w+]] = OpTypeFloat 32 +; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[float]] +; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer +; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[float]] +; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} ModfStruct [[float_0]] +; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0 +; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 1 +; CHECK: OpStore [[var]] [[ex1]] Volatile +; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +%import = OpExtInstImport "GLSL.std.450" +OpEntryPoint GLCompute %func "func" +OpDecorate %wg_var Volatile +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%ptr_ssbo_float = OpTypePointer StorageBuffer %float +%wg_var = OpVariable %ptr_ssbo_float StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%2 = OpExtInst %float %import Modf %float_0 %wg_var +%3 = OpFAdd %float %float_0 %2 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, UpgradeFrexpNoFlags) { + const std::string text = R"( +; CHECK: [[float:%\w+]] = OpTypeFloat 32 +; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0 +; CHECK: [[int:%\w+]] = OpTypeInt 32 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[int]] +; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer +; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[int]] +; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]] +; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0 +; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1 +; CHECK: OpStore [[var]] [[ex1]] +; CHECK-NOT: NonPrivatePointerKHR +; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +%import = OpExtInstImport "GLSL.std.450" +OpEntryPoint GLCompute %func "func" +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%2 = OpExtInst %float %import Frexp %float_0 %ssbo_var +%3 = OpFAdd %float %float_0 %2 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, UpgradeFrexpWorkgroupCoherent) { + const std::string text = R"( +; CHECK: [[float:%\w+]] = OpTypeFloat 32 +; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0 +; CHECK: [[int:%\w+]] = OpTypeInt 32 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer Workgroup [[int]] +; CHECK: [[var:%\w+]] = OpVariable [[ptr]] Workgroup +; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[int]] +; CHECK: [[wg_scope:%\w+]] = OpConstant {{%\w+}} 2 +; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]] +; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0 +; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1 +; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailableKHR|NonPrivatePointerKHR [[wg_scope]] +; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +%import = OpExtInstImport "GLSL.std.450" +OpEntryPoint GLCompute %func "func" +OpDecorate %wg_var Coherent +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%int = OpTypeInt 32 0 +%ptr_wg_int = OpTypePointer Workgroup %int +%wg_var = OpVariable %ptr_wg_int Workgroup +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%2 = OpExtInst %float %import Frexp %float_0 %wg_var +%3 = OpFAdd %float %float_0 %2 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, UpgradeFrexpSSBOCoherent) { + const std::string text = R"( +; CHECK: [[float:%\w+]] = OpTypeFloat 32 +; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0 +; CHECK: [[int:%\w+]] = OpTypeInt 32 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[int]] +; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer +; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[int]] +; CHECK: [[qf_scope:%\w+]] = OpConstant {{%\w+}} 5 +; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]] +; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0 +; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1 +; CHECK: OpStore [[var]] [[ex1]] MakePointerAvailableKHR|NonPrivatePointerKHR [[qf_scope]] +; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +%import = OpExtInstImport "GLSL.std.450" +OpEntryPoint GLCompute %func "func" +OpDecorate %ssbo_var Coherent +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%ssbo_var = OpVariable %ptr_ssbo_int StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%2 = OpExtInst %float %import Frexp %float_0 %ssbo_var +%3 = OpFAdd %float %float_0 %2 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + +TEST_F(UpgradeMemoryModelTest, UpgradeFrexpSSBOVolatile) { + const std::string text = R"( +; CHECK: [[float:%\w+]] = OpTypeFloat 32 +; CHECK: [[float_0:%\w+]] = OpConstant [[float]] 0 +; CHECK: [[int:%\w+]] = OpTypeInt 32 0 +; CHECK: [[ptr:%\w+]] = OpTypePointer StorageBuffer [[int]] +; CHECK: [[var:%\w+]] = OpVariable [[ptr]] StorageBuffer +; CHECK: [[struct:%\w+]] = OpTypeStruct [[float]] [[int]] +; CHECK: [[modfstruct:%\w+]] = OpExtInst [[struct]] {{%\w+}} FrexpStruct [[float_0]] +; CHECK: [[ex0:%\w+]] = OpCompositeExtract [[float]] [[modfstruct]] 0 +; CHECK: [[ex1:%\w+]] = OpCompositeExtract [[int]] [[modfstruct]] 1 +; CHECK: OpStore [[var]] [[ex1]] Volatile +; CHECK: OpFAdd [[float]] [[float_0]] [[ex0]] +OpCapability Shader +OpMemoryModel Logical GLSL450 +%import = OpExtInstImport "GLSL.std.450" +OpEntryPoint GLCompute %func "func" +OpDecorate %wg_var Volatile +%void = OpTypeVoid +%float = OpTypeFloat 32 +%float_0 = OpConstant %float 0 +%int = OpTypeInt 32 0 +%ptr_ssbo_int = OpTypePointer StorageBuffer %int +%wg_var = OpVariable %ptr_ssbo_int StorageBuffer +%func_ty = OpTypeFunction %void +%func = OpFunction %void None %func_ty +%1 = OpLabel +%2 = OpExtInst %float %import Frexp %float_0 %wg_var +%3 = OpFAdd %float %float_0 %2 +OpReturn +OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} } // namespace diff --git a/3rdparty/spirv-tools/test/test_fixture.h b/3rdparty/spirv-tools/test/test_fixture.h index e85015c94..436993e21 100644 --- a/3rdparty/spirv-tools/test/test_fixture.h +++ b/3rdparty/spirv-tools/test/test_fixture.h @@ -61,6 +61,8 @@ class TextToBinaryTestBase : public T { // compilation success. Returns the compiled code. SpirvVector CompileSuccessfully(const std::string& txt, spv_target_env env = SPV_ENV_UNIVERSAL_1_0) { + DestroyBinary(); + DestroyDiagnostic(); spv_result_t status = spvTextToBinary(ScopedContext(env).context, txt.c_str(), txt.size(), &binary, &diagnostic); @@ -79,6 +81,8 @@ class TextToBinaryTestBase : public T { // Returns the error message(s). std::string CompileFailure(const std::string& txt, spv_target_env env = SPV_ENV_UNIVERSAL_1_0) { + DestroyBinary(); + DestroyDiagnostic(); EXPECT_NE(SPV_SUCCESS, spvTextToBinary(ScopedContext(env).context, txt.c_str(), txt.size(), &binary, &diagnostic)) @@ -94,6 +98,7 @@ class TextToBinaryTestBase : public T { uint32_t disassemble_options = SPV_BINARY_TO_TEXT_OPTION_NONE, spv_target_env env = SPV_ENV_UNIVERSAL_1_0) { DestroyBinary(); + DestroyDiagnostic(); ScopedContext context(env); disassemble_options |= SPV_BINARY_TO_TEXT_OPTION_NO_HEADER; spv_result_t error = spvTextToBinary(context.context, txt.c_str(), @@ -126,6 +131,8 @@ class TextToBinaryTestBase : public T { // Returns the error message. std::string EncodeSuccessfullyDecodeFailed( const std::string& txt, const SpirvVector& words_to_append) { + DestroyBinary(); + DestroyDiagnostic(); SpirvVector code = spvtest::Concatenate({CompileSuccessfully(txt), words_to_append}); @@ -169,6 +176,12 @@ class TextToBinaryTestBase : public T { binary = nullptr; } + // Destroys the diagnostic, if it exists. + void DestroyDiagnostic() { + spvDiagnosticDestroy(diagnostic); + diagnostic = nullptr; + } + spv_diagnostic diagnostic; std::string textString; diff --git a/3rdparty/spirv-tools/test/val/val_constants_test.cpp b/3rdparty/spirv-tools/test/val/val_constants_test.cpp index 80bc9709b..824d6fda5 100644 --- a/3rdparty/spirv-tools/test/val/val_constants_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_constants_test.cpp @@ -280,6 +280,20 @@ INSTANTIATE_TEST_CASE_P( "InBoundsPtrAccessChain"), })); +INSTANTIATE_TEST_CASE_P( + UConvertInAMD_gpu_shader_int16, ValidateConstantOp, + ValuesIn(std::vector{ + // SPV_AMD_gpu_shader_int16 should enable UConvert for OpSpecConstantOp + // https://github.com/KhronosGroup/glslang/issues/848 + {SPV_ENV_UNIVERSAL_1_0, + "OpCapability Shader " + "OpCapability Linkage ; So we don't need to define a function\n" + "OpExtension \"SPV_AMD_gpu_shader_int16\" " + "OpMemoryModel Logical Simple " kBasicTypes + "%v = OpSpecConstantOp %uint UConvert %uint_0", + true, ""}, + })); + } // namespace } // namespace val } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/val/val_conversion_test.cpp b/3rdparty/spirv-tools/test/val/val_conversion_test.cpp index 4161c7428..5e4ad4908 100644 --- a/3rdparty/spirv-tools/test/val/val_conversion_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_conversion_test.cpp @@ -1302,6 +1302,118 @@ OpFunctionEnd "type")); } +TEST_F(ValidateConversion, ConvertUToPtrPSBSuccess) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%uint64 = OpTypeInt 64 0 +%u64_1 = OpConstant %uint64 1 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpConvertUToPtr %ptr %u64_1 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateConversion, ConvertUToPtrPSBStorageClass) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%uint64 = OpTypeInt 64 0 +%u64_1 = OpConstant %uint64 1 +%ptr = OpTypePointer Function %uint64 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpConvertUToPtr %ptr %u64_1 +%val2 = OpConvertPtrToU %uint64 %val1 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Pointer storage class must be " + "PhysicalStorageBufferEXT: ConvertUToPtr")); +} + +TEST_F(ValidateConversion, ConvertPtrToUPSBSuccess) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 RestrictPointerEXT +%uint64 = OpTypeInt 64 0 +%u64_1 = OpConstant %uint64 1 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +%val2 = OpLoad %ptr %val1 +%val3 = OpConvertPtrToU %uint64 %val2 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateConversion, ConvertPtrToUPSBStorageClass) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%uint64 = OpTypeInt 64 0 +%u64_1 = OpConstant %uint64 1 +%ptr = OpTypePointer Function %uint64 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %ptr Function +%val2 = OpConvertPtrToU %uint64 %val1 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("Pointer storage class must be " + "PhysicalStorageBufferEXT: ConvertPtrToU")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/val/val_data_test.cpp b/3rdparty/spirv-tools/test/val/val_data_test.cpp index fcf447a59..48a484612 100644 --- a/3rdparty/spirv-tools/test/val/val_data_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_data_test.cpp @@ -36,6 +36,24 @@ std::string HeaderWith(std::string cap) { cap + " OpMemoryModel Logical GLSL450 "; } +std::string WebGPUHeaderWith(std::string cap) { + return R"( +OpCapability Shader +OpCapability )" + + cap + R"( +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +)"; +} + +std::string webgpu_header = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +)"; + std::string header = R"( OpCapability Shader OpCapability Linkage @@ -249,6 +267,18 @@ TEST_F(ValidateData, int8_with_storage_push_constant_8_good) { EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString(); } +TEST_F(ValidateData, webgpu_int8_bad) { + std::string str = WebGPUHeaderWith("Int8") + "%2 = OpTypeInt 8 0"; + CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Capability Int8 is not allowed by WebGPU specification (or " + "requires extension)\n" + " OpCapability Int8\n")); +} + TEST_F(ValidateData, int16_good) { std::string str = header_with_int16 + "%2 = OpTypeInt 16 1"; CompileSuccessfully(str.c_str()); @@ -308,6 +338,34 @@ TEST_F(ValidateData, int16_bad) { EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int16_cap_error)); } +TEST_F(ValidateData, webgpu_int16_bad) { + std::string str = WebGPUHeaderWith("Int16") + "%2 = OpTypeInt 16 1"; + CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Capability Int16 is not allowed by WebGPU specification (or " + "requires extension)\n" + " OpCapability Int16\n")); +} + +TEST_F(ValidateData, webgpu_int32_good) { + std::string str = webgpu_header + R"( + OpEntryPoint Fragment %func "func" + OpExecutionMode %func OriginUpperLeft +%uint_t = OpTypeInt 32 0 + %void = OpTypeVoid +%func_t = OpTypeFunction %void + %func = OpFunction %void None %func_t + %1 = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + TEST_F(ValidateData, int64_good) { std::string str = header_with_int64 + "%2 = OpTypeInt 64 1"; CompileSuccessfully(str.c_str()); @@ -321,6 +379,18 @@ TEST_F(ValidateData, int64_bad) { EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_int64_cap_error)); } +TEST_F(ValidateData, webgpu_int64_bad) { + std::string str = WebGPUHeaderWith("Int64") + "%2 = OpTypeInt 64 1"; + CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Capability Int64 is not allowed by WebGPU specification (or " + "requires extension)\n" + " OpCapability Int64\n")); +} + // Number of bits in an integer may be only one of: {8,16,32,64} TEST_F(ValidateData, int_invalid_num_bits) { std::string str = header + "%2 = OpTypeInt 48 1"; @@ -348,6 +418,34 @@ TEST_F(ValidateData, float16_bad) { EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float16_cap_error)); } +TEST_F(ValidateData, webgpu_float16_bad) { + std::string str = WebGPUHeaderWith("Float16") + "%2 = OpTypeFloat 16"; + CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Capability Float16 is not allowed by WebGPU specification (or " + "requires extension)\n" + " OpCapability Float16\n")); +} + +TEST_F(ValidateData, webgpu_float32_good) { + std::string str = webgpu_header + R"( + OpEntryPoint Fragment %func "func" + OpExecutionMode %func OriginUpperLeft +%float_t = OpTypeFloat 32 + %void = OpTypeVoid + %func_t = OpTypeFunction %void + %func = OpFunction %void None %func_t + %1 = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); +} + TEST_F(ValidateData, float64_good) { std::string str = header_with_float64 + "%2 = OpTypeFloat 64"; CompileSuccessfully(str.c_str()); @@ -361,6 +459,18 @@ TEST_F(ValidateData, float64_bad) { EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_float64_cap_error)); } +TEST_F(ValidateData, webgpu_float64_bad) { + std::string str = WebGPUHeaderWith("Float64") + "%2 = OpTypeFloat 64"; + CompileSuccessfully(str.c_str(), SPV_ENV_WEBGPU_0); + ASSERT_EQ(SPV_ERROR_INVALID_CAPABILITY, + ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Capability Float64 is not allowed by WebGPU specification (or " + "requires extension)\n" + " OpCapability Float64\n")); +} + // Number of bits in a float may be only one of: {16,32,64} TEST_F(ValidateData, float_invalid_num_bits) { std::string str = header + "%2 = OpTypeFloat 48"; @@ -703,6 +813,65 @@ TEST_F(ValidateData, void_runtime_array) { HasSubstr( "OpTypeRuntimeArray Element Type '1[%void]' is a void type.")); } + +TEST_F(ValidateData, vulkan_RTA_array_at_end_of_struct) { + 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 + OpDecorate %struct_t Block + %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_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateData, vulkan_RTA_not_at_end_of_struct) { + 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 + OpDecorate %struct_t Block + %uint_t = OpTypeInt 32 0 + %array_t = OpTypeRuntimeArray %uint_t + %struct_t = OpTypeStruct %array_t %uint_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(), + HasSubstr("In Vulkan, OpTypeRuntimeArray must only be used for " + "the last member of an OpTypeStruct\n %_struct_3 = " + "OpTypeStruct %_runtimearr_uint %uint\n")); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/val/val_decoration_test.cpp b/3rdparty/spirv-tools/test/val/val_decoration_test.cpp index 3a4320dba..827ebf185 100644 --- a/3rdparty/spirv-tools/test/val/val_decoration_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_decoration_test.cpp @@ -4345,11 +4345,11 @@ OpFunctionEnd CompileSuccessfully(spirv); EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateAndRetrieveValidationState()); - EXPECT_THAT( - getDiagnosticString(), - HasSubstr("FPRoundingMode decoration can be applied only to the " - "Object operand of an OpStore in the StorageBuffer, Uniform, " - "PushConstant, Input, or Output Storage Classes.")); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("FPRoundingMode decoration can be applied only to the " + "Object operand of an OpStore in the StorageBuffer, " + "PhysicalStorageBufferEXT, Uniform, " + "PushConstant, Input, or Output Storage Classes.")); } TEST_F(ValidateDecorations, FPRoundingModeMultipleOpStoreGood) { @@ -4810,6 +4810,498 @@ TEST_F(ValidateDecorations, BlockAndBufferBlockDecorationsOnSameID) { "ID '2' decorated with both BufferBlock and Block is not allowed.")); } +std::string MakeIntegerShader( + const std::string& decoration, const std::string& inst, + const std::string& extension = + "OpExtension \"SPV_KHR_no_integer_wrap_decoration\"") { + return R"( +OpCapability Shader +OpCapability Linkage +)" + extension + + R"( +%glsl = OpExtInstImport "GLSL.std.450" +%opencl = OpExtInstImport "OpenCL.std" +OpMemoryModel Logical GLSL450 +OpEntryPoint GLCompute %main "main" +OpName %entry "entry" +)" + decoration + + R"( + %void = OpTypeVoid + %voidfn = OpTypeFunction %void + %int = OpTypeInt 32 1 + %zero = OpConstantNull %int + %float = OpTypeFloat 32 + %float0 = OpConstantNull %float + %main = OpFunction %void None %voidfn + %entry = OpLabel +)" + inst + + R"( +OpReturn +OpFunctionEnd)"; +} + +// NoSignedWrap + +TEST_F(ValidateDecorations, NoSignedWrapOnTypeBad) { + std::string spirv = MakeIntegerShader("OpDecorate %void NoSignedWrap", ""); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("NoSignedWrap decoration may not be applied to TypeVoid")); +} + +TEST_F(ValidateDecorations, NoSignedWrapOnLabelBad) { + std::string spirv = MakeIntegerShader("OpDecorate %entry NoSignedWrap", ""); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NoSignedWrap decoration may not be applied to Label")); +} + +TEST_F(ValidateDecorations, NoSignedWrapRequiresExtensionBad) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpIAdd %int %zero %zero", ""); + + CompileSuccessfully(spirv); + EXPECT_NE(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires one of these extensions: " + "SPV_KHR_no_integer_wrap_decoration")); +} + +TEST_F(ValidateDecorations, NoSignedWrapIAddGood) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpIAdd %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoSignedWrapISubGood) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpISub %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoSignedWrapIMulGood) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpIMul %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoSignedWrapShiftLeftLogicalGood) { + std::string spirv = + MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpShiftLeftLogical %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoSignedWrapSNegateGood) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpSNegate %int %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoSignedWrapSRemBad) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpSRem %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NoSignedWrap decoration may not be applied to SRem")); +} + +TEST_F(ValidateDecorations, NoSignedWrapFAddBad) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpFAdd %float %float0 %float0"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("NoSignedWrap decoration may not be applied to FAdd")); +} + +TEST_F(ValidateDecorations, NoSignedWrapExtInstOpenCLGood) { + std::string spirv = + MakeIntegerShader("OpDecorate %val NoSignedWrap", + "%val = OpExtInst %int %opencl s_abs %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoSignedWrapExtInstGLSLGood) { + std::string spirv = MakeIntegerShader( + "OpDecorate %val NoSignedWrap", "%val = OpExtInst %int %glsl SAbs %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +// TODO(dneto): For NoSignedWrap and NoUnsignedWrap, permit +// "OpExtInst for instruction numbers specified in the extended +// instruction-set specifications as accepting this decoration." + +// NoUnignedWrap + +TEST_F(ValidateDecorations, NoUnsignedWrapOnTypeBad) { + std::string spirv = MakeIntegerShader("OpDecorate %void NoUnsignedWrap", ""); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("NoUnsignedWrap decoration may not be applied to TypeVoid")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapOnLabelBad) { + std::string spirv = MakeIntegerShader("OpDecorate %entry NoUnsignedWrap", ""); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("NoUnsignedWrap decoration may not be applied to Label")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapRequiresExtensionBad) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpIAdd %int %zero %zero", ""); + + CompileSuccessfully(spirv); + EXPECT_NE(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("requires one of these extensions: " + "SPV_KHR_no_integer_wrap_decoration")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapIAddGood) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpIAdd %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapISubGood) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpISub %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapIMulGood) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpIMul %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapShiftLeftLogicalGood) { + std::string spirv = + MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpShiftLeftLogical %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapSNegateGood) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpSNegate %int %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapSRemBad) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpSRem %int %zero %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("NoUnsignedWrap decoration may not be applied to SRem")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapFAddBad) { + std::string spirv = MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpFAdd %float %float0 %float0"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("NoUnsignedWrap decoration may not be applied to FAdd")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapExtInstOpenCLGood) { + std::string spirv = + MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpExtInst %int %opencl s_abs %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +TEST_F(ValidateDecorations, NoUnsignedWrapExtInstGLSLGood) { + std::string spirv = + MakeIntegerShader("OpDecorate %val NoUnsignedWrap", + "%val = OpExtInst %int %glsl SAbs %zero"); + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), Eq("")); +} + +// TODO(dneto): For NoUnsignedWrap and NoUnsignedWrap, permit +// "OpExtInst for instruction numbers specified in the extended +// instruction-set specifications as accepting this decoration." + +TEST_F(ValidateDecorations, PSBAliasedRestrictPointerSuccess) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 RestrictPointerEXT +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateDecorations, PSBAliasedRestrictPointerMissing) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected AliasedPointerEXT or RestrictPointerEXT for " + "PhysicalStorageBufferEXT pointer")); +} + +TEST_F(ValidateDecorations, PSBAliasedRestrictPointerBoth) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 RestrictPointerEXT +OpDecorate %val1 AliasedPointerEXT +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("can't specify both AliasedPointerEXT and RestrictPointerEXT " + "for PhysicalStorageBufferEXT pointer")); +} + +TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamSuccess) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %fparam Restrict +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%fnptr = OpTypeFunction %void %ptr +%main = OpFunction %void None %voidfn +%entry = OpLabel +OpReturn +OpFunctionEnd +%fn = OpFunction %void None %fnptr +%fparam = OpFunctionParameter %ptr +%lab = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamMissing) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%fnptr = OpTypeFunction %void %ptr +%main = OpFunction %void None %voidfn +%entry = OpLabel +OpReturn +OpFunctionEnd +%fn = OpFunction %void None %fnptr +%fparam = OpFunctionParameter %ptr +%lab = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("expected Aliased or Restrict for " + "PhysicalStorageBufferEXT pointer")); +} + +TEST_F(ValidateDecorations, PSBAliasedRestrictFunctionParamBoth) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %fparam Restrict +OpDecorate %fparam Aliased +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%fnptr = OpTypeFunction %void %ptr +%main = OpFunction %void None %voidfn +%entry = OpLabel +OpReturn +OpFunctionEnd +%fn = OpFunction %void None %fnptr +%fparam = OpFunctionParameter %ptr +%lab = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("can't specify both Aliased and Restrict for " + "PhysicalStorageBufferEXT pointer")); +} + +TEST_F(ValidateDecorations, PSBFPRoundingModeSuccess) { + std::string spirv = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Shader +OpCapability Linkage +OpCapability StorageBuffer16BitAccess +OpExtension "SPV_EXT_physical_storage_buffer" +OpExtension "SPV_KHR_storage_buffer_storage_class" +OpExtension "SPV_KHR_variable_pointers" +OpExtension "SPV_KHR_16bit_storage" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint GLCompute %main "main" +OpDecorate %_ FPRoundingMode RTE +OpDecorate %half_ptr_var AliasedPointerEXT +%half = OpTypeFloat 16 +%float = OpTypeFloat 32 +%float_1_25 = OpConstant %float 1.25 +%half_ptr = OpTypePointer PhysicalStorageBufferEXT %half +%half_pptr_f = OpTypePointer Function %half_ptr +%void = OpTypeVoid +%func = OpTypeFunction %void +%main = OpFunction %void None %func +%main_entry = OpLabel +%half_ptr_var = OpVariable %half_pptr_f Function +%val1 = OpLoad %half_ptr %half_ptr_var +%_ = OpFConvert %half %float_1_25 +OpStore %val1 %_ Aligned 2 +OpReturn +OpFunctionEnd + )"; + + CompileSuccessfully(spirv); + EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/val/val_fixtures.h b/3rdparty/spirv-tools/test/val/val_fixtures.h index 73a0cc624..69bc9d82f 100644 --- a/3rdparty/spirv-tools/test/val/val_fixtures.h +++ b/3rdparty/spirv-tools/test/val/val_fixtures.h @@ -56,6 +56,18 @@ class ValidateBase : public ::testing::Test, spv_result_t ValidateAndRetrieveValidationState( spv_target_env env = SPV_ENV_UNIVERSAL_1_0); + // Destroys the stored binary. + void DestroyBinary() { + spvBinaryDestroy(binary_); + binary_ = nullptr; + } + + // Destroys the stored diagnostic. + void DestroyDiagnostic() { + spvDiagnosticDestroy(diagnostic_); + diagnostic_ = nullptr; + } + std::string getDiagnosticString(); spv_position_t getErrorPosition(); spv_validator_options getValidatorOptions(); @@ -67,7 +79,7 @@ class ValidateBase : public ::testing::Test, }; template -ValidateBase::ValidateBase() : binary_(), diagnostic_() { +ValidateBase::ValidateBase() : binary_(nullptr), diagnostic_(nullptr) { // Initialize to default command line options. Different tests can then // specialize specific options as necessary. options_ = spvValidatorOptionsCreate(); @@ -83,14 +95,15 @@ void ValidateBase::TearDown() { if (diagnostic_) { spvDiagnosticPrint(diagnostic_); } - spvDiagnosticDestroy(diagnostic_); - spvBinaryDestroy(binary_); + DestroyBinary(); + DestroyDiagnostic(); spvValidatorOptionsDestroy(options_); } template void ValidateBase::CompileSuccessfully(std::string code, spv_target_env env) { + DestroyBinary(); spv_diagnostic diagnostic = nullptr; ASSERT_EQ(SPV_SUCCESS, spvTextToBinary(ScopedContext(env).context, code.c_str(), @@ -98,6 +111,7 @@ void ValidateBase::CompileSuccessfully(std::string code, << "ERROR: " << diagnostic->error << "\nSPIR-V could not be compiled into binary:\n" << code; + spvDiagnosticDestroy(diagnostic); } template @@ -110,6 +124,7 @@ void ValidateBase::OverwriteAssembledBinary(uint32_t index, uint32_t word) { template spv_result_t ValidateBase::ValidateInstructions(spv_target_env env) { + DestroyDiagnostic(); return spvValidateWithOptions(ScopedContext(env).context, options_, get_const_binary(), &diagnostic_); } @@ -117,6 +132,7 @@ spv_result_t ValidateBase::ValidateInstructions(spv_target_env env) { template spv_result_t ValidateBase::ValidateAndRetrieveValidationState( spv_target_env env) { + DestroyDiagnostic(); return spvtools::val::ValidateBinaryAndKeepValidationState( ScopedContext(env).context, options_, get_const_binary()->code, get_const_binary()->wordCount, &diagnostic_, &vstate_); diff --git a/3rdparty/spirv-tools/test/val/val_id_test.cpp b/3rdparty/spirv-tools/test/val/val_id_test.cpp index 25fac88d1..a09761e02 100644 --- a/3rdparty/spirv-tools/test/val/val_id_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_id_test.cpp @@ -780,6 +780,8 @@ class OpTypeArrayLengthTest // Runs spvValidate() on v, printing any errors via spvDiagnosticPrint(). spv_result_t Val(const SpirvVector& v, const std::string& expected_err = "") { spv_const_binary_t cbinary{v.data(), v.size()}; + spvDiagnosticDestroy(diagnostic_); + diagnostic_ = nullptr; const auto status = spvValidate(ScopedContext().context, &cbinary, &diagnostic_); if (status != SPV_SUCCESS) { diff --git a/3rdparty/spirv-tools/test/val/val_logicals_test.cpp b/3rdparty/spirv-tools/test/val/val_logicals_test.cpp index f457887c0..da8e7d9e9 100644 --- a/3rdparty/spirv-tools/test/val/val_logicals_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_logicals_test.cpp @@ -919,6 +919,36 @@ TEST_F(ValidateLogicals, OpSGreaterThanDifferentBitWidth) { "width: SGreaterThan")); } +TEST_F(ValidateLogicals, PSBSelectSuccess) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 AliasedPointerEXT +%uint64 = OpTypeInt 64 0 +%bool = OpTypeBool +%true = OpConstantTrue %bool +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +%val2 = OpLoad %ptr %val1 +%val3 = OpSelect %ptr %true %val2 %val2 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/val/val_memory_test.cpp b/3rdparty/spirv-tools/test/val/val_memory_test.cpp index a5e5f9101..8ad1db46d 100644 --- a/3rdparty/spirv-tools/test/val/val_memory_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_memory_test.cpp @@ -138,7 +138,9 @@ OpFunctionEnd TEST_F(ValidateMemory, VulkanUniformConstantOnOpaqueResourceRuntimeArrayGood) { std::string spirv = R"( +OpCapability RuntimeDescriptorArrayEXT OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %func "func" OpExecutionMode %func OriginUpperLeft @@ -455,6 +457,93 @@ OpFunctionEnd " %5 = OpVariable %_ptr_Uniform_float Uniform %float_1\n")); } +TEST_F(ValidateMemory, WebGPUOutputStorageClassWithoutInitializerBad) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Output %float +%1 = OpVariable %float_ptr Output +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpVariable, '4[%4]', must have an initializer.\n" + "From WebGPU execution environment spec:\n" + "All variables in the following storage classes must have an " + "initializer: Output, Private, or Function\n" + " %4 = OpVariable %_ptr_Output_float Output\n")); +} + +TEST_F(ValidateMemory, WebGPUFunctionStorageClassWithoutInitializerBad) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Function %float +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%1 = OpLabel +%2 = OpVariable %float_ptr Function +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpVariable, '7[%7]', must have an initializer.\n" + "From WebGPU execution environment spec:\n" + "All variables in the following storage classes must have an " + "initializer: Output, Private, or Function\n" + " %7 = OpVariable %_ptr_Function_float Function\n")); +} + +TEST_F(ValidateMemory, WebGPUPrivateStorageClassWithoutInitializerBad) { + std::string spirv = R"( +OpCapability Shader +OpCapability VulkanMemoryModelKHR +OpExtension "SPV_KHR_vulkan_memory_model" +OpMemoryModel Logical VulkanKHR +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%float = OpTypeFloat 32 +%float_ptr = OpTypePointer Private %float +%1 = OpVariable %float_ptr Private +%void = OpTypeVoid +%functy = OpTypeFunction %void +%func = OpFunction %void None %functy +%2 = OpLabel +OpReturn +OpFunctionEnd +)"; + CompileSuccessfully(spirv.c_str(), SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpVariable, '4[%4]', must have an initializer.\n" + "From WebGPU execution environment spec:\n" + "All variables in the following storage classes must have an " + "initializer: Output, Private, or Function\n" + " %4 = OpVariable %_ptr_Private_float Private\n")); +} + TEST_F(ValidateMemory, VulkanInitializerWithOutputStorageClassesGood) { std::string spirv = R"( OpCapability Shader @@ -1537,6 +1626,732 @@ OpFunctionEnd HasSubstr("Operand 1[%incorrect] requires a type")); } +TEST_F(ValidateMemory, PSBLoadAlignedSuccess) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 AliasedPointerEXT +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +%val2 = OpLoad %ptr %val1 +%val3 = OpLoad %uint64 %val2 Aligned 8 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMemory, PSBLoadAlignedMissing) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 AliasedPointerEXT +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +%val2 = OpLoad %ptr %val1 +%val3 = OpLoad %uint64 %val2 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Memory accesses with PhysicalStorageBufferEXT must use Aligned")); +} + +TEST_F(ValidateMemory, PSBStoreAlignedSuccess) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 AliasedPointerEXT +%uint64 = OpTypeInt 64 0 +%u64_1 = OpConstant %uint64 1 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +%val2 = OpLoad %ptr %val1 +OpStore %val2 %u64_1 Aligned 8 +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateMemory, PSBStoreAlignedMissing) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 AliasedPointerEXT +%uint64 = OpTypeInt 64 0 +%u64_1 = OpConstant %uint64 1 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%pptr_f = OpTypePointer Function %ptr +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +%val1 = OpVariable %pptr_f Function +%val2 = OpLoad %ptr %val1 +OpStore %val2 %u64_1 None +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "Memory accesses with PhysicalStorageBufferEXT must use Aligned")); +} + +TEST_F(ValidateMemory, PSBVariable) { + const std::string body = R"( +OpCapability PhysicalStorageBufferAddressesEXT +OpCapability Int64 +OpCapability Shader +OpExtension "SPV_EXT_physical_storage_buffer" +OpMemoryModel PhysicalStorageBuffer64EXT GLSL450 +OpEntryPoint Fragment %main "main" +OpExecutionMode %main OriginUpperLeft +OpDecorate %val1 AliasedPointerEXT +%uint64 = OpTypeInt 64 0 +%ptr = OpTypePointer PhysicalStorageBufferEXT %uint64 +%val1 = OpVariable %ptr PhysicalStorageBufferEXT +%void = OpTypeVoid +%voidfn = OpTypeFunction %void +%main = OpFunction %void None %voidfn +%entry = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(body.c_str()); + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("PhysicalStorageBufferEXT must not be used with OpVariable")); +} + +TEST_F(ValidateMemory, VulkanRTAOutsideOfStructBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%sampler_t = OpTypeSampler +%array_t = OpTypeRuntimeArray %sampler_t +%array_ptr = OpTypePointer UniformConstant %array_t +%2 = OpVariable %array_ptr UniformConstant +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpVariable, '5[%5]', is attempting to create memory for an " + "illegal type, OpTypeRuntimeArray.\nFor Vulkan OpTypeRuntimeArray " + "can only appear as the final member of an OpTypeStruct, thus cannot " + "be instantiated via OpVariable\n %5 = OpVariable " + "%_ptr_UniformConstant__runtimearr_2 UniformConstant\n")); +} + +TEST_F(ValidateMemory, VulkanRTAOutsideOfStructWithRuntimeDescriptorArrayGood) { + std::string spirv = R"( +OpCapability Shader +OpCapability RuntimeDescriptorArrayEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%sampler_t = OpTypeSampler +%array_t = OpTypeRuntimeArray %sampler_t +%array_sb_ptr = OpTypePointer StorageBuffer %array_t +%2 = OpVariable %array_sb_ptr StorageBuffer +%array_uc_ptr = OpTypePointer UniformConstant %array_t +%3 = OpVariable %array_uc_ptr UniformConstant +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F( + ValidateMemory, + VulkanRTAOutsideOfStructWithRuntimeDescriptorArrayAndWrongStorageClassBad) { + std::string spirv = R"( +OpCapability Shader +OpCapability RuntimeDescriptorArrayEXT +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%uint_t = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %uint_t +%array_ptr = OpTypePointer Workgroup %array_t +%2 = OpVariable %array_ptr Workgroup +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("For Vulkan with RuntimeDescriptorArrayEXT, a variable " + "containing OpTypeRuntimeArray must have storage class of " + "StorageBuffer, Uniform, or UniformConstant.\n %5 = " + "OpVariable %_ptr_Workgroup__runtimearr_uint Workgroup\n")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideStorageBufferStructGood) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %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(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, VulkanRTAInsideWrongStorageClassStructBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%uint_t = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %array_t +%struct_ptr = OpTypePointer Workgroup %struct_t +%2 = OpVariable %struct_ptr Workgroup +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "For Vulkan, OpTypeStruct variables containing OpTypeRuntimeArray " + "must have storage class of StorageBuffer or Uniform.\n %6 = " + "OpVariable %_ptr_Workgroup__struct_4 Workgroup\n")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideStorageBufferStructWithoutBlockBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%uint_t = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %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(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("For Vulkan, an OpTypeStruct variable containing an " + "OpTypeRuntimeArray must be decorated with Block if it " + "has storage class StorageBuffer.\n %6 = OpVariable " + "%_ptr_StorageBuffer__struct_4 StorageBuffer\n")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideUniformStructGood) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t BufferBlock +%uint_t = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %array_t +%struct_ptr = OpTypePointer Uniform %struct_t +%2 = OpVariable %struct_ptr Uniform +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, VulkanRTAInsideUniformStructWithoutBufferBlockBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%uint_t = OpTypeInt 32 0 +%array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %array_t +%struct_ptr = OpTypePointer Uniform %struct_t +%2 = OpVariable %struct_ptr Uniform +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT(getDiagnosticString(), + 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")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideRTABad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%sampler_t = OpTypeSampler +%inner_array_t = OpTypeRuntimeArray %sampler_t +%array_t = OpTypeRuntimeArray %inner_array_t +%array_ptr = OpTypePointer UniformConstant %array_t +%2 = OpVariable %array_ptr UniformConstant +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpTypeRuntimeArray Element Type '3[%_runtimearr_2]' is not " + "valid in Vulkan environment.\n %_runtimearr__runtimearr_2 = " + "OpTypeRuntimeArray %_runtimearr_2\n")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideRTAWithRuntimeDescriptorArrayBad) { + std::string spirv = R"( +OpCapability RuntimeDescriptorArrayEXT +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t Block +%uint_t = OpTypeInt 32 0 +%inner_array_t = OpTypeRuntimeArray %uint_t +%array_t = OpTypeRuntimeArray %inner_array_t +%array_ptr = OpTypePointer StorageBuffer %array_t +%2 = OpVariable %array_ptr StorageBuffer +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpTypeRuntimeArray Element Type '4[%_runtimearr_uint]' is not " + "valid in Vulkan environment.\n %_runtimearr__runtimearr_uint = " + "OpTypeRuntimeArray %_runtimearr_uint\n")); +} + +TEST_F(ValidateMemory, + VulkanUniformStructInsideRTAWithRuntimeDescriptorArrayGood) { + std::string spirv = R"( +OpCapability RuntimeDescriptorArrayEXT +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%struct_t = OpTypeStruct %uint_t +%array_t = OpTypeRuntimeArray %struct_t +%array_ptr = OpTypePointer Uniform %array_t +%2 = OpVariable %array_ptr Uniform +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, VulkanRTAInsideRTAInsideStructBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%inner_array_t = OpTypeRuntimeArray %uint_t +%array_t = OpTypeRuntimeArray %inner_array_t +%struct_t = OpTypeStruct %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(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpTypeRuntimeArray Element Type '5[%_runtimearr_uint]' is not " + "valid in Vulkan environment.\n %_runtimearr__runtimearr_uint = " + "OpTypeRuntimeArray %_runtimearr_uint\n")); +} + +TEST_F(ValidateMemory, + VulkanRTAInsideRTAInsideStructWithRuntimeDescriptorArrayBad) { + std::string spirv = R"( +OpCapability RuntimeDescriptorArrayEXT +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%inner_array_t = OpTypeRuntimeArray %uint_t +%array_t = OpTypeRuntimeArray %inner_array_t +%struct_t = OpTypeStruct %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(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpTypeRuntimeArray Element Type '5[%_runtimearr_uint]' is not " + "valid in Vulkan environment.\n %_runtimearr__runtimearr_uint = " + "OpTypeRuntimeArray %_runtimearr_uint\n")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideArrayBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +%uint_t = OpTypeInt 32 0 +%dim = OpConstant %uint_t 1 +%sampler_t = OpTypeSampler +%inner_array_t = OpTypeRuntimeArray %sampler_t +%array_t = OpTypeArray %inner_array_t %dim +%array_ptr = OpTypePointer UniformConstant %array_t +%2 = OpVariable %array_ptr UniformConstant +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpTypeArray Element Type '5[%_runtimearr_4]' is not " + "valid in Vulkan environment.\n %_arr__runtimearr_4_uint_1 = " + "OpTypeArray %_runtimearr_4 %uint_1\n")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideArrayWithRuntimeDescriptorArrayBad) { + std::string spirv = R"( +OpCapability RuntimeDescriptorArrayEXT +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t Block +%uint_t = OpTypeInt 32 0 +%dim = OpConstant %uint_t 1 +%sampler_t = OpTypeSampler +%inner_array_t = OpTypeRuntimeArray %uint_t +%array_t = OpTypeRuntimeArray %inner_array_t +%array_ptr = OpTypePointer StorageBuffer %array_t +%2 = OpVariable %array_ptr StorageBuffer +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr( + "OpTypeRuntimeArray Element Type '6[%_runtimearr_uint]' is not " + "valid in Vulkan environment.\n %_runtimearr__runtimearr_uint = " + "OpTypeRuntimeArray %_runtimearr_uint\n")); +} + +TEST_F(ValidateMemory, VulkanRTAInsideArrayInsideStructBad) { + std::string spirv = R"( +OpCapability Shader +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%dim = OpConstant %uint_t 1 +%inner_array_t = OpTypeRuntimeArray %uint_t +%array_t = OpTypeArray %inner_array_t %dim +%struct_t = OpTypeStruct %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(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpTypeArray Element Type '6[%_runtimearr_uint]' is not " + "valid in Vulkan environment.\n %_arr__runtimearr_uint_uint_1 " + "= OpTypeArray %_runtimearr_uint %uint_1\n")); +} + +TEST_F(ValidateMemory, + VulkanRTAInsideArrayInsideStructWithRuntimeDescriptorArrayBad) { + std::string spirv = R"( +OpCapability RuntimeDescriptorArrayEXT +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%dim = OpConstant %uint_t 1 +%inner_array_t = OpTypeRuntimeArray %uint_t +%array_t = OpTypeArray %inner_array_t %dim +%struct_t = OpTypeStruct %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(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_1)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("OpTypeArray Element Type '6[%_runtimearr_uint]' is not " + "valid in Vulkan environment.\n %_arr__runtimearr_uint_uint_1 " + "= OpTypeArray %_runtimearr_uint %uint_1\n")); +} + +TEST_F(ValidateMemory, VulkanRTAStructInsideRTAWithRuntimeDescriptorArrayGood) { + std::string spirv = R"( +OpCapability RuntimeDescriptorArrayEXT +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%inner_array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %inner_array_t +%array_t = OpTypeRuntimeArray %struct_t +%array_ptr = OpTypePointer StorageBuffer %array_t +%2 = OpVariable %array_ptr StorageBuffer +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + +TEST_F(ValidateMemory, VulkanRTAStructInsideArrayGood) { + std::string spirv = R"( +OpCapability RuntimeDescriptorArrayEXT +OpCapability Shader +OpExtension "SPV_EXT_descriptor_indexing" +OpMemoryModel Logical GLSL450 +OpEntryPoint Fragment %func "func" +OpExecutionMode %func OriginUpperLeft +OpDecorate %array_t ArrayStride 4 +OpMemberDecorate %struct_t 0 Offset 0 +OpDecorate %struct_t Block +%uint_t = OpTypeInt 32 0 +%inner_array_t = OpTypeRuntimeArray %uint_t +%struct_t = OpTypeStruct %inner_array_t +%array_size = OpConstant %uint_t 5 +%array_t = OpTypeArray %struct_t %array_size +%array_ptr = OpTypePointer StorageBuffer %array_t +%2 = OpVariable %array_ptr StorageBuffer +%void = OpTypeVoid +%func_t = OpTypeFunction %void +%func = OpFunction %void None %func_t +%1 = OpLabel +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(spirv.c_str(), SPV_ENV_VULKAN_1_1); + EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_1)); +} + } // namespace } // namespace val } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/val/val_validation_state_test.cpp b/3rdparty/spirv-tools/test/val/val_validation_state_test.cpp index e010fe9f2..bf6509497 100644 --- a/3rdparty/spirv-tools/test/val/val_validation_state_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_validation_state_test.cpp @@ -306,6 +306,54 @@ TEST_F(ValidationStateTest, CheckWebGPUIndirectlyRecursiveBodyBad) { "called.\n %9 = OpFunctionCall %_struct_5 %10\n")); } +TEST_F(ValidationStateTest, + CheckWebGPUDuplicateEntryNamesDifferentFunctionsBad) { + std::string spirv = std::string(kVulkanMemoryHeader) + R"( +OpEntryPoint Fragment %func_1 "main" +OpEntryPoint Vertex %func_2 "main" +OpExecutionMode %func_1 OriginUpperLeft +%void = OpTypeVoid +%void_f = OpTypeFunction %void +%func_1 = OpFunction %void None %void_f +%label_1 = OpLabel + OpReturn + OpFunctionEnd +%func_2 = OpFunction %void None %void_f +%label_2 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, + ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Entry point name \"main\" is not unique, which is not allow " + "in WebGPU env.\n %1 = OpFunction %void None %4\n")); +} + +TEST_F(ValidationStateTest, CheckWebGPUDuplicateEntryNamesSameFunctionBad) { + std::string spirv = std::string(kVulkanMemoryHeader) + R"( +OpEntryPoint GLCompute %func_1 "main" +OpEntryPoint Vertex %func_1 "main" +%void = OpTypeVoid +%void_f = OpTypeFunction %void +%func_1 = OpFunction %void None %void_f +%label_1 = OpLabel + OpReturn + OpFunctionEnd +)"; + + CompileSuccessfully(spirv, SPV_ENV_WEBGPU_0); + EXPECT_EQ(SPV_ERROR_INVALID_BINARY, + ValidateAndRetrieveValidationState(SPV_ENV_WEBGPU_0)); + EXPECT_THAT( + getDiagnosticString(), + HasSubstr("Entry point name \"main\" is not unique, which is not allow " + "in WebGPU env.\n %1 = OpFunction %void None %3\n")); +} + } // namespace } // namespace val } // namespace spvtools