Updated spirv-tools.

This commit is contained in:
Бранимир Караџић
2019-03-16 20:28:47 -07:00
parent 45a64efab9
commit b28dfbd770
27 changed files with 1106 additions and 44 deletions

View File

@@ -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 \

View File

@@ -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",

View File

@@ -1 +1 @@
"v2019.2", "SPIRV-Tools v2019.2 79f67a4905acf223f9e37a52e059a62c2bdbdc69"
"v2019.2", "SPIRV-Tools v2019.2 45a64efab9d50ebcf9694a3297acc3223502610d"

View File

@@ -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},

View File

@@ -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.

View File

@@ -605,3 +605,35 @@ bool spvOpcodeIsDebug(SpvOp opcode) {
return false;
}
}
std::vector<uint32_t> 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 {};
}
}

View File

@@ -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 <id>
// operands for |opcode|.
std::vector<uint32_t> spvOpcodeMemorySemanticsOperandIndices(SpvOp opcode);
#endif // SOURCE_OPCODE_H_

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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<const analysis::Constant*>&) {
assert(inst->opcode() == SpvOpEntryPoint &&
"Wrong opcode. Should be OpEntryPoint.");
bool has_redundant_operand = false;
std::unordered_set<uint32_t> seen_operands;
std::vector<Operand> 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());

View File

@@ -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<Optimizer::PassToken::Impl>(MakeUnique<opt::NullPass>());
}
Optimizer::PassToken CreateStripAtomicCounterMemoryPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::StripAtomicCounterMemoryPass>());
}
Optimizer::PassToken CreateStripDebugInfoPass() {
return MakeUnique<Optimizer::PassToken::Impl>(
MakeUnique<opt::StripDebugInfoPass>());

View File

@@ -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"

View File

@@ -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

View File

@@ -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_

View File

@@ -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<uint32_t>(2);
return a_type && (a_type == b->GetOperandAs<uint32_t>(2));
}
spv_result_t ValidateFunction(ValidationState_t& _, const Instruction* inst) {
const auto function_type_id = inst->GetOperandAs<uint32_t>(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<uint32_t>(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 <id> '" << _.getIdName(argument_id)
<< "'s type does not match Function <id> '"
@@ -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";

View File

@@ -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<SpvStorageClass>(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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -896,6 +896,35 @@ OpFunctionEnd
SinglePassRunAndMatch<CCPPass>(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<CCPPass>(text, true);
}
} // namespace
} // namespace opt
} // namespace spvtools

View File

@@ -6211,6 +6211,106 @@ INSTANTIATE_TEST_SUITE_P(VectorShuffleMatchingTest, MatchingInstructionWithNoRes
9, true)
));
using EntryPointFoldingTest =
::testing::TestWithParam<InstructionFoldingCase<bool>>;
TEST_P(EntryPointFoldingTest, Case) {
const auto& tc = GetParam();
// Build module.
std::unique_ptr<IRContext> 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<Instruction> 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<bool>(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<bool>(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<bool>(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

View File

@@ -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<std::string> expected_passes = {
"eliminate-dead-branches", "eliminate-dead-code-aggressive",
"flatten-decorations", "strip-debug"};
std::vector<std::string> 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<WebGPUPassCase>{
// 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

View File

@@ -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 <vector>
#include "test/opt/pass_fixture.h"
#include "test/opt/pass_utils.h"
namespace spvtools {
namespace opt {
namespace {
typedef std::tuple<std::string, std::string> StripAtomicCounterMemoryParam;
using MemorySemanticsModified =
PassTest<::testing::TestWithParam<StripAtomicCounterMemoryParam>>;
using NonMemorySemanticsUnmodifiedTest = PassTest<::testing::Test>;
void operator+=(std::vector<const char*>& 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<const char*> 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<const char*> 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<std::string, std::string> 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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(input, expected,
/* skip_nop = */ false);
}
// clang-format off
INSTANTIATE_TEST_SUITE_P(
StripAtomicCounterMemoryTest, MemorySemanticsModified,
::testing::ValuesIn(std::vector<StripAtomicCounterMemoryParam>({
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<StripAtomicCounterMemoryPass>(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<StripAtomicCounterMemoryPass>(input, expected,
/* skip_nop = */ false);
}
} // namespace
} // namespace opt
} // namespace spvtools

View File

@@ -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

View File

@@ -321,13 +321,15 @@ TEST_P(ValidateFunctionCall, NonMemoryObjectDeclarationNoVariablePointers) {
std::string spirv = GenerateShaderAccessChain(storage_class, "", "");
const std::vector<std::string> 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<std::string> 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<std::string> 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) {

View File

@@ -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

View File

@@ -26,7 +26,10 @@ namespace val {
namespace {
using ::testing::HasSubstr;
using ::testing::Values;
using ValidateStorage = spvtest::ValidateBase<std::string>;
using ValidateStorageClass =
spvtest::ValidateBase<std::tuple<std::string, bool, bool, std::string>>;
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 <id> '"));
}
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

View File

@@ -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