From b28dfbd770b33ff1526715082264a10d023683da 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: Sat, 16 Mar 2019 20:28:47 -0700 Subject: [PATCH] Updated spirv-tools. --- 3rdparty/spirv-tools/Android.mk | 1 + 3rdparty/spirv-tools/BUILD.gn | 2 + .../include/generated/build-version.inc | 2 +- .../include/generated/core.insts-unified1.inc | 34 +- .../include/spirv-tools/optimizer.hpp | 7 + 3rdparty/spirv-tools/source/opcode.cpp | 32 ++ 3rdparty/spirv-tools/source/opcode.h | 4 + .../spirv-tools/source/opt/CMakeLists.txt | 2 + 3rdparty/spirv-tools/source/opt/ccp_pass.cpp | 1 + .../spirv-tools/source/opt/folding_rules.cpp | 33 ++ 3rdparty/spirv-tools/source/opt/optimizer.cpp | 11 +- 3rdparty/spirv-tools/source/opt/passes.h | 1 + .../opt/strip_atomic_counter_memory_pass.cpp | 57 +++ .../opt/strip_atomic_counter_memory_pass.h | 51 +++ .../source/val/validate_function.cpp | 19 +- .../source/val/validate_instruction.cpp | 30 ++ .../source/val/validate_mode_setting.cpp | 16 + 3rdparty/spirv-tools/test/opt/CMakeLists.txt | 1 + 3rdparty/spirv-tools/test/opt/ccp_test.cpp | 29 ++ 3rdparty/spirv-tools/test/opt/fold_test.cpp | 100 +++++ .../spirv-tools/test/opt/optimizer_test.cpp | 102 ++++- .../opt/strip_atomic_counter_memory_test.cpp | 406 ++++++++++++++++++ .../test/val/val_decoration_test.cpp | 2 + .../test/val/val_function_test.cpp | 22 +- .../spirv-tools/test/val/val_modes_test.cpp | 55 ++- .../spirv-tools/test/val/val_storage_test.cpp | 128 ++++++ 3rdparty/spirv-tools/tools/opt/opt.cpp | 2 + 27 files changed, 1106 insertions(+), 44 deletions(-) create mode 100644 3rdparty/spirv-tools/source/opt/strip_atomic_counter_memory_pass.cpp create mode 100644 3rdparty/spirv-tools/source/opt/strip_atomic_counter_memory_pass.h create mode 100644 3rdparty/spirv-tools/test/opt/strip_atomic_counter_memory_test.cpp diff --git a/3rdparty/spirv-tools/Android.mk b/3rdparty/spirv-tools/Android.mk index 8f4f5fea7..fe7a93dec 100644 --- a/3rdparty/spirv-tools/Android.mk +++ b/3rdparty/spirv-tools/Android.mk @@ -154,6 +154,7 @@ SPVTOOLS_OPT_SRC_FILES := \ source/opt/simplification_pass.cpp \ source/opt/ssa_rewrite_pass.cpp \ source/opt/strength_reduction_pass.cpp \ + source/opt/strip_atomic_counter_memory_pass.cpp \ source/opt/strip_debug_info_pass.cpp \ source/opt/strip_reflect_info_pass.cpp \ source/opt/struct_cfg_analysis.cpp \ diff --git a/3rdparty/spirv-tools/BUILD.gn b/3rdparty/spirv-tools/BUILD.gn index 3038b9379..24f500635 100644 --- a/3rdparty/spirv-tools/BUILD.gn +++ b/3rdparty/spirv-tools/BUILD.gn @@ -612,6 +612,8 @@ static_library("spvtools_opt") { "source/opt/ssa_rewrite_pass.h", "source/opt/strength_reduction_pass.cpp", "source/opt/strength_reduction_pass.h", + "source/opt/strip_atomic_counter_memory_pass.cpp", + "source/opt/strip_atomic_counter_memory_pass.h", "source/opt/strip_debug_info_pass.cpp", "source/opt/strip_debug_info_pass.h", "source/opt/strip_reflect_info_pass.cpp", diff --git a/3rdparty/spirv-tools/include/generated/build-version.inc b/3rdparty/spirv-tools/include/generated/build-version.inc index 0138df9b0..87c3414e9 100644 --- a/3rdparty/spirv-tools/include/generated/build-version.inc +++ b/3rdparty/spirv-tools/include/generated/build-version.inc @@ -1 +1 @@ -"v2019.2", "SPIRV-Tools v2019.2 79f67a4905acf223f9e37a52e059a62c2bdbdc69" +"v2019.2", "SPIRV-Tools v2019.2 45a64efab9d50ebcf9694a3297acc3223502610d" diff --git a/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc b/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc index 3f4704c94..3fee08899 100644 --- a/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc +++ b/3rdparty/spirv-tools/include/generated/core.insts-unified1.inc @@ -8,7 +8,7 @@ static const SpvCapability pygen_variable_caps_FragmentMaskAMD[] = {SpvCapabilit static const SpvCapability pygen_variable_caps_Geometry[] = {SpvCapabilityGeometry}; static const SpvCapability pygen_variable_caps_GeometryStreams[] = {SpvCapabilityGeometryStreams}; static const SpvCapability pygen_variable_caps_GroupNonUniform[] = {SpvCapabilityGroupNonUniform}; -static const SpvCapability pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered[] = {SpvCapabilityGroupNonUniformArithmetic, SpvCapabilityGroupNonUniformClustered}; +static const SpvCapability pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV[] = {SpvCapabilityGroupNonUniformArithmetic, SpvCapabilityGroupNonUniformClustered, SpvCapabilityGroupNonUniformPartitionedNV}; static const SpvCapability pygen_variable_caps_GroupNonUniformBallot[] = {SpvCapabilityGroupNonUniformBallot}; static const SpvCapability pygen_variable_caps_GroupNonUniformPartitionedNV[] = {SpvCapabilityGroupNonUniformPartitionedNV}; static const SpvCapability pygen_variable_caps_GroupNonUniformQuad[] = {SpvCapabilityGroupNonUniformQuad}; @@ -375,22 +375,22 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = { {"GroupNonUniformShuffleXor", SpvOpGroupNonUniformShuffleXor, 1, pygen_variable_caps_GroupNonUniformShuffle, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, {"GroupNonUniformShuffleUp", SpvOpGroupNonUniformShuffleUp, 1, pygen_variable_caps_GroupNonUniformShuffleRelative, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, {"GroupNonUniformShuffleDown", SpvOpGroupNonUniformShuffleDown, 1, pygen_variable_caps_GroupNonUniformShuffleRelative, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, - {"GroupNonUniformIAdd", SpvOpGroupNonUniformIAdd, 2, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, - {"GroupNonUniformFAdd", SpvOpGroupNonUniformFAdd, 2, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, - {"GroupNonUniformIMul", SpvOpGroupNonUniformIMul, 2, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, - {"GroupNonUniformFMul", SpvOpGroupNonUniformFMul, 2, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, - {"GroupNonUniformSMin", SpvOpGroupNonUniformSMin, 2, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, - {"GroupNonUniformUMin", SpvOpGroupNonUniformUMin, 2, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, - {"GroupNonUniformFMin", SpvOpGroupNonUniformFMin, 2, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, - {"GroupNonUniformSMax", SpvOpGroupNonUniformSMax, 2, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, - {"GroupNonUniformUMax", SpvOpGroupNonUniformUMax, 2, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, - {"GroupNonUniformFMax", SpvOpGroupNonUniformFMax, 2, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, - {"GroupNonUniformBitwiseAnd", SpvOpGroupNonUniformBitwiseAnd, 2, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, - {"GroupNonUniformBitwiseOr", SpvOpGroupNonUniformBitwiseOr, 2, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, - {"GroupNonUniformBitwiseXor", SpvOpGroupNonUniformBitwiseXor, 2, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, - {"GroupNonUniformLogicalAnd", SpvOpGroupNonUniformLogicalAnd, 2, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, - {"GroupNonUniformLogicalOr", SpvOpGroupNonUniformLogicalOr, 2, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, - {"GroupNonUniformLogicalXor", SpvOpGroupNonUniformLogicalXor, 2, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClustered, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, + {"GroupNonUniformIAdd", SpvOpGroupNonUniformIAdd, 3, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, + {"GroupNonUniformFAdd", SpvOpGroupNonUniformFAdd, 3, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, + {"GroupNonUniformIMul", SpvOpGroupNonUniformIMul, 3, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, + {"GroupNonUniformFMul", SpvOpGroupNonUniformFMul, 3, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, + {"GroupNonUniformSMin", SpvOpGroupNonUniformSMin, 3, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, + {"GroupNonUniformUMin", SpvOpGroupNonUniformUMin, 3, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, + {"GroupNonUniformFMin", SpvOpGroupNonUniformFMin, 3, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, + {"GroupNonUniformSMax", SpvOpGroupNonUniformSMax, 3, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, + {"GroupNonUniformUMax", SpvOpGroupNonUniformUMax, 3, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, + {"GroupNonUniformFMax", SpvOpGroupNonUniformFMax, 3, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, + {"GroupNonUniformBitwiseAnd", SpvOpGroupNonUniformBitwiseAnd, 3, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, + {"GroupNonUniformBitwiseOr", SpvOpGroupNonUniformBitwiseOr, 3, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, + {"GroupNonUniformBitwiseXor", SpvOpGroupNonUniformBitwiseXor, 3, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, + {"GroupNonUniformLogicalAnd", SpvOpGroupNonUniformLogicalAnd, 3, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, + {"GroupNonUniformLogicalOr", SpvOpGroupNonUniformLogicalOr, 3, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, + {"GroupNonUniformLogicalXor", SpvOpGroupNonUniformLogicalXor, 3, pygen_variable_caps_GroupNonUniformArithmeticGroupNonUniformClusteredGroupNonUniformPartitionedNV, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, {"GroupNonUniformQuadBroadcast", SpvOpGroupNonUniformQuadBroadcast, 1, pygen_variable_caps_GroupNonUniformQuad, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, {"GroupNonUniformQuadSwap", SpvOpGroupNonUniformQuadSwap, 1, pygen_variable_caps_GroupNonUniformQuad, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,3)}, {"SubgroupBallotKHR", SpvOpSubgroupBallotKHR, 1, pygen_variable_caps_SubgroupBallotKHR, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 1, pygen_variable_exts_SPV_KHR_shader_ballot, 0xffffffffu}, diff --git a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp index e2d5e46f9..bbc70041a 100644 --- a/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp +++ b/3rdparty/spirv-tools/include/spirv-tools/optimizer.hpp @@ -208,6 +208,13 @@ class Optimizer { // A null pass does nothing to the SPIR-V module to be optimized. Optimizer::PassToken CreateNullPass(); +// Creates a strip-atomic-counter-memory pass. +// A strip-atomic-counter-memory pass removes all usages of the +// AtomicCounterMemory bit in Memory Semantics bitmasks. This bit is a no-op in +// Vulkan, so isn't needed in that env. And the related capability is not +// allowed in WebGPU, so it is not allowed in that env. +Optimizer::PassToken CreateStripAtomicCounterMemoryPass(); + // Creates a strip-debug-info pass. // A strip-debug-info pass removes all debug instructions (as documented in // Section 3.32.2 of the SPIR-V spec) of the SPIR-V module to be optimized. diff --git a/3rdparty/spirv-tools/source/opcode.cpp b/3rdparty/spirv-tools/source/opcode.cpp index da096a404..ddf2deb9a 100644 --- a/3rdparty/spirv-tools/source/opcode.cpp +++ b/3rdparty/spirv-tools/source/opcode.cpp @@ -605,3 +605,35 @@ bool spvOpcodeIsDebug(SpvOp opcode) { return false; } } + +std::vector spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode) { + switch (opcode) { + case SpvOpMemoryBarrier: + return {1}; + case SpvOpAtomicStore: + case SpvOpControlBarrier: + case SpvOpAtomicFlagClear: + case SpvOpMemoryNamedBarrier: + return {2}; + case SpvOpAtomicLoad: + case SpvOpAtomicExchange: + case SpvOpAtomicIIncrement: + case SpvOpAtomicIDecrement: + case SpvOpAtomicIAdd: + case SpvOpAtomicISub: + case SpvOpAtomicSMin: + case SpvOpAtomicUMin: + case SpvOpAtomicSMax: + case SpvOpAtomicUMax: + case SpvOpAtomicAnd: + case SpvOpAtomicOr: + case SpvOpAtomicXor: + case SpvOpAtomicFlagTestAndSet: + return {4}; + case SpvOpAtomicCompareExchange: + case SpvOpAtomicCompareExchangeWeak: + return {4, 5}; + default: + return {}; + } +} diff --git a/3rdparty/spirv-tools/source/opcode.h b/3rdparty/spirv-tools/source/opcode.h index 76f9a0e84..ed64f1b5a 100644 --- a/3rdparty/spirv-tools/source/opcode.h +++ b/3rdparty/spirv-tools/source/opcode.h @@ -133,4 +133,8 @@ bool spvOpcodeIsScalarizable(SpvOp opcode); // Returns true if the given opcode is a debug instruction. bool spvOpcodeIsDebug(SpvOp opcode); +// Returns a vector containing the indices of the memory semantics +// operands for |opcode|. +std::vector spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode); + #endif // SOURCE_OPCODE_H_ diff --git a/3rdparty/spirv-tools/source/opt/CMakeLists.txt b/3rdparty/spirv-tools/source/opt/CMakeLists.txt index f2ffcca8c..53901a4e2 100644 --- a/3rdparty/spirv-tools/source/opt/CMakeLists.txt +++ b/3rdparty/spirv-tools/source/opt/CMakeLists.txt @@ -96,6 +96,7 @@ set(SPIRV_TOOLS_OPT_SOURCES simplification_pass.h ssa_rewrite_pass.h strength_reduction_pass.h + strip_atomic_counter_memory_pass.h strip_debug_info_pass.h strip_reflect_info_pass.h struct_cfg_analysis.h @@ -189,6 +190,7 @@ set(SPIRV_TOOLS_OPT_SOURCES simplification_pass.cpp ssa_rewrite_pass.cpp strength_reduction_pass.cpp + strip_atomic_counter_memory_pass.cpp strip_debug_info_pass.cpp strip_reflect_info_pass.cpp struct_cfg_analysis.cpp diff --git a/3rdparty/spirv-tools/source/opt/ccp_pass.cpp b/3rdparty/spirv-tools/source/opt/ccp_pass.cpp index 835619530..2de925020 100644 --- a/3rdparty/spirv-tools/source/opt/ccp_pass.cpp +++ b/3rdparty/spirv-tools/source/opt/ccp_pass.cpp @@ -271,6 +271,7 @@ bool CCPPass::ReplaceValues() { uint32_t id = it.first; uint32_t cst_id = it.second; if (!IsVaryingValue(cst_id) && id != cst_id) { + context()->KillNamesAndDecorates(id); retval |= context()->ReplaceAllUsesWith(id, cst_id); } } diff --git a/3rdparty/spirv-tools/source/opt/folding_rules.cpp b/3rdparty/spirv-tools/source/opt/folding_rules.cpp index 327431969..18d51498f 100644 --- a/3rdparty/spirv-tools/source/opt/folding_rules.cpp +++ b/3rdparty/spirv-tools/source/opt/folding_rules.cpp @@ -2167,6 +2167,37 @@ FoldingRule VectorShuffleFeedingShuffle() { }; } +// Removes duplicate ids from the interface list of an OpEntryPoint +// instruction. +FoldingRule RemoveRedundantOperands() { + return [](IRContext*, Instruction* inst, + const std::vector&) { + assert(inst->opcode() == SpvOpEntryPoint && + "Wrong opcode. Should be OpEntryPoint."); + bool has_redundant_operand = false; + std::unordered_set seen_operands; + std::vector new_operands; + + new_operands.emplace_back(inst->GetOperand(0)); + new_operands.emplace_back(inst->GetOperand(1)); + new_operands.emplace_back(inst->GetOperand(2)); + for (uint32_t i = 3; i < inst->NumOperands(); ++i) { + if (seen_operands.insert(inst->GetSingleWordOperand(i)).second) { + new_operands.emplace_back(inst->GetOperand(i)); + } else { + has_redundant_operand = true; + } + } + + if (!has_redundant_operand) { + return false; + } + + inst->SetInOperands(std::move(new_operands)); + return true; + }; +} + } // namespace FoldingRules::FoldingRules() { @@ -2183,6 +2214,8 @@ FoldingRules::FoldingRules() { rules_[SpvOpDot].push_back(DotProductDoingExtract()); + rules_[SpvOpEntryPoint].push_back(RemoveRedundantOperands()); + rules_[SpvOpExtInst].push_back(RedundantFMix()); rules_[SpvOpFAdd].push_back(RedundantFAdd()); diff --git a/3rdparty/spirv-tools/source/opt/optimizer.cpp b/3rdparty/spirv-tools/source/opt/optimizer.cpp index 344f3dc3b..5fb487577 100644 --- a/3rdparty/spirv-tools/source/opt/optimizer.cpp +++ b/3rdparty/spirv-tools/source/opt/optimizer.cpp @@ -219,6 +219,8 @@ Optimizer& Optimizer::RegisterSizePasses() { Optimizer& Optimizer::RegisterWebGPUPasses() { return RegisterPass(CreateStripDebugInfoPass()) + .RegisterPass(CreateStripAtomicCounterMemoryPass()) + .RegisterPass(CreateEliminateDeadConstantPass()) .RegisterPass(CreateFlattenDecorationPass()) .RegisterPass(CreateAggressiveDCEPass()) .RegisterPass(CreateDeadBranchElimPass()); @@ -266,7 +268,9 @@ bool Optimizer::RegisterPassFromFlag(const std::string& flag) { // // Both Pass::name() and Pass::desc() should be static class members so they // can be invoked without creating a pass instance. - if (pass_name == "strip-debug") { + if (pass_name == "strip-atomic-counter-memory") { + RegisterPass(CreateStripAtomicCounterMemoryPass()); + } else if (pass_name == "strip-debug") { RegisterPass(CreateStripDebugInfoPass()); } else if (pass_name == "strip-reflect") { RegisterPass(CreateStripReflectInfoPass()); @@ -529,6 +533,11 @@ Optimizer::PassToken CreateNullPass() { return MakeUnique(MakeUnique()); } +Optimizer::PassToken CreateStripAtomicCounterMemoryPass() { + return MakeUnique( + MakeUnique()); +} + Optimizer::PassToken CreateStripDebugInfoPass() { return MakeUnique( MakeUnique()); diff --git a/3rdparty/spirv-tools/source/opt/passes.h b/3rdparty/spirv-tools/source/opt/passes.h index 6f8081c94..2b9779302 100644 --- a/3rdparty/spirv-tools/source/opt/passes.h +++ b/3rdparty/spirv-tools/source/opt/passes.h @@ -63,6 +63,7 @@ #include "source/opt/simplification_pass.h" #include "source/opt/ssa_rewrite_pass.h" #include "source/opt/strength_reduction_pass.h" +#include "source/opt/strip_atomic_counter_memory_pass.h" #include "source/opt/strip_debug_info_pass.h" #include "source/opt/strip_reflect_info_pass.h" #include "source/opt/unify_const_pass.h" diff --git a/3rdparty/spirv-tools/source/opt/strip_atomic_counter_memory_pass.cpp b/3rdparty/spirv-tools/source/opt/strip_atomic_counter_memory_pass.cpp new file mode 100644 index 000000000..46a727cb7 --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/strip_atomic_counter_memory_pass.cpp @@ -0,0 +1,57 @@ +// Copyright (c) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "source/opt/strip_atomic_counter_memory_pass.h" +#include "source/opt/ir_context.h" + +namespace spvtools { +namespace opt { + +Pass::Status StripAtomicCounterMemoryPass::Process() { + bool changed = false; + context()->module()->ForEachInst([this, &changed](Instruction* inst) { + auto indices = spvOpcodeMemorySemanticsOperandIndices(inst->opcode()); + if (indices.empty()) return; + + for (auto idx : indices) { + auto mem_sem_id = inst->GetSingleWordOperand(idx); + const auto& mem_sem_inst = + context()->get_def_use_mgr()->GetDef(mem_sem_id); + // The spec explicitly says that this id must be an OpConstant + auto mem_sem_val = mem_sem_inst->GetSingleWordOperand(2); + if (!(mem_sem_val & SpvMemorySemanticsAtomicCounterMemoryMask)) { + continue; + } + mem_sem_val &= ~SpvMemorySemanticsAtomicCounterMemoryMask; + + analysis::Integer int_type(32, false); + const analysis::Type* uint32_type = + context()->get_type_mgr()->GetRegisteredType(&int_type); + auto* new_const = context()->get_constant_mgr()->GetConstant( + uint32_type, {mem_sem_val}); + auto* new_const_inst = + context()->get_constant_mgr()->GetDefiningInstruction(new_const); + auto new_const_id = new_const_inst->result_id(); + + inst->SetOperand(idx, {new_const_id}); + context()->UpdateDefUse(inst); + changed = true; + } + }); + + return changed ? Status::SuccessWithChange : Status::SuccessWithoutChange; +} + +} // namespace opt +} // namespace spvtools diff --git a/3rdparty/spirv-tools/source/opt/strip_atomic_counter_memory_pass.h b/3rdparty/spirv-tools/source/opt/strip_atomic_counter_memory_pass.h new file mode 100644 index 000000000..d94cf324b --- /dev/null +++ b/3rdparty/spirv-tools/source/opt/strip_atomic_counter_memory_pass.h @@ -0,0 +1,51 @@ +// Copyright (c) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef SOURCE_OPT_STRIP_ATOMIC_COUNT_MEMORY_PASS_H_ +#define SOURCE_OPT_STRIP_ATOMIC_COUNT_MEMORY_PASS_H_ + +#include "source/opt/ir_context.h" +#include "source/opt/module.h" +#include "source/opt/pass.h" + +namespace spvtools { +namespace opt { + +// Removes the AtomicCounterMemory bit from the value being passed into memory +// semantics. This bit being set is ignored in Vulkan environments and +// forbidden WebGPU ones. +class StripAtomicCounterMemoryPass : public Pass { + public: + const char* name() const override { return "strip-atomic-counter-memory"; } + Status Process() override; + + IRContext::Analysis GetPreservedAnalyses() override { + return IRContext::kAnalysisInstrToBlockMapping | + IRContext::kAnalysisDecorations | IRContext::kAnalysisCombinators | + IRContext::kAnalysisCFG | IRContext::kAnalysisDominatorAnalysis | + IRContext::kAnalysisLoopAnalysis | IRContext::kAnalysisNameMap | + IRContext::kAnalysisScalarEvolution | + IRContext::kAnalysisRegisterPressure | + IRContext::kAnalysisValueNumberTable | + IRContext::kAnalysisStructuredCFG | + IRContext::kAnalysisBuiltinVarId | + IRContext::kAnalysisIdToFuncMapping | IRContext::kAnalysisTypes | + IRContext::kAnalysisDefUse | IRContext::kAnalysisConstants; + } +}; + +} // namespace opt +} // namespace spvtools + +#endif // SOURCE_OPT_STRIP_ATOMIC_COUNT_MEMORY_PASS_H_ diff --git a/3rdparty/spirv-tools/source/val/validate_function.cpp b/3rdparty/spirv-tools/source/val/validate_function.cpp index 9eebb1ca4..56090086c 100644 --- a/3rdparty/spirv-tools/source/val/validate_function.cpp +++ b/3rdparty/spirv-tools/source/val/validate_function.cpp @@ -24,6 +24,17 @@ namespace spvtools { namespace val { namespace { +// Returns true if |a| and |b| are instruction defining pointers that point to +// the same type. +bool ArePointersToSameType(val::Instruction* a, val::Instruction* b) { + if (a->opcode() != SpvOpTypePointer || b->opcode() != SpvOpTypePointer) { + return false; + } + + uint32_t a_type = a->GetOperandAs(2); + return a_type && (a_type == b->GetOperandAs(2)); +} + spv_result_t ValidateFunction(ValidationState_t& _, const Instruction* inst) { const auto function_type_id = inst->GetOperandAs(3); const auto function_type = _.FindDef(function_type_id); @@ -245,7 +256,10 @@ spv_result_t ValidateFunctionCall(ValidationState_t& _, const auto parameter_type_id = function_type->GetOperandAs(param_index); const auto parameter_type = _.FindDef(parameter_type_id); - if (!parameter_type || argument_type->id() != parameter_type->id()) { + if (!parameter_type || + (argument_type->id() != parameter_type->id() && + !(_.options()->relax_logical_pointer && + ArePointersToSameType(argument_type, parameter_type)))) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "OpFunctionCall Argument '" << _.getIdName(argument_id) << "'s type does not match Function '" @@ -287,7 +301,8 @@ spv_result_t ValidateFunctionCall(ValidationState_t& _, sc == SpvStorageClassStorageBuffer; const bool wg_vptr = _.features().variable_pointers && sc == SpvStorageClassWorkgroup; - if (!ssbo_vptr && !wg_vptr) { + const bool uc_ptr = sc == SpvStorageClassUniformConstant; + if (!ssbo_vptr && !wg_vptr && !uc_ptr) { return _.diag(SPV_ERROR_INVALID_ID, inst) << "Pointer operand " << _.getIdName(argument_id) << " must be a memory object declaration"; diff --git a/3rdparty/spirv-tools/source/val/validate_instruction.cpp b/3rdparty/spirv-tools/source/val/validate_instruction.cpp index 17949d22a..a626103d3 100644 --- a/3rdparty/spirv-tools/source/val/validate_instruction.cpp +++ b/3rdparty/spirv-tools/source/val/validate_instruction.cpp @@ -55,6 +55,18 @@ std::string ToString(const CapabilitySet& capabilities, return ss.str(); } +bool IsValidWebGPUStorageClass(SpvStorageClass storage_class) { + return storage_class == SpvStorageClassUniformConstant || + storage_class == SpvStorageClassUniform || + storage_class == SpvStorageClassStorageBuffer || + storage_class == SpvStorageClassInput || + storage_class == SpvStorageClassOutput || + storage_class == SpvStorageClassImage || + storage_class == SpvStorageClassWorkgroup || + storage_class == SpvStorageClassPrivate || + storage_class == SpvStorageClassFunction; +} + // Returns capabilities that enable an opcode. An empty result is interpreted // as no prohibition of use of the opcode. If the result is non-empty, then // the opcode may only be used if at least one of the capabilities is specified @@ -483,6 +495,15 @@ spv_result_t InstructionPass(ValidationState_t& _, const Instruction* inst) { if (auto error = LimitCheckNumVars(_, inst->id(), storage_class)) { return error; } + + if (spvIsWebGPUEnv(_.context()->target_env) && + !IsValidWebGPUStorageClass(storage_class)) { + return _.diag(SPV_ERROR_INVALID_BINARY, inst) + << "For WebGPU, OpVariable storage class must be one of " + "UniformConstant, Uniform, StorageBuffer, Input, Output, " + "Image, Workgroup, Private, Function for WebGPU"; + } + if (storage_class == SpvStorageClassGeneric) return _.diag(SPV_ERROR_INVALID_BINARY, inst) << "OpVariable storage class cannot be Generic"; @@ -506,6 +527,15 @@ spv_result_t InstructionPass(ValidationState_t& _, const Instruction* inst) { "outside of a function"; } } + } else if (opcode == SpvOpTypePointer) { + const auto storage_class = inst->GetOperandAs(1); + if (spvIsWebGPUEnv(_.context()->target_env) && + !IsValidWebGPUStorageClass(storage_class)) { + return _.diag(SPV_ERROR_INVALID_BINARY, inst) + << "For WebGPU, OpTypePointer storage class must be one of " + "UniformConstant, Uniform, StorageBuffer, Input, Output, " + "Image, Workgroup, Private, Function"; + } } // SPIR-V Spec 2.16.3: Validation Rules for Kernel Capabilities: The diff --git a/3rdparty/spirv-tools/source/val/validate_mode_setting.cpp b/3rdparty/spirv-tools/source/val/validate_mode_setting.cpp index c1bfc2740..a2006bfc5 100644 --- a/3rdparty/spirv-tools/source/val/validate_mode_setting.cpp +++ b/3rdparty/spirv-tools/source/val/validate_mode_setting.cpp @@ -344,6 +344,7 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _, case SpvExecutionModeOriginLowerLeft: case SpvExecutionModeEarlyFragmentTests: case SpvExecutionModeDepthReplacing: + case SpvExecutionModeDepthGreater: case SpvExecutionModeDepthLess: case SpvExecutionModeDepthUnchanged: if (!std::all_of(models->begin(), models->end(), @@ -411,6 +412,21 @@ spv_result_t ValidateExecutionMode(ValidationState_t& _, } } + if (spvIsWebGPUEnv(_.context()->target_env)) { + if (mode != SpvExecutionModeOriginUpperLeft && + mode != SpvExecutionModeDepthReplacing && + mode != SpvExecutionModeDepthGreater && + mode != SpvExecutionModeDepthLess && + mode != SpvExecutionModeDepthUnchanged && + mode != SpvExecutionModeLocalSize && + mode != SpvExecutionModeLocalSizeHint) { + return _.diag(SPV_ERROR_INVALID_DATA, inst) + << "Execution mode must be one of OriginUpperLeft, " + "DepthReplacing, DepthGreater, DepthLess, DepthUnchanged, " + "LocalSize, or LocalSizeHint for WebGPU environment."; + } + } + return SPV_SUCCESS; } diff --git a/3rdparty/spirv-tools/test/opt/CMakeLists.txt b/3rdparty/spirv-tools/test/opt/CMakeLists.txt index c8deb39a9..398baa482 100644 --- a/3rdparty/spirv-tools/test/opt/CMakeLists.txt +++ b/3rdparty/spirv-tools/test/opt/CMakeLists.txt @@ -77,6 +77,7 @@ add_spvtools_unittest(TARGET opt set_spec_const_default_value_test.cpp simplification_test.cpp strength_reduction_test.cpp + strip_atomic_counter_memory_test.cpp strip_debug_info_test.cpp strip_reflect_info_test.cpp struct_cfg_analysis_test.cpp diff --git a/3rdparty/spirv-tools/test/opt/ccp_test.cpp b/3rdparty/spirv-tools/test/opt/ccp_test.cpp index 20d883b0a..2ee7cce2f 100644 --- a/3rdparty/spirv-tools/test/opt/ccp_test.cpp +++ b/3rdparty/spirv-tools/test/opt/ccp_test.cpp @@ -896,6 +896,35 @@ OpFunctionEnd SinglePassRunAndMatch(text, true); } +TEST_F(CCPTest, FoldWithDecoration) { + const std::string text = R"( +; CHECK: OpCapability +; CHECK-NOT: OpDecorate +; CHECK: OpFunctionEnd + OpCapability Shader + %1 = OpExtInstImport "GLSL.std.450" + OpMemoryModel Logical GLSL450 + OpEntryPoint Fragment %2 "main" + OpExecutionMode %2 OriginUpperLeft + OpSource ESSL 310 + OpDecorate %3 RelaxedPrecision + %void = OpTypeVoid + %5 = OpTypeFunction %void + %float = OpTypeFloat 32 + %v3float = OpTypeVector %float 3 + %float_0 = OpConstant %float 0 + %v4float = OpTypeVector %float 4 + %10 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 + %2 = OpFunction %void None %5 + %11 = OpLabel + %3 = OpVectorShuffle %v3float %10 %10 0 1 2 + OpReturn + OpFunctionEnd +)"; + + SinglePassRunAndMatch(text, true); +} + } // namespace } // namespace opt } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/opt/fold_test.cpp b/3rdparty/spirv-tools/test/opt/fold_test.cpp index b3c344115..7458e1ce3 100644 --- a/3rdparty/spirv-tools/test/opt/fold_test.cpp +++ b/3rdparty/spirv-tools/test/opt/fold_test.cpp @@ -6211,6 +6211,106 @@ INSTANTIATE_TEST_SUITE_P(VectorShuffleMatchingTest, MatchingInstructionWithNoRes 9, true) )); +using EntryPointFoldingTest = +::testing::TestWithParam>; + +TEST_P(EntryPointFoldingTest, Case) { + const auto& tc = GetParam(); + + // Build module. + std::unique_ptr context = + BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.test_body, + SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); + ASSERT_NE(nullptr, context); + + // Fold the instruction to test. + Instruction* inst = nullptr; + inst = &*context->module()->entry_points().begin(); + assert(inst && "Invalid test. Could not find entry point instruction to fold."); + std::unique_ptr original_inst(inst->Clone(context.get())); + bool succeeded = context->get_instruction_folder().FoldInstruction(inst); + EXPECT_EQ(succeeded, tc.expected_result); + if (succeeded) { + Match(tc.test_body, context.get()); + } +} + +INSTANTIATE_TEST_SUITE_P(OpEntryPointFoldingTest, EntryPointFoldingTest, +::testing::Values( + // Test case 0: Basic test 1 + InstructionFoldingCase(std::string() + + "; CHECK: OpEntryPoint Fragment %2 \"main\" %3\n" + + "OpCapability Shader\n" + + "%1 = OpExtInstImport \"GLSL.std.450\"\n" + + "OpMemoryModel Logical GLSL450\n" + + "OpEntryPoint Fragment %2 \"main\" %3 %3 %3\n" + + "OpExecutionMode %2 OriginUpperLeft\n" + + "OpSource GLSL 430\n" + + "OpDecorate %3 Location 0\n" + + "%void = OpTypeVoid\n" + + "%5 = OpTypeFunction %void\n" + + "%float = OpTypeFloat 32\n" + + "%v4float = OpTypeVector %float 4\n" + + "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" + + "%3 = OpVariable %_ptr_Output_v4float Output\n" + + "%int = OpTypeInt 32 1\n" + + "%int_0 = OpConstant %int 0\n" + +"%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" + + "%2 = OpFunction %void None %5\n" + + "%12 = OpLabel\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 9, true), + InstructionFoldingCase(std::string() + + "; CHECK: OpEntryPoint Fragment %2 \"main\" %3 %4\n" + + "OpCapability Shader\n" + + "%1 = OpExtInstImport \"GLSL.std.450\"\n" + + "OpMemoryModel Logical GLSL450\n" + + "OpEntryPoint Fragment %2 \"main\" %3 %4 %3\n" + + "OpExecutionMode %2 OriginUpperLeft\n" + + "OpSource GLSL 430\n" + + "OpDecorate %3 Location 0\n" + + "%void = OpTypeVoid\n" + + "%5 = OpTypeFunction %void\n" + + "%float = OpTypeFloat 32\n" + + "%v4float = OpTypeVector %float 4\n" + + "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" + + "%3 = OpVariable %_ptr_Output_v4float Output\n" + + "%4 = OpVariable %_ptr_Output_v4float Output\n" + + "%int = OpTypeInt 32 1\n" + + "%int_0 = OpConstant %int 0\n" + +"%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" + + "%2 = OpFunction %void None %5\n" + + "%12 = OpLabel\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 9, true), + InstructionFoldingCase(std::string() + + "; CHECK: OpEntryPoint Fragment %2 \"main\" %4 %3\n" + + "OpCapability Shader\n" + + "%1 = OpExtInstImport \"GLSL.std.450\"\n" + + "OpMemoryModel Logical GLSL450\n" + + "OpEntryPoint Fragment %2 \"main\" %4 %4 %3\n" + + "OpExecutionMode %2 OriginUpperLeft\n" + + "OpSource GLSL 430\n" + + "OpDecorate %3 Location 0\n" + + "%void = OpTypeVoid\n" + + "%5 = OpTypeFunction %void\n" + + "%float = OpTypeFloat 32\n" + + "%v4float = OpTypeVector %float 4\n" + + "%_ptr_Output_v4float = OpTypePointer Output %v4float\n" + + "%3 = OpVariable %_ptr_Output_v4float Output\n" + + "%4 = OpVariable %_ptr_Output_v4float Output\n" + + "%int = OpTypeInt 32 1\n" + + "%int_0 = OpConstant %int 0\n" + +"%_ptr_PushConstant_v4float = OpTypePointer PushConstant %v4float\n" + + "%2 = OpFunction %void None %5\n" + + "%12 = OpLabel\n" + + "OpReturn\n" + + "OpFunctionEnd\n", + 9, true) +)); + } // namespace } // namespace opt } // namespace spvtools diff --git a/3rdparty/spirv-tools/test/opt/optimizer_test.cpp b/3rdparty/spirv-tools/test/opt/optimizer_test.cpp index 52838d5b1..77d2d1a25 100644 --- a/3rdparty/spirv-tools/test/opt/optimizer_test.cpp +++ b/3rdparty/spirv-tools/test/opt/optimizer_test.cpp @@ -231,9 +231,12 @@ TEST(Optimizer, WebGPUModeSetsCorrectPasses) { for (auto name = pass_names.begin(); name != pass_names.end(); ++name) registered_passes.push_back(*name); - std::vector expected_passes = { - "eliminate-dead-branches", "eliminate-dead-code-aggressive", - "flatten-decorations", "strip-debug"}; + std::vector expected_passes = {"eliminate-dead-branches", + "eliminate-dead-code-aggressive", + "eliminate-dead-const", + "flatten-decorations", + "strip-debug", + "strip-atomic-counter-memory"}; std::sort(registered_passes.begin(), registered_passes.end()); std::sort(expected_passes.begin(), expected_passes.end()); @@ -265,7 +268,6 @@ TEST_P(WebGPUPassTest, Ran) { class ValidatorOptions validator_options; ASSERT_TRUE(opt.Run(binary.data(), binary.size(), &optimized, validator_options, true)); - std::string disassembly; tools.Disassemble(optimized.data(), optimized.size(), &disassembly); @@ -274,7 +276,7 @@ TEST_P(WebGPUPassTest, Ran) { } INSTANTIATE_TEST_SUITE_P( - WebGPU, WebGPUPassTest, + Optimizer, WebGPUPassTest, ::testing::ValuesIn(std::vector{ // FlattenDecorations {// input @@ -346,7 +348,95 @@ INSTANTIATE_TEST_SUITE_P( "OpReturn\n" "OpFunctionEnd\n", // pass - "strip-debug"}})); + "strip-debug"}, + // Eliminate Dead Constants + {// input + "OpCapability Shader\n" + "OpCapability VulkanMemoryModelKHR\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical VulkanKHR\n" + "OpEntryPoint Vertex %func \"shader\"\n" + "%u32 = OpTypeInt 32 0\n" + "%u32_ptr = OpTypePointer Workgroup %u32\n" + "%u32_var = OpVariable %u32_ptr Workgroup\n" + "%u32_1 = OpConstant %u32 1\n" + "%cross_device = OpConstant %u32 0\n" + "%relaxed = OpConstant %u32 0\n" + "%acquire_release_atomic_counter_workgroup = OpConstant %u32 1288\n" + "%void = OpTypeVoid\n" + "%void_f = OpTypeFunction %void\n" + "%func = OpFunction %void None %void_f\n" + "%label = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", + // expected + "OpCapability Shader\n" + "OpCapability VulkanMemoryModelKHR\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical VulkanKHR\n" + "OpEntryPoint Vertex %1 \"shader\"\n" + "%uint = OpTypeInt 32 0\n" + "%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint\n" + "%4 = OpVariable %_ptr_Workgroup_uint Workgroup\n" + "%void = OpTypeVoid\n" + "%10 = OpTypeFunction %void\n" + "%1 = OpFunction %void None %10\n" + "%11 = OpLabel\n" + "OpReturn\n" + "OpFunctionEnd\n", + "eliminate-dead-const"}, + // Strip Atomic Counter Memory + {// input + "OpCapability Shader\n" + "OpCapability VulkanMemoryModelKHR\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical VulkanKHR\n" + "OpEntryPoint Vertex %func \"shader\"\n" + "%u32 = OpTypeInt 32 0\n" + "%u32_ptr = OpTypePointer Workgroup %u32\n" + "%u32_var = OpVariable %u32_ptr Workgroup\n" + "%u32_0 = OpConstant %u32 0\n" + "%u32_1 = OpConstant %u32 1\n" + "%cross_device = OpConstant %u32 0\n" + "%acquire_release_atomic_counter_workgroup = OpConstant %u32 1288\n" + "%void = OpTypeVoid\n" + "%void_f = OpTypeFunction %void\n" + "%func = OpFunction %void None %void_f\n" + "%label = OpLabel\n" + "%val0 = OpAtomicStore %u32_var %cross_device " + "%acquire_release_atomic_counter_workgroup %u32_1\n" + "%val1 = OpAtomicIIncrement %u32 %u32_var %cross_device " + "%acquire_release_atomic_counter_workgroup\n" + "%val2 = OpAtomicCompareExchange %u32 %u32_var %cross_device " + "%acquire_release_atomic_counter_workgroup " + "%acquire_release_atomic_counter_workgroup %u32_0 %u32_0\n" + "OpReturn\n" + "OpFunctionEnd\n", + // expected + "OpCapability Shader\n" + "OpCapability VulkanMemoryModelKHR\n" + "OpExtension \"SPV_KHR_vulkan_memory_model\"\n" + "OpMemoryModel Logical VulkanKHR\n" + "OpEntryPoint Vertex %1 \"shader\"\n" + "%uint = OpTypeInt 32 0\n" + "%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint\n" + "%4 = OpVariable %_ptr_Workgroup_uint Workgroup\n" + "%uint_0 = OpConstant %uint 0\n" + "%uint_1 = OpConstant %uint 1\n" + "%uint_0_0 = OpConstant %uint 0\n" + "%void = OpTypeVoid\n" + "%10 = OpTypeFunction %void\n" + "%uint_264 = OpConstant %uint 264\n" + "%1 = OpFunction %void None %10\n" + "%11 = OpLabel\n" + "OpAtomicStore %4 %uint_0_0 %uint_264 %uint_1\n" + "%12 = OpAtomicIIncrement %uint %4 %uint_0_0 %uint_264\n" + "%13 = OpAtomicCompareExchange %uint %4 %uint_0_0 %uint_264 %uint_264 " + "%uint_0 %uint_0\n" + "OpReturn\n" + "OpFunctionEnd\n", + // pass + "strip-atomic-counter-memory"}})); } // namespace } // namespace opt diff --git a/3rdparty/spirv-tools/test/opt/strip_atomic_counter_memory_test.cpp b/3rdparty/spirv-tools/test/opt/strip_atomic_counter_memory_test.cpp new file mode 100644 index 000000000..8756e815a --- /dev/null +++ b/3rdparty/spirv-tools/test/opt/strip_atomic_counter_memory_test.cpp @@ -0,0 +1,406 @@ +// Copyright (c) 2019 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "test/opt/pass_fixture.h" +#include "test/opt/pass_utils.h" + +namespace spvtools { +namespace opt { +namespace { + +typedef std::tuple StripAtomicCounterMemoryParam; + +using MemorySemanticsModified = + PassTest<::testing::TestWithParam>; +using NonMemorySemanticsUnmodifiedTest = PassTest<::testing::Test>; + +void operator+=(std::vector& lhs, const char* rhs) { + lhs.push_back(rhs); +} + +std::string GetConstDecl(std::string val) { + std::string decl; + decl += "%uint_" + val + " = OpConstant %uint " + val; + return decl; +} + +std::string GetUnchangedString(std::string(generate_inst)(std::string), + std::string val) { + std::string decl = GetConstDecl(val); + std::string inst = generate_inst(val); + + std::vector result = { + // clang-format off + "OpCapability Shader", + "OpCapability VulkanMemoryModelKHR", + "OpExtension \"SPV_KHR_vulkan_memory_model\"", + "OpMemoryModel Logical VulkanKHR", + "OpEntryPoint Vertex %1 \"shader\"", + "%uint = OpTypeInt 32 0", +"%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint", + "%4 = OpVariable %_ptr_Workgroup_uint Workgroup", + "%uint_0 = OpConstant %uint 0", + "%uint_1 = OpConstant %uint 1", + "%void = OpTypeVoid", + "%8 = OpTypeFunction %void", + decl.c_str(), + "%1 = OpFunction %void None %8", + "%10 = OpLabel", + inst.c_str(), + "OpReturn", + "OpFunctionEnd" + // clang-format on + }; + return JoinAllInsts(result); +} + +std::string GetChangedString(std::string(generate_inst)(std::string), + std::string orig, std::string changed) { + std::string orig_decl = GetConstDecl(orig); + std::string changed_decl = GetConstDecl(changed); + std::string inst = generate_inst(changed); + + std::vector result = { + // clang-format off + "OpCapability Shader", + "OpCapability VulkanMemoryModelKHR", + "OpExtension \"SPV_KHR_vulkan_memory_model\"", + "OpMemoryModel Logical VulkanKHR", + "OpEntryPoint Vertex %1 \"shader\"", + "%uint = OpTypeInt 32 0", +"%_ptr_Workgroup_uint = OpTypePointer Workgroup %uint", + "%4 = OpVariable %_ptr_Workgroup_uint Workgroup", + "%uint_0 = OpConstant %uint 0", + "%uint_1 = OpConstant %uint 1", + "%void = OpTypeVoid", + "%8 = OpTypeFunction %void", + orig_decl.c_str() }; + // clang-format on + if (changed != "0") result += changed_decl.c_str(); + result += "%1 = OpFunction %void None %8"; + result += "%10 = OpLabel"; + result += inst.c_str(); + result += "OpReturn"; + result += "OpFunctionEnd"; + return JoinAllInsts(result); +} + +std::tuple GetInputAndExpected( + std::string(generate_inst)(std::string), + StripAtomicCounterMemoryParam param) { + std::string orig = std::get<0>(param); + std::string changed = std::get<1>(param); + std::string input = GetUnchangedString(generate_inst, orig); + std::string expected = orig == changed + ? GetUnchangedString(generate_inst, changed) + : GetChangedString(generate_inst, orig, changed); + return std::make_tuple(input, expected); +} + +std::string GetOpControlBarrierInst(std::string val) { + return "OpControlBarrier %uint_1 %uint_1 %uint_" + val; +} + +TEST_P(MemorySemanticsModified, OpControlBarrier) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpControlBarrierInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpMemoryBarrierInst(std::string val) { + return "OpMemoryBarrier %uint_1 %uint_" + val; +} + +TEST_P(MemorySemanticsModified, OpMemoryBarrier) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpMemoryBarrierInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicLoadInst(std::string val) { + return "%11 = OpAtomicLoad %uint %4 %uint_1 %uint_" + val; +} + +TEST_P(MemorySemanticsModified, OpAtomicLoad) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicLoadInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicStoreInst(std::string val) { + return "OpAtomicStore %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicStore) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicStoreInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicExchangeInst(std::string val) { + return "%11 = OpAtomicExchange %uint %4 %uint_1 %uint_" + val + " %uint_0"; +} + +TEST_P(MemorySemanticsModified, OpAtomicExchange) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicExchangeInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicCompareExchangeInst(std::string val) { + return "%11 = OpAtomicCompareExchange %uint %4 %uint_1 %uint_" + val + + " %uint_" + val + " %uint_0 %uint_0"; +} + +TEST_P(MemorySemanticsModified, OpAtomicCompareExchange) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicCompareExchangeInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicCompareExchangeWeakInst(std::string val) { + return "%11 = OpAtomicCompareExchangeWeak %uint %4 %uint_1 %uint_" + val + + " %uint_" + val + " %uint_0 %uint_0"; +} + +TEST_P(MemorySemanticsModified, OpAtomicCompareExchangeWeak) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicCompareExchangeWeakInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicIIncrementInst(std::string val) { + return "%11 = OpAtomicIIncrement %uint %4 %uint_1 %uint_" + val; +} + +TEST_P(MemorySemanticsModified, OpAtomicIIncrement) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicIIncrementInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicIDecrementInst(std::string val) { + return "%11 = OpAtomicIDecrement %uint %4 %uint_1 %uint_" + val; +} + +TEST_P(MemorySemanticsModified, OpAtomicIDecrement) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicIDecrementInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicIAddInst(std::string val) { + return "%11 = OpAtomicIAdd %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicIAdd) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicIAddInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicISubInst(std::string val) { + return "%11 = OpAtomicISub %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicISub) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicISubInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicSMinInst(std::string val) { + return "%11 = OpAtomicSMin %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicSMin) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicSMinInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicUMinInst(std::string val) { + return "%11 = OpAtomicUMin %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicUMin) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicUMinInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicSMaxInst(std::string val) { + return "%11 = OpAtomicSMax %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicSMax) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicSMaxInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicUMaxInst(std::string val) { + return "%11 = OpAtomicUMax %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicUMax) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicUMaxInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicAndInst(std::string val) { + return "%11 = OpAtomicAnd %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicAnd) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicAndInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicOrInst(std::string val) { + return "%11 = OpAtomicOr %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicOr) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicOrInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicXorInst(std::string val) { + return "%11 = OpAtomicXor %uint %4 %uint_1 %uint_" + val + " %uint_1"; +} + +TEST_P(MemorySemanticsModified, OpAtomicXor) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicXorInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicFlagTestAndSetInst(std::string val) { + return "%11 = OpAtomicFlagTestAndSet %uint %4 %uint_1 %uint_" + val; +} + +TEST_P(MemorySemanticsModified, OpAtomicFlagTestAndSet) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicFlagTestAndSetInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpAtomicFlagClearInst(std::string val) { + return "OpAtomicFlagClear %4 %uint_1 %uint_" + val; +} + +TEST_P(MemorySemanticsModified, OpAtomicFlagClear) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpAtomicFlagClearInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetOpMemoryNamedBarrierInst(std::string val) { + return "OpMemoryNamedBarrier %4 %uint_1 %uint_" + val; +} + +TEST_P(MemorySemanticsModified, OpMemoryNamedBarrier) { + std::string input, expected; + std::tie(input, expected) = + GetInputAndExpected(GetOpMemoryNamedBarrierInst, GetParam()); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +// clang-format off +INSTANTIATE_TEST_SUITE_P( + StripAtomicCounterMemoryTest, MemorySemanticsModified, + ::testing::ValuesIn(std::vector({ + std::make_tuple("1024", "0"), + std::make_tuple("5", "5"), + std::make_tuple("1288", "264"), + std::make_tuple("264", "264") + }))); +// clang-format on + +std::string GetNoMemorySemanticsPresentInst(std::string val) { + return "%11 = OpVariable %_ptr_Workgroup_uint Workgroup %uint_" + val; +} + +TEST_F(NonMemorySemanticsUnmodifiedTest, NoMemorySemanticsPresent) { + std::string input, expected; + StripAtomicCounterMemoryParam param = std::make_tuple("1288", "1288"); + std::tie(input, expected) = + GetInputAndExpected(GetNoMemorySemanticsPresentInst, param); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +std::string GetMemorySemanticsPresentInst(std::string val) { + return "%11 = OpAtomicIAdd %uint %4 %uint_1 %uint_" + val + " %uint_1288"; +} + +TEST_F(NonMemorySemanticsUnmodifiedTest, MemorySemanticsPresent) { + std::string input, expected; + StripAtomicCounterMemoryParam param = std::make_tuple("1288", "264"); + std::tie(input, expected) = + GetInputAndExpected(GetMemorySemanticsPresentInst, param); + SinglePassRunAndCheck(input, expected, + /* skip_nop = */ false); +} + +} // namespace +} // namespace opt +} // 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 e954f99af..635afad2b 100644 --- a/3rdparty/spirv-tools/test/val/val_decoration_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_decoration_test.cpp @@ -3023,6 +3023,8 @@ TEST_F(ValidateDecorations, OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %1 "main" OpExecutionMode %1 OriginUpperLeft + OpDecorate %struct Block + OpMemberDecorate %struct 0 Offset 0 %void = OpTypeVoid %voidfn = OpTypeFunction %void diff --git a/3rdparty/spirv-tools/test/val/val_function_test.cpp b/3rdparty/spirv-tools/test/val/val_function_test.cpp index f3dd15e76..6c0e8a108 100644 --- a/3rdparty/spirv-tools/test/val/val_function_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_function_test.cpp @@ -321,13 +321,15 @@ TEST_P(ValidateFunctionCall, NonMemoryObjectDeclarationNoVariablePointers) { std::string spirv = GenerateShaderAccessChain(storage_class, "", ""); const std::vector valid_storage_classes = { - "UniformConstant", "Function", "Private", "Workgroup", "AtomicCounter"}; + "Function", "Private", "Workgroup", "AtomicCounter"}; bool valid_sc = std::find(valid_storage_classes.begin(), valid_storage_classes.end(), storage_class) != valid_storage_classes.end(); CompileSuccessfully(spirv); - EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + spv_result_t expected_result = + storage_class == "UniformConstant" ? SPV_SUCCESS : SPV_ERROR_INVALID_ID; + EXPECT_EQ(expected_result, ValidateInstructions()); if (valid_sc) { EXPECT_THAT( getDiagnosticString(), @@ -338,7 +340,7 @@ TEST_P(ValidateFunctionCall, NonMemoryObjectDeclarationNoVariablePointers) { EXPECT_THAT(getDiagnosticString(), HasSubstr("StorageBuffer pointer operand 2[%gep] requires a " "variable pointers capability")); - } else { + } else if (storage_class != "UniformConstant") { EXPECT_THAT( getDiagnosticString(), HasSubstr("Invalid storage class for pointer operand 2[%gep]")); @@ -355,12 +357,12 @@ TEST_P(ValidateFunctionCall, "OpExtension \"SPV_KHR_variable_pointers\""); const std::vector valid_storage_classes = { - "UniformConstant", "Function", "Private", - "Workgroup", "StorageBuffer", "AtomicCounter"}; + "Function", "Private", "Workgroup", "StorageBuffer", "AtomicCounter"}; bool valid_sc = std::find(valid_storage_classes.begin(), valid_storage_classes.end(), storage_class) != valid_storage_classes.end(); - bool validate = storage_class == "StorageBuffer"; + bool validate = + storage_class == "StorageBuffer" || storage_class == "UniformConstant"; CompileSuccessfully(spirv); if (validate) { @@ -388,13 +390,13 @@ TEST_P(ValidateFunctionCall, NonMemoryObjectDeclarationVariablePointers) { "OpExtension \"SPV_KHR_variable_pointers\""); const std::vector valid_storage_classes = { - "UniformConstant", "Function", "Private", - "Workgroup", "StorageBuffer", "AtomicCounter"}; + "Function", "Private", "Workgroup", "StorageBuffer", "AtomicCounter"}; bool valid_sc = std::find(valid_storage_classes.begin(), valid_storage_classes.end(), storage_class) != valid_storage_classes.end(); - bool validate = - storage_class == "StorageBuffer" || storage_class == "Workgroup"; + bool validate = storage_class == "StorageBuffer" || + storage_class == "Workgroup" || + storage_class == "UniformConstant"; CompileSuccessfully(spirv); if (validate) { diff --git a/3rdparty/spirv-tools/test/val/val_modes_test.cpp b/3rdparty/spirv-tools/test/val/val_modes_test.cpp index 41d42eed8..12f2b8ce9 100644 --- a/3rdparty/spirv-tools/test/val/val_modes_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_modes_test.cpp @@ -531,16 +531,24 @@ TEST_P(ValidateModeExecution, ExecutionMode) { std::ostringstream sstr; sstr << "OpCapability Shader\n"; - sstr << "OpCapability Geometry\n"; - sstr << "OpCapability Tessellation\n"; - sstr << "OpCapability TransformFeedback\n"; - if (!spvIsVulkanEnv(env)) { + if (!spvIsWebGPUEnv(env)) { + sstr << "OpCapability Geometry\n"; + sstr << "OpCapability Tessellation\n"; + sstr << "OpCapability TransformFeedback\n"; + } + if (!spvIsVulkanOrWebGPUEnv(env)) { sstr << "OpCapability Kernel\n"; if (env == SPV_ENV_UNIVERSAL_1_3) { sstr << "OpCapability SubgroupDispatch\n"; } } - sstr << "OpMemoryModel Logical GLSL450\n"; + if (spvIsWebGPUEnv(env)) { + sstr << "OpCapability VulkanMemoryModelKHR\n"; + sstr << "OpExtension \"SPV_KHR_vulkan_memory_model\"\n"; + sstr << "OpMemoryModel Logical VulkanKHR\n"; + } else { + sstr << "OpMemoryModel Logical GLSL450\n"; + } sstr << "OpEntryPoint " << model << " %main \"main\"\n"; if (mode.find("LocalSizeId") == 0 || mode.find("LocalSizeHintId") == 0 || mode.find("SubgroupsPerWorkgroupId") == 0) { @@ -657,8 +665,8 @@ INSTANTIATE_TEST_SUITE_P( Values("Geometry", "TessellationControl", "TessellationEvaluation", "GLCompute", "Vertex", "Kernel"), Values("PixelCenterInteger", "OriginUpperLeft", "OriginLowerLeft", - "EarlyFragmentTests", "DepthReplacing", "DepthLess", - "DepthUnchanged"), + "EarlyFragmentTests", "DepthReplacing", "DepthGreater", + "DepthLess", "DepthUnchanged"), Values(SPV_ENV_UNIVERSAL_1_0))); INSTANTIATE_TEST_SUITE_P(ValidateModeKernelOnlyGoodSpv13, ValidateModeExecution, @@ -706,6 +714,39 @@ INSTANTIATE_TEST_SUITE_P( "SubgroupsPerWorkgroup 1", "SubgroupsPerWorkgroupId %int1"), Values(SPV_ENV_UNIVERSAL_1_3))); +INSTANTIATE_TEST_SUITE_P(ValidateModeGLComputeWebGPUWhitelistGood, + ValidateModeExecution, + Combine(Values(SPV_SUCCESS), Values(""), + Values("GLCompute"), Values("LocalSize 1 1 1"), + Values(SPV_ENV_WEBGPU_0))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeGLComputeWebGPUWhitelistBad, ValidateModeExecution, + Combine(Values(SPV_ERROR_INVALID_DATA), + Values("Execution mode must be one of OriginUpperLeft, " + "DepthReplacing, DepthGreater, DepthLess, DepthUnchanged, " + "LocalSize, or LocalSizeHint for WebGPU environment"), + Values("GLCompute"), Values("LocalSizeId %int1 %int1 %int1"), + Values(SPV_ENV_WEBGPU_0))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeFragmentWebGPUWhitelistGood, ValidateModeExecution, + Combine(Values(SPV_SUCCESS), Values(""), Values("Fragment"), + Values("OriginUpperLeft", "DepthReplacing", "DepthGreater", + "DepthLess", "DepthUnchanged"), + Values(SPV_ENV_WEBGPU_0))); + +INSTANTIATE_TEST_SUITE_P( + ValidateModeFragmentWebGPUWhitelistBad, ValidateModeExecution, + Combine(Values(SPV_ERROR_INVALID_DATA), + Values("Execution mode must be one of OriginUpperLeft, " + "DepthReplacing, DepthGreater, DepthLess, DepthUnchanged, " + "LocalSize, or LocalSizeHint for WebGPU environment"), + Values("Fragment"), + Values("PixelCenterInteger", "OriginLowerLeft", + "EarlyFragmentTests"), + Values(SPV_ENV_WEBGPU_0))); + TEST_F(ValidateModeExecution, MeshNVLocalSize) { const std::string spirv = R"( OpCapability Shader diff --git a/3rdparty/spirv-tools/test/val/val_storage_test.cpp b/3rdparty/spirv-tools/test/val/val_storage_test.cpp index 6f4fe4224..c02b7690a 100644 --- a/3rdparty/spirv-tools/test/val/val_storage_test.cpp +++ b/3rdparty/spirv-tools/test/val/val_storage_test.cpp @@ -26,7 +26,10 @@ namespace val { namespace { using ::testing::HasSubstr; +using ::testing::Values; using ValidateStorage = spvtest::ValidateBase; +using ValidateStorageClass = + spvtest::ValidateBase>; TEST_F(ValidateStorage, FunctionStorageInsideFunction) { char str[] = R"( @@ -186,6 +189,131 @@ TEST_F(ValidateStorage, GenericVariableInsideFunction) { HasSubstr("OpVariable storage class cannot be Generic")); } +TEST_F(ValidateStorage, RelaxedLogicalPointerFunctionParam) { + const auto str = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 +%intt = OpTypeInt 32 1 +%voidt = OpTypeVoid +%ptrt = OpTypePointer Function %intt +%vfunct = OpTypeFunction %voidt +%vifunct = OpTypeFunction %voidt %ptrt +%wgroupptrt = OpTypePointer Workgroup %intt +%wgroup = OpVariable %wgroupptrt Workgroup +%main = OpFunction %voidt None %vfunct +%mainl = OpLabel +%ret = OpFunctionCall %voidt %func %wgroup + OpReturn + OpFunctionEnd +%func = OpFunction %voidt None %vifunct +%arg = OpFunctionParameter %ptrt +%funcl = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str); + getValidatorOptions()->relax_logical_pointer = true; + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); +} + +TEST_F(ValidateStorage, RelaxedLogicalPointerFunctionParamBad) { + const auto str = R"( + OpCapability Shader + OpCapability Linkage + OpMemoryModel Logical GLSL450 +%floatt = OpTypeFloat 32 +%intt = OpTypeInt 32 1 +%voidt = OpTypeVoid +%ptrt = OpTypePointer Function %intt +%vfunct = OpTypeFunction %voidt +%vifunct = OpTypeFunction %voidt %ptrt +%wgroupptrt = OpTypePointer Workgroup %floatt +%wgroup = OpVariable %wgroupptrt Workgroup +%main = OpFunction %voidt None %vfunct +%mainl = OpLabel +%ret = OpFunctionCall %voidt %func %wgroup + OpReturn + OpFunctionEnd +%func = OpFunction %voidt None %vifunct +%arg = OpFunctionParameter %ptrt +%funcl = OpLabel + OpReturn + OpFunctionEnd +)"; + CompileSuccessfully(str); + getValidatorOptions()->relax_logical_pointer = true; + ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); + EXPECT_THAT(getDiagnosticString(), + HasSubstr("OpFunctionCall Argument '")); +} + +std::string GetVarDeclStr(const std::string& storage_class) { + if (storage_class != "Output" && storage_class != "Private" && + storage_class != "Function") { + return "%var = OpVariable %ptrt " + storage_class + "\n"; + } else { + return "%var = OpVariable %ptrt " + storage_class + " %null\n"; + } +} + +TEST_P(ValidateStorageClass, WebGPU) { + std::string storage_class = std::get<0>(GetParam()); + bool is_local = std::get<1>(GetParam()); + bool is_valid = std::get<2>(GetParam()); + std::string error = std::get<3>(GetParam()); + + std::string str = R"( + OpCapability Shader + OpCapability VulkanMemoryModelKHR + OpExtension "SPV_KHR_vulkan_memory_model" + OpMemoryModel Logical VulkanKHR + OpEntryPoint Fragment %func "func" + OpExecutionMode %func OriginUpperLeft +%intt = OpTypeInt 32 1 +%voidt = OpTypeVoid +%vfunct = OpTypeFunction %voidt +%null = OpConstantNull %intt +)"; + str += "%ptrt = OpTypePointer " + storage_class + " %intt\n"; + if (!is_local) str += GetVarDeclStr(storage_class); + str += R"( +%func = OpFunction %voidt None %vfunct +%funcl = OpLabel +)"; + if (is_local) str += GetVarDeclStr(storage_class); + str += R"( +OpReturn +OpFunctionEnd +)"; + + CompileSuccessfully(str, SPV_ENV_WEBGPU_0); + if (is_valid) { + ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0)); + } else { + ASSERT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions(SPV_ENV_WEBGPU_0)); + EXPECT_THAT(getDiagnosticString(), HasSubstr(error)); + } +} + +INSTANTIATE_TEST_SUITE_P( + StorageClass, ValidateStorageClass, + Values(std::make_tuple("UniformConstant", false, true, ""), + std::make_tuple("Uniform", false, true, ""), + std::make_tuple("StorageBuffer", false, true, ""), + std::make_tuple("Input", false, true, ""), + std::make_tuple("Output", false, true, ""), + std::make_tuple("Image", false, true, ""), + std::make_tuple("Workgroup", false, true, ""), + std::make_tuple("Private", false, true, ""), + std::make_tuple("Function", true, true, ""), + std::make_tuple( + "CrossWorkgroup", false, false, + "For WebGPU, OpTypePointer storage class must be one of"), + std::make_tuple( + "PushConstant", false, false, + "For WebGPU, OpTypePointer storage class must be one of"))); + } // namespace } // namespace val } // namespace spvtools diff --git a/3rdparty/spirv-tools/tools/opt/opt.cpp b/3rdparty/spirv-tools/tools/opt/opt.cpp index fb794270e..0e77d95fb 100644 --- a/3rdparty/spirv-tools/tools/opt/opt.cpp +++ b/3rdparty/spirv-tools/tools/opt/opt.cpp @@ -340,6 +340,8 @@ Options (in lexicographical order): This options should be used rarely, and with caution. --strength-reduction Replaces instructions with equivalent and less expensive ones. + --strip-atomic-counter-memory + Removes AtomicCountMemory bit from memory semantics values. --strip-debug Remove all debug instructions. --strip-reflect