Support SPV_KHR_vulkan_memory_model rev2
Support collapsed into one commit:
- Asm/Dis support for SPV_KHR_vulkan_memory_model
- Add Vulkan mem model image operands to switch
- Add TODO for source/validate_image.cpp
- val: Image operands NonPrivateTexelKHR, VolatileTexelKHR have no operands
This is required for memory model tests to pass SPIR-V validation.
- Round trip tests: Test new flags on OpCopyMemory*
diff --git a/source/val/validate_image.cpp b/source/val/validate_image.cpp
index 2c020ed..b362292 100644
--- a/source/val/validate_image.cpp
+++ b/source/val/validate_image.cpp
@@ -55,6 +55,13 @@
case SpvImageOperandsConstOffsetsMask:
case SpvImageOperandsSampleMask:
case SpvImageOperandsMinLodMask:
+
+ // TODO(dneto): Support image operands related to the Vulkan memory model.
+ // https://gitlab.khronos.org/spirv/spirv-tools/issues/32
+ case SpvImageOperandsMakeTexelAvailableKHRMask:
+ case SpvImageOperandsMakeTexelVisibleKHRMask:
+ case SpvImageOperandsNonPrivateTexelKHRMask:
+ case SpvImageOperandsVolatileTexelKHRMask:
return true;
}
return false;
@@ -210,7 +217,12 @@
const SpvOp opcode = inst->opcode();
const size_t num_words = inst->words().size();
- size_t expected_num_image_operand_words = spvtools::utils::CountSetBits(mask);
+ // NonPrivate and Volatile take no operand words.
+ const uint32_t mask_bits_having_operands =
+ mask & ~uint32_t(SpvImageOperandsNonPrivateTexelKHRMask |
+ SpvImageOperandsVolatileTexelKHRMask);
+ size_t expected_num_image_operand_words =
+ spvtools::utils::CountSetBits(mask_bits_having_operands);
if (mask & SpvImageOperandsGradMask) {
// Grad uses two words.
++expected_num_image_operand_words;
diff --git a/test/binary_parse_test.cpp b/test/binary_parse_test.cpp
index 7d97001..8cf3043 100644
--- a/test/binary_parse_test.cpp
+++ b/test/binary_parse_test.cpp
@@ -890,8 +890,8 @@
"Invalid function control operand: 31 has invalid mask component 16"},
{"OpLoopMerge %1 %2 !1027",
"Invalid loop control operand: 1027 has invalid mask component 1024"},
- {"%2 = OpImageFetch %1 %image %coord !511",
- "Invalid image operand: 511 has invalid mask component 256"},
+ {"%2 = OpImageFetch %1 %image %coord !32770",
+ "Invalid image operand: 32770 has invalid mask component 32768"},
{"OpSelectionMerge %1 !7",
"Invalid selection control operand: 7 has invalid mask component 4"},
}), );
diff --git a/test/operand_capabilities_test.cpp b/test/operand_capabilities_test.cpp
index 0aeb505..152cf5b 100644
--- a/test/operand_capabilities_test.cpp
+++ b/test/operand_capabilities_test.cpp
@@ -604,16 +604,18 @@
})), );
// See SPIR-V Section 3.27 Scope <id>
-INSTANTIATE_TEST_CASE_P(Scope, EnumCapabilityTest,
- Combine(Values(SPV_ENV_UNIVERSAL_1_0,
- SPV_ENV_UNIVERSAL_1_1),
- ValuesIn(std::vector<EnumCapabilityCase>{
- CASE0(SCOPE_ID, ScopeCrossDevice),
- CASE0(SCOPE_ID, ScopeDevice),
- CASE0(SCOPE_ID, ScopeWorkgroup),
- CASE0(SCOPE_ID, ScopeSubgroup),
- CASE0(SCOPE_ID, ScopeInvocation),
- })), );
+INSTANTIATE_TEST_CASE_P(
+ Scope, EnumCapabilityTest,
+ Combine(Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
+ SPV_ENV_UNIVERSAL_1_2, SPV_ENV_UNIVERSAL_1_3),
+ ValuesIn(std::vector<EnumCapabilityCase>{
+ CASE0(SCOPE_ID, ScopeCrossDevice),
+ CASE0(SCOPE_ID, ScopeDevice),
+ CASE0(SCOPE_ID, ScopeWorkgroup),
+ CASE0(SCOPE_ID, ScopeSubgroup),
+ CASE0(SCOPE_ID, ScopeInvocation),
+ CASE1(SCOPE_ID, ScopeQueueFamilyKHR, VulkanMemoryModelKHR),
+ })), );
// See SPIR-V Section 3.28 Group Operation
INSTANTIATE_TEST_CASE_P(
diff --git a/test/operand_pattern_test.cpp b/test/operand_pattern_test.cpp
index b3e3024..851051b 100644
--- a/test/operand_pattern_test.cpp
+++ b/test/operand_pattern_test.cpp
@@ -89,9 +89,10 @@
::testing::ValuesIn(std::vector<MaskExpansionCase>{
// No bits means no change.
{SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS, 0, {PREFIX0}, {PREFIX0}},
- // Unknown bits means no change.
+ // Unknown bits means no change. Use all bits that aren't in the grammar.
+ // The last mask enum is 0x20
{SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS,
- 0xfffffffc,
+ 0xffffffc0,
{PREFIX1},
{PREFIX1}},
// Volatile has no operands.
diff --git a/test/text_to_binary.extension_test.cpp b/test/text_to_binary.extension_test.cpp
index 0d8d324..7bed03d 100644
--- a/test/text_to_binary.extension_test.cpp
+++ b/test/text_to_binary.extension_test.cpp
@@ -510,6 +510,147 @@
{SpvCapabilityVariablePointersStorageBuffer})},
})), );
+// SPV_KHR_vulkan_memory_model
+
+INSTANTIATE_TEST_CASE_P(
+ SPV_KHR_vulkan_memory_model, ExtensionRoundTripTest,
+ // We'll get coverage over operand tables by trying the universal
+ // environments, and at least one specific environment.
+ //
+ // Note: SPV_KHR_vulkan_memory_model adds scope enum value QueueFamilyKHR.
+ // Scope enums are used in ID defini
+ Combine(
+ Values(SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1,
+ SPV_ENV_UNIVERSAL_1_3, SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1),
+ ValuesIn(std::vector<AssemblyCase>{
+ {"OpCapability VulkanMemoryModelKHR\n",
+ MakeInstruction(SpvOpCapability,
+ {SpvCapabilityVulkanMemoryModelKHR})},
+ {"OpCapability VulkanMemoryModelDeviceScopeKHR\n",
+ MakeInstruction(SpvOpCapability,
+ {SpvCapabilityVulkanMemoryModelDeviceScopeKHR})},
+ {"OpMemoryModel Logical VulkanKHR\n",
+ MakeInstruction(SpvOpMemoryModel, {SpvAddressingModelLogical,
+ SpvMemoryModelVulkanKHR})},
+ {"OpStore %1 %2 MakePointerAvailableKHR %3\n",
+ MakeInstruction(SpvOpStore,
+ {1, 2, SpvMemoryAccessMakePointerAvailableKHRMask,
+ 3})},
+ {"OpStore %1 %2 Volatile|MakePointerAvailableKHR %3\n",
+ MakeInstruction(SpvOpStore,
+ {1, 2,
+ int(SpvMemoryAccessMakePointerAvailableKHRMask) |
+ int(SpvMemoryAccessVolatileMask),
+ 3})},
+ {"OpStore %1 %2 Aligned|MakePointerAvailableKHR 4 %3\n",
+ MakeInstruction(SpvOpStore,
+ {1, 2,
+ int(SpvMemoryAccessMakePointerAvailableKHRMask) |
+ int(SpvMemoryAccessAlignedMask),
+ 4, 3})},
+ {"OpStore %1 %2 MakePointerAvailableKHR|NonPrivatePointerKHR %3\n",
+ MakeInstruction(SpvOpStore,
+ {1, 2,
+ int(SpvMemoryAccessMakePointerAvailableKHRMask) |
+ int(SpvMemoryAccessNonPrivatePointerKHRMask),
+ 3})},
+ {"%2 = OpLoad %1 %3 MakePointerVisibleKHR %4\n",
+ MakeInstruction(SpvOpLoad,
+ {1, 2, 3, SpvMemoryAccessMakePointerVisibleKHRMask,
+ 4})},
+ {"%2 = OpLoad %1 %3 Volatile|MakePointerVisibleKHR %4\n",
+ MakeInstruction(SpvOpLoad,
+ {1, 2, 3,
+ int(SpvMemoryAccessMakePointerVisibleKHRMask) |
+ int(SpvMemoryAccessVolatileMask),
+ 4})},
+ {"%2 = OpLoad %1 %3 Aligned|MakePointerVisibleKHR 8 %4\n",
+ MakeInstruction(SpvOpLoad,
+ {1, 2, 3,
+ int(SpvMemoryAccessMakePointerVisibleKHRMask) |
+ int(SpvMemoryAccessAlignedMask),
+ 8, 4})},
+ {"%2 = OpLoad %1 %3 MakePointerVisibleKHR|NonPrivatePointerKHR "
+ "%4\n",
+ MakeInstruction(SpvOpLoad,
+ {1, 2, 3,
+ int(SpvMemoryAccessMakePointerVisibleKHRMask) |
+ int(SpvMemoryAccessNonPrivatePointerKHRMask),
+ 4})},
+ {"OpCopyMemory %1 %2 "
+ "MakePointerAvailableKHR|"
+ "MakePointerVisibleKHR|"
+ "NonPrivatePointerKHR "
+ "%3 %4\n",
+ MakeInstruction(SpvOpCopyMemory,
+ {1, 2,
+ (int(SpvMemoryAccessMakePointerVisibleKHRMask) |
+ int(SpvMemoryAccessMakePointerAvailableKHRMask) |
+ int(SpvMemoryAccessNonPrivatePointerKHRMask)),
+ 3, 4})},
+ {"OpCopyMemorySized %1 %2 %3 "
+ "MakePointerAvailableKHR|"
+ "MakePointerVisibleKHR|"
+ "NonPrivatePointerKHR "
+ "%4 %5\n",
+ MakeInstruction(SpvOpCopyMemorySized,
+ {1, 2, 3,
+ (int(SpvMemoryAccessMakePointerVisibleKHRMask) |
+ int(SpvMemoryAccessMakePointerAvailableKHRMask) |
+ int(SpvMemoryAccessNonPrivatePointerKHRMask)),
+ 4, 5})},
+ // Image operands
+ {"OpImageWrite %1 %2 %3 MakeTexelAvailableKHR "
+ "%4\n",
+ MakeInstruction(
+ SpvOpImageWrite,
+ {1, 2, 3, int(SpvImageOperandsMakeTexelAvailableKHRMask), 4})},
+ {"OpImageWrite %1 %2 %3 MakeTexelAvailableKHR|NonPrivateTexelKHR "
+ "%4\n",
+ MakeInstruction(SpvOpImageWrite,
+ {1, 2, 3,
+ int(SpvImageOperandsMakeTexelAvailableKHRMask) |
+ int(SpvImageOperandsNonPrivateTexelKHRMask),
+ 4})},
+ {"OpImageWrite %1 %2 %3 "
+ "MakeTexelAvailableKHR|NonPrivateTexelKHR|VolatileTexelKHR "
+ "%4\n",
+ MakeInstruction(SpvOpImageWrite,
+ {1, 2, 3,
+ int(SpvImageOperandsMakeTexelAvailableKHRMask) |
+ int(SpvImageOperandsNonPrivateTexelKHRMask) |
+ int(SpvImageOperandsVolatileTexelKHRMask),
+ 4})},
+ {"%2 = OpImageRead %1 %3 %4 MakeTexelVisibleKHR "
+ "%5\n",
+ MakeInstruction(SpvOpImageRead,
+ {1, 2, 3, 4,
+ int(SpvImageOperandsMakeTexelVisibleKHRMask),
+ 5})},
+ {"%2 = OpImageRead %1 %3 %4 "
+ "MakeTexelVisibleKHR|NonPrivateTexelKHR "
+ "%5\n",
+ MakeInstruction(SpvOpImageRead,
+ {1, 2, 3, 4,
+ int(SpvImageOperandsMakeTexelVisibleKHRMask) |
+ int(SpvImageOperandsNonPrivateTexelKHRMask),
+ 5})},
+ {"%2 = OpImageRead %1 %3 %4 "
+ "MakeTexelVisibleKHR|NonPrivateTexelKHR|VolatileTexelKHR "
+ "%5\n",
+ MakeInstruction(SpvOpImageRead,
+ {1, 2, 3, 4,
+ int(SpvImageOperandsMakeTexelVisibleKHRMask) |
+ int(SpvImageOperandsNonPrivateTexelKHRMask) |
+ int(SpvImageOperandsVolatileTexelKHRMask),
+ 5})},
+
+ // Memory semantics ID values are numbers put into a SPIR-V
+ // constant integer referenced by Id. There is no token for
+ // them, and so no assembler or disassembler support required.
+ // Similar for Scope ID.
+ })), );
+
// SPV_GOOGLE_decorate_string
INSTANTIATE_TEST_CASE_P(