blob: 96f812d763307b9aa5b4873612a982ad64481953 [file]
// Copyright (c) 2025 The Khronos Group 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 "gmock/gmock.h"
#include "test/val/val_fixtures.h"
namespace spvtools {
namespace val {
namespace {
using ::testing::Combine;
using ::testing::HasSubstr;
using ::testing::Values;
using ::testing::ValuesIn;
using ::testing::internal::ParamGenerator;
// clang-format off
#define MEMORY_SEMANTICS_OPERANDS \
OpMemoryBarrier, \
OpControlBarrier, \
OpAtomicLoad, \
OpAtomicStore, \
OpAtomicExchange, \
OpAtomicIIncrement, \
OpAtomicIDecrement, \
OpAtomicIAdd, \
OpAtomicISub, \
OpAtomicSMin, \
OpAtomicSMax, \
OpAtomicUMin, \
OpAtomicUMax, \
OpAtomicAnd, \
OpAtomicOr, \
OpAtomicXor, \
OpAtomicCompareExchangeEqual, \
OpAtomicCompareExchangeUnequal
enum Operand { MEMORY_SEMANTICS_OPERANDS };
const Operand Operands[] = { MEMORY_SEMANTICS_OPERANDS };
const size_t OperandsCount = sizeof(Operands) / sizeof(Operand);
#undef MEMORY_SEMANTICS_OPERANDS
// clang-format on
enum Value {
None = uint32_t(spv::MemorySemanticsMask::MaskNone),
Acquire = uint32_t(spv::MemorySemanticsMask::Acquire),
Release = uint32_t(spv::MemorySemanticsMask::Release),
AcqRel = uint32_t(spv::MemorySemanticsMask::AcquireRelease),
SeqCst = uint32_t(spv::MemorySemanticsMask::SequentiallyConsistent),
Uniform = uint32_t(spv::MemorySemanticsMask::UniformMemory),
Subgroup = uint32_t(spv::MemorySemanticsMask::SubgroupMemory),
Workgroup = uint32_t(spv::MemorySemanticsMask::WorkgroupMemory),
CrossWorkgroup = uint32_t(spv::MemorySemanticsMask::CrossWorkgroupMemory),
AtomicCounter = uint32_t(spv::MemorySemanticsMask::AtomicCounterMemory),
Image = uint32_t(spv::MemorySemanticsMask::ImageMemory),
Output = uint32_t(spv::MemorySemanticsMask::OutputMemory),
Available = uint32_t(spv::MemorySemanticsMask::MakeAvailable),
Visible = uint32_t(spv::MemorySemanticsMask::MakeVisible),
Volatile = uint32_t(spv::MemorySemanticsMask::Volatile)
};
struct TestResult {
explicit TestResult(spv_result_t in_result = SPV_SUCCESS,
const char* in_vuid = nullptr,
const char* in_error = nullptr)
: result(in_result), vuid(in_vuid), error(in_error) {}
spv_result_t result;
const char* vuid;
const char* error;
};
template <typename T, typename... Ts>
ParamGenerator<T> ValuesInExcept(const T* items, const size_t count,
const Ts... skip) {
std::vector<T> filtered;
std::initializer_list<T> excluded = {skip...};
std::copy_if(items, items + count, std::back_inserter(filtered),
[&excluded](const T& value) {
return std::all_of(
excluded.begin(), excluded.end(),
[&value](const T& other) { return value != other; });
});
return ValuesIn(filtered);
}
std::string GenerateInstruction(const Operand operand) {
switch (operand) {
case OpMemoryBarrier:
return "OpMemoryBarrier %scope %semantics";
case OpControlBarrier:
return "OpControlBarrier %uint_2 %scope %semantics";
case OpAtomicLoad:
return "%result = OpAtomicLoad %uint %var %scope %semantics";
case OpAtomicStore:
return "OpAtomicStore %var %scope %semantics %uint_1";
case OpAtomicExchange:
return "%result = OpAtomicExchange %uint %var %scope %semantics %uint_1";
case OpAtomicCompareExchangeEqual:
return "%result = OpAtomicCompareExchange %uint %var %scope %semantics "
"%semantics_min %uint_1 %uint_0";
case OpAtomicCompareExchangeUnequal:
return "%result = OpAtomicCompareExchange %uint %var %scope "
"%semantics_max %semantics %uint_1 %uint_0";
case OpAtomicIIncrement:
return "%result = OpAtomicIIncrement %uint %var %scope %semantics";
case OpAtomicIDecrement:
return "%result = OpAtomicIDecrement %uint %var %scope %semantics";
case OpAtomicIAdd:
return "%result = OpAtomicIAdd %uint %var %scope %semantics %uint_1";
case OpAtomicISub:
return "%result = OpAtomicISub %uint %var %scope %semantics %uint_1";
case OpAtomicSMin:
return "%result = OpAtomicSMin %uint %var %scope %semantics %uint_1";
case OpAtomicUMin:
return "%result = OpAtomicUMin %uint %var %scope %semantics %uint_1";
case OpAtomicSMax:
return "%result = OpAtomicSMax %uint %var %scope %semantics %uint_1";
case OpAtomicUMax:
return "%result = OpAtomicUMax %uint %var %scope %semantics %uint_1";
case OpAtomicAnd:
return "%result = OpAtomicAnd %uint %var %scope %semantics %uint_1";
case OpAtomicOr:
return "%result = OpAtomicOr %uint %var %scope %semantics %uint_1";
case OpAtomicXor:
return "%result = OpAtomicXor %uint %var %scope %semantics %uint_1";
default:
return "";
}
}
std::string GenerateVulkanCode(const std::string instruction,
const uint32_t semantics,
const uint32_t semantics2 = 0) {
std::ostringstream ss;
ss << R"(
OpCapability Shader
OpCapability VulkanMemoryModel
OpExtension "SPV_KHR_vulkan_memory_model"
OpMemoryModel Logical Vulkan
OpEntryPoint GLCompute %main "main" %var
OpExecutionMode %main LocalSize 32 1 1
%void = OpTypeVoid
%uint = OpTypeInt 32 0
%func = OpTypeFunction %void
%uint_ptr = OpTypePointer Workgroup %uint
%uint_0 = OpConstant %uint 0
%uint_1 = OpConstant %uint 1
%uint_2 = OpConstant %uint 2
%uint_4 = OpConstant %uint 4
%scope = OpConstant %uint 5
%semantics = OpConstant %uint )"
<< semantics << R"(
%semantics2 = OpConstant %uint )"
<< semantics2 << R"(
%semantics_min = OpConstant %uint )"
<< (semantics & Volatile) << R"(
%semantics_max = OpConstant %uint )"
<< (32712 | (semantics & Volatile)) << R"(
%var = OpVariable %uint_ptr Workgroup
%main = OpFunction %void None %func
%label = OpLabel
)" << instruction
<< R"(
OpReturn
OpFunctionEnd)";
return ss.str();
}
using VulkanMemorySemantics =
spvtest::ValidateBase<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t,
uint32_t, Operand, TestResult>>;
using VulkanUnequalMemorySemantics = spvtest::ValidateBase<
std::tuple<uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t,
uint32_t, uint32_t, bool, uint32_t, TestResult>>;
INSTANTIATE_TEST_SUITE_P(
ErrorMultipleMemoryOrderBits, VulkanMemorySemantics,
Combine(
Values(Acquire | Release, Acquire | AcqRel, Release | AcqRel,
Acquire | SeqCst, Release | SeqCst, AcqRel | SeqCst),
Values(None, Uniform | Workgroup | Image | Output),
Values(None, Available, Visible, Available | Visible),
Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
ValuesIn(Operands),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-MemorySemantics-10865",
"Memory Semantics must have at most one non-relaxed memory order "
"bit set"))));
INSTANTIATE_TEST_SUITE_P(
ErrorSequentiallyConsistentMemoryOrder, VulkanMemorySemantics,
Combine(
Values(SeqCst), Values(None, Uniform | Workgroup | Image | Output),
Values(None, Available, Visible, Available | Visible),
Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
ValuesIn(Operands),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-MemorySemantics-10866",
"Memory Semantics with SequentiallyConsistent memory order must "
"not be used in the Vulkan API"))));
INSTANTIATE_TEST_SUITE_P(
ErrorAtomicStoreWithAcquireMemoryOrder, VulkanMemorySemantics,
Combine(Values(Acquire, AcqRel),
Values(None, Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(None, Visible, Available, Available | Visible),
Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(OpAtomicStore),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-MemorySemantics-10867",
"MemorySemantics must not use Acquire or AcquireRelease "
"memory order with AtomicStore"))));
INSTANTIATE_TEST_SUITE_P(
ErrorAtomicLoadWithReleaseMemoryOrder, VulkanMemorySemantics,
Combine(Values(Release, AcqRel),
Values(None, Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(None, Available, Visible, Available | Visible),
Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(OpAtomicLoad),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-MemorySemantics-10868",
"MemorySemantics must not use Release or AcquireRelease "
"memory order with AtomicLoad"))));
INSTANTIATE_TEST_SUITE_P(
ErrorMemoryBarrierWithRelaxedMemoryOrder, VulkanMemorySemantics,
Combine(Values(None),
Values(None, Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(None, Available, Visible, Available | Visible),
Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(OpMemoryBarrier),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-MemorySemantics-10869",
"MemorySemantics must not use Relaxed memory order with "
"MemoryBarrier"))));
INSTANTIATE_TEST_SUITE_P(
ErrorNonRelaxedSemanticsWithoutStorageClass, VulkanMemorySemantics,
Combine(Values(Acquire, Release, AcqRel), Values(None),
Values(None, Available, Visible, Available | Visible),
Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
ValuesInExcept(Operands, OperandsCount, OpAtomicLoad,
OpAtomicStore),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-MemorySemantics-10870",
"Memory Semantics with a non-relaxed memory order (Acquire, "
"Release, or AcquireRelease) must have at least one "
"Vulkan-supported storage class semantics bit set "
"(UniformMemory, WorkgroupMemory, ImageMemory, "
"or OutputMemory)"))));
INSTANTIATE_TEST_SUITE_P(
ErrorNonRelaxedSemanticsWithoutStorageClassLoad, VulkanMemorySemantics,
Combine(Values(Acquire), Values(None),
Values(None, Available, Visible, Available | Visible),
Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(OpAtomicLoad),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-MemorySemantics-10870",
"Memory Semantics with a non-relaxed memory order (Acquire, "
"Release, or AcquireRelease) must have at least one "
"Vulkan-supported storage class semantics bit set "
"(UniformMemory, WorkgroupMemory, ImageMemory, or "
"OutputMemory)"))));
INSTANTIATE_TEST_SUITE_P(
ErrorNonRelaxedSemanticsWithoutStorageClassStore, VulkanMemorySemantics,
Combine(Values(Release), Values(None),
Values(None, Available, Visible, Available | Visible),
Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(OpAtomicStore),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-MemorySemantics-10870",
"Memory Semantics with a non-relaxed memory order (Acquire, "
"Release, or AcquireRelease) must have at least one "
"Vulkan-supported storage class semantics bit set "
"(UniformMemory, WorkgroupMemory, ImageMemory, or "
"OutputMemory)"))));
INSTANTIATE_TEST_SUITE_P(
ErrorRelaxedSemanticsWithStorageClass, VulkanMemorySemantics,
Combine(
Values(None),
Values(Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(None, Available, Visible, Available | Visible),
Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
ValuesInExcept(Operands, OperandsCount, OpMemoryBarrier),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-MemorySemantics-10871",
"Memory Semantics with at least one Vulkan-supported storage class "
"semantics bit set (UniformMemory, WorkgroupMemory, ImageMemory, "
"or OutputMemory) must use a non-relaxed memory order (Acquire, "
"Release, or AcquireRelease)"))));
INSTANTIATE_TEST_SUITE_P(
ErrorMakeAvailableWithRelaxedMemoryOrder, VulkanMemorySemantics,
Combine(Values(None), Values(None), Values(Available, Available | Visible),
Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
ValuesInExcept(Operands, OperandsCount, OpMemoryBarrier),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-MemorySemantics-10872",
"Memory Semantics with MakeAvailable bit set must use Release "
"or AcquireRelease memory order"))));
INSTANTIATE_TEST_SUITE_P(
ErrorMakeAvailableWithAcquireMemoryOrder, VulkanMemorySemantics,
Combine(Values(Acquire),
Values(Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(Available, Available | Visible), Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
ValuesInExcept(Operands, OperandsCount, OpAtomicStore),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-MemorySemantics-10872",
"Memory Semantics with MakeAvailable bit set must use Release "
"or AcquireRelease memory order"))));
INSTANTIATE_TEST_SUITE_P(
ErrorMakeVisibleWithRelaxedMemoryOrder, VulkanMemorySemantics,
Combine(Values(None), Values(None), Values(Visible), Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
ValuesInExcept(Operands, OperandsCount, OpMemoryBarrier),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-MemorySemantics-10873",
"Memory Semantics with MakeVisible bit set must use Acquire "
"or AcquireRelease memory order"))));
INSTANTIATE_TEST_SUITE_P(
ErrorMakeVisibleWithReleaseMemoryOrder, VulkanMemorySemantics,
Combine(Values(Release),
Values(Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(Visible, Available | Visible), Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
ValuesInExcept(Operands, OperandsCount, OpAtomicLoad),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-MemorySemantics-10873",
"Memory Semantics with MakeVisible bit set must use Acquire "
"or AcquireRelease memory order"))));
INSTANTIATE_TEST_SUITE_P(
ErrorVolatileBarrierWithRelaxedSemantics, VulkanMemorySemantics,
Combine(Values(None), Values(None), Values(None), Values(Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(OpControlBarrier),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-MemorySemantics-10874",
"Memory Semantics with Volatile bit set must not be used with "
"barrier instructions"))));
INSTANTIATE_TEST_SUITE_P(
ErrorVolatileBarrierWithNonRelaxedSemantics, VulkanMemorySemantics,
Combine(Values(Acquire, Acquire | Visible, Release, Release | Available,
AcqRel, AcqRel | Visible, AcqRel | Available,
AcqRel | Available | Visible),
Values(Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(None), Values(Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(OpControlBarrier, OpMemoryBarrier),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-MemorySemantics-10874",
"Memory Semantics with Volatile bit set must not be used with "
"barrier instructions"))));
INSTANTIATE_TEST_SUITE_P(
ErrorCompareExchangeUnequalSemanticsWithRelease, VulkanMemorySemantics,
Combine(Values(Release, AcqRel, AcqRel | Visible),
Values(Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(None, Available), Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(OpAtomicCompareExchangeUnequal),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-UnequalMemorySemantics-10875",
"AtomicCompareExchange Unequal Memory Semantics must not use "
"Release or AcquireRelease memory order"))));
INSTANTIATE_TEST_SUITE_P(
SuccessAtomicsRelaxed, VulkanMemorySemantics,
Combine(Values(None), Values(None), Values(None), Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
ValuesInExcept(Operands, OperandsCount, OpMemoryBarrier,
OpControlBarrier),
Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
SuccessAtomicsAcquire, VulkanMemorySemantics,
Combine(Values(Acquire),
Values(Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(None, Visible), Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
ValuesInExcept(Operands, OperandsCount, OpMemoryBarrier,
OpControlBarrier, OpAtomicStore),
Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
SuccessAtomicsRelease, VulkanMemorySemantics,
Combine(Values(Release),
Values(Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(None, Available), Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
ValuesInExcept(Operands, OperandsCount, OpMemoryBarrier,
OpControlBarrier, OpAtomicLoad,
OpAtomicCompareExchangeUnequal),
Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
SuccessAtomicsAcqRel, VulkanMemorySemantics,
Combine(Values(AcqRel),
Values(Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(None, Available, Visible, Available | Visible),
Values(None, Volatile),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
ValuesInExcept(Operands, OperandsCount, OpMemoryBarrier,
OpControlBarrier, OpAtomicLoad, OpAtomicStore,
OpAtomicCompareExchangeUnequal),
Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
SuccessBarriersRelaxed, VulkanMemorySemantics,
Combine(Values(None), Values(None), Values(None), Values(None),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(OpControlBarrier), Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
SuccessBarriersNonRelaxed, VulkanMemorySemantics,
Combine(Values(Acquire, Acquire | Visible, Release, Release | Available,
AcqRel, AcqRel | Available, AcqRel | Visible,
AcqRel | Available | Visible),
Values(Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(None), Values(None),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(OpControlBarrier, OpMemoryBarrier), Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
ErrorMemoryOrderTooWeak, VulkanUnequalMemorySemantics,
Combine(Values(None), Values(None), Values(None),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(Acquire),
Values(Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(None, Visible),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(true, false), Values(None, Volatile),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-UnequalMemorySemantics-10876",
"AtomicCompareExchange Unequal Memory Semantics must not use a "
"stronger memory order than the corresponding Equal Memory "
"Semantics"))));
INSTANTIATE_TEST_SUITE_P(
ErrorMissingStorageClassSemanticsFlags, VulkanUnequalMemorySemantics,
Combine(
Values(Acquire, Acquire | Visible, Release, Release | Available, AcqRel,
AcqRel | Visible, AcqRel | Available,
AcqRel | Available | Visible),
Values(Uniform | Workgroup), Values(None),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(Acquire), Values(Uniform | Image, Output), Values(None, Visible),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(true, false), Values(None, Volatile),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-UnequalMemorySemantics-10877",
"AtomicCompareExchange Unequal Memory Semantics must not have any "
"Vulkan-supported storage class semantics bit set (UniformMemory, "
"WorkgroupMemory, ImageMemory, or OutputMemory) unless this bit is "
"also set in the corresponding Equal Memory Semantics"))));
INSTANTIATE_TEST_SUITE_P(
ErrorMissingMakeVisibleFlag, VulkanUnequalMemorySemantics,
Combine(Values(Acquire, Release, Release | Available, AcqRel,
AcqRel | Available),
Values(Uniform | Workgroup | Image | Output), Values(None),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(Acquire),
Values(Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(Visible),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(true, false), Values(None, Volatile),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-UnequalMemorySemantics-10878",
"AtomicCompareExchange Unequal Memory Semantics must not have "
"MakeVisible bit set unless this bit is also set in the "
"corresponding Equal Memory Semantics"))));
INSTANTIATE_TEST_SUITE_P(
ErrorMismatchingVolatileFlagsRelaxedAndRelaxed,
VulkanUnequalMemorySemantics,
Combine(
Values(None), Values(None), Values(None),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter), Values(None),
Values(None), Values(None),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter), Values(false),
Values(None, Volatile),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-UnequalMemorySemantics-10879",
"AtomicCompareExchange Unequal Memory Semantics must have Volatile "
"bit set if and only if this bit is also set in the corresponding "
"Equal Memory Semantics"))));
INSTANTIATE_TEST_SUITE_P(
ErrorMismatchingVolatileFlagsNonRelaxedAndRelaxed,
VulkanUnequalMemorySemantics,
Combine(
Values(Acquire, Acquire | Visible, Release, Release | Available, AcqRel,
AcqRel | Visible, AcqRel | Available,
AcqRel | Available | Visible),
Values(Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(None), Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(None), Values(None), Values(None),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter), Values(false),
Values(None, Volatile),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-UnequalMemorySemantics-10879",
"AtomicCompareExchange Unequal Memory Semantics must have Volatile "
"bit set if and only if this bit is also set in the corresponding "
"Equal Memory Semantics"))));
INSTANTIATE_TEST_SUITE_P(
ErrorMismatchingVolatileFlagsNonRelaxedAndAcquire,
VulkanUnequalMemorySemantics,
Combine(
Values(Acquire, Acquire | Visible, Release, Release | Available, AcqRel,
AcqRel | Visible, AcqRel | Available,
AcqRel | Available | Visible),
Values(Uniform | Workgroup | Image | Output), Values(None),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(Acquire),
Values(Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(None), Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(false), Values(None, Volatile),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-UnequalMemorySemantics-10879",
"AtomicCompareExchange Unequal Memory Semantics must have Volatile "
"bit set if and only if this bit is also set in the corresponding "
"Equal Memory Semantics"))));
INSTANTIATE_TEST_SUITE_P(
ErrorMismatchingVolatileFlagsNonRelaxedAndAcquireVisible,
VulkanUnequalMemorySemantics,
Combine(
Values(Acquire, AcqRel, AcqRel | Available),
Values(Uniform | Workgroup | Image | Output), Values(Visible),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(Acquire),
Values(Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(Visible),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter), Values(false),
Values(None, Volatile),
Values(TestResult(
SPV_ERROR_INVALID_DATA,
"VUID-StandaloneSpirv-UnequalMemorySemantics-10879",
"AtomicCompareExchange Unequal Memory Semantics must have Volatile "
"bit set if and only if this bit is also set in the corresponding "
"Equal Memory Semantics"))));
INSTANTIATE_TEST_SUITE_P(
SuccessNonRelaxedAndAcquire, VulkanUnequalMemorySemantics,
Combine(Values(Acquire, Acquire | Visible, Release, Release | Available,
AcqRel, AcqRel | Visible, AcqRel | Available,
AcqRel | Available | Visible),
Values(Uniform | Workgroup | Image | Output), Values(None),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(Acquire),
Values(Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(None),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(true), Values(None, Volatile), Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
SuccessNonRelaxedAndAcquireVisible, VulkanUnequalMemorySemantics,
Combine(Values(Acquire, AcqRel, AcqRel | Available),
Values(Uniform | Workgroup | Image | Output), Values(Visible),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(Acquire),
Values(Uniform, Workgroup, Image, Output,
Uniform | Workgroup | Image | Output),
Values(Visible),
Values(None, Subgroup | CrossWorkgroup | AtomicCounter),
Values(true), Values(None, Volatile), Values(TestResult())));
TEST_P(VulkanMemorySemantics, Case) {
const uint32_t semantics = std::get<0>(GetParam()) | std::get<1>(GetParam()) |
std::get<2>(GetParam()) | std::get<3>(GetParam()) |
std::get<4>(GetParam());
const Operand operand = std::get<5>(GetParam());
const TestResult& result = std::get<6>(GetParam());
const std::string instruction = GenerateInstruction(operand);
CompileSuccessfully(GenerateVulkanCode(instruction, semantics),
SPV_ENV_VULKAN_1_4);
ASSERT_EQ(result.result, ValidateInstructions(SPV_ENV_VULKAN_1_4));
if (result.vuid) {
EXPECT_THAT(getDiagnosticString(), AnyVUID(result.vuid));
}
if (result.error) {
EXPECT_THAT(getDiagnosticString(), HasSubstr(result.error));
}
}
TEST_P(VulkanUnequalMemorySemantics, Case) {
const uint32_t equal_volatile = std::get<9>(GetParam());
const uint32_t unequal_volatile =
std::get<8>(GetParam()) ? equal_volatile : Volatile ^ equal_volatile;
const uint32_t equal = std::get<0>(GetParam()) | std::get<1>(GetParam()) |
std::get<2>(GetParam()) | std::get<3>(GetParam()) |
equal_volatile;
const uint32_t unequal = std::get<4>(GetParam()) | std::get<5>(GetParam()) |
std::get<6>(GetParam()) | std::get<7>(GetParam()) |
unequal_volatile;
const TestResult& result = std::get<10>(GetParam());
const std::string instruction =
"%result = OpAtomicCompareExchange %uint %var %scope %semantics "
"%semantics2 %uint_1 %uint_0";
CompileSuccessfully(GenerateVulkanCode(instruction, equal, unequal),
SPV_ENV_VULKAN_1_4);
ASSERT_EQ(result.result, ValidateInstructions(SPV_ENV_VULKAN_1_4));
if (result.vuid) {
EXPECT_THAT(getDiagnosticString(), AnyVUID(result.vuid));
}
if (result.error) {
EXPECT_THAT(getDiagnosticString(), HasSubstr(result.error));
}
}
} // namespace
} // namespace val
} // namespace spvtools