spirv-fuzz: Support atomic operations opcode (#4348)

This change captures the fact that the signedness of memory semantics
and scope parameters of atomic operations does not matter.

Fixes #4345.
This commit is contained in:
Mostafa Ashraf 2021-07-20 11:03:58 +02:00 коммит произвёл GitHub
Родитель 3a68a72740
Коммит f084bcfe2b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 237 добавлений и 6 удалений

Просмотреть файл

@ -140,9 +140,43 @@ bool TransformationReplaceIdWithSynonym::IsAgnosticToSignednessOfOperand(
case SpvOpUGreaterThanEqual:
case SpvOpSGreaterThanEqual:
return true;
case SpvOpAtomicStore:
case SpvOpAtomicExchange:
case SpvOpAtomicIAdd:
case SpvOpAtomicISub:
case SpvOpAtomicSMin:
case SpvOpAtomicUMin:
case SpvOpAtomicSMax:
case SpvOpAtomicUMax:
case SpvOpAtomicAnd:
case SpvOpAtomicOr:
case SpvOpAtomicXor:
case SpvOpAtomicFAddEXT: // Capability AtomicFloat32AddEXT,
// AtomicFloat64AddEXT.
assert(use_in_operand_index != 0 &&
"Signedness check should not occur on a pointer operand.");
return use_in_operand_index == 1 || use_in_operand_index == 2;
case SpvOpAtomicCompareExchange:
case SpvOpAtomicCompareExchangeWeak: // Capability Kernel.
assert(use_in_operand_index != 0 &&
"Signedness check should not occur on a pointer operand.");
return use_in_operand_index >= 1 && use_in_operand_index <= 3;
case SpvOpAtomicLoad:
case SpvOpAtomicIIncrement:
case SpvOpAtomicIDecrement:
case SpvOpAtomicFlagTestAndSet: // Capability Kernel.
case SpvOpAtomicFlagClear: // Capability Kernel.
assert(use_in_operand_index != 0 &&
"Signedness check should not occur on a pointer operand.");
return use_in_operand_index >= 1;
case SpvOpAccessChain:
// The signedness of indices does not matter.
return use_in_operand_index > 0;
default:
// Conservatively assume that the id cannot be swapped in other
// instructions.

Просмотреть файл

@ -2176,7 +2176,7 @@ TEST(TransformationReplaceIdWithSynonymTest,
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/4345): Improve this
// test so that it covers more atomic operations, and enable the test once the
// issue is fixed.
TEST(TransformationReplaceIdWithSynonymTest, DISABLED_TypesAreCompatible) {
TEST(TransformationReplaceIdWithSynonymTest, TypesAreCompatible) {
const std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
@ -2188,8 +2188,39 @@ TEST(TransformationReplaceIdWithSynonymTest, DISABLED_TypesAreCompatible) {
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%9 = OpTypeInt 32 0
%8 = OpTypeStruct %6
%10 = OpTypePointer StorageBuffer %8
%11 = OpVariable %10 StorageBuffer
%86 = OpTypeStruct %9
%87 = OpTypePointer Workgroup %86
%88 = OpVariable %87 Workgroup
%89 = OpTypePointer Workgroup %9
%19 = OpConstant %9 0
%18 = OpConstant %9 1
%12 = OpConstant %6 0
%13 = OpTypePointer StorageBuffer %6
%15 = OpConstant %6 2
%16 = OpConstant %6 7
%20 = OpConstant %9 64
%4 = OpFunction %2 None %3
%5 = OpLabel
%14 = OpAccessChain %13 %11 %12
%90 = OpAccessChain %89 %88 %19
%21 = OpAtomicLoad %6 %14 %15 %20
%22 = OpAtomicExchange %6 %14 %15 %20 %16
%23 = OpAtomicCompareExchange %6 %14 %15 %20 %12 %16 %15
%24 = OpAtomicIIncrement %6 %14 %15 %20
%25 = OpAtomicIDecrement %6 %14 %15 %20
%26 = OpAtomicIAdd %6 %14 %15 %20 %16
%27 = OpAtomicISub %6 %14 %15 %20 %16
%28 = OpAtomicSMin %6 %14 %15 %20 %16
%29 = OpAtomicUMin %9 %90 %15 %20 %18
%30 = OpAtomicSMax %6 %14 %15 %20 %15
%31 = OpAtomicUMax %9 %90 %15 %20 %18
%32 = OpAtomicAnd %6 %14 %15 %20 %16
%33 = OpAtomicOr %6 %14 %15 %20 %16
%34 = OpAtomicXor %6 %14 %15 %20 %16
OpAtomicStore %14 %15 %20 %16
OpReturn
OpFunctionEnd
)";
@ -2208,7 +2239,7 @@ TEST(TransformationReplaceIdWithSynonymTest, DISABLED_TypesAreCompatible) {
#ifndef NDEBUG
ASSERT_DEATH(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicLoad, 0, int_type, uint_type),
"Invalid operand index");
"Signedness check should not occur on a pointer operand.");
#endif
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicLoad, 1, int_type, uint_type));
@ -2219,17 +2250,183 @@ TEST(TransformationReplaceIdWithSynonymTest, DISABLED_TypesAreCompatible) {
#ifndef NDEBUG
ASSERT_DEATH(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicExchange, 0, int_type, uint_type),
"Invalid operand index");
"Signedness check should not occur on a pointer operand.");
#endif
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicExchange, 1, int_type, uint_type));
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicExchange, 2, int_type, uint_type));
ASSERT_FALSE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicExchange, 2, int_type, uint_type));
context.get(), SpvOpAtomicExchange, 3, int_type, uint_type));
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/4345): Similar for
// other atomic instructions
// OpAtomicStore
#ifndef NDEBUG
ASSERT_DEATH(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicStore, 0, int_type, uint_type),
"Signedness check should not occur on a pointer operand.");
#endif
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicStore, 1, int_type, uint_type));
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicStore, 2, int_type, uint_type));
ASSERT_FALSE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicStore, 3, int_type, uint_type));
// OpAtomicCompareExchange
#ifndef NDEBUG
ASSERT_DEATH(
TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicCompareExchange, 0, int_type, uint_type),
"Signedness check should not occur on a pointer operand.");
#endif
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicCompareExchange, 1, int_type, uint_type));
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicCompareExchange, 2, int_type, uint_type));
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicCompareExchange, 3, int_type, uint_type));
ASSERT_FALSE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicCompareExchange, 4, int_type, uint_type));
// OpAtomicIIncrement
#ifndef NDEBUG
ASSERT_DEATH(
TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicIIncrement, 0, int_type, uint_type),
"Signedness check should not occur on a pointer operand.");
#endif
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicIIncrement, 1, int_type, uint_type));
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicIIncrement, 2, int_type, uint_type));
// OpAtomicIDecrement
#ifndef NDEBUG
ASSERT_DEATH(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicStore, 0, int_type, uint_type),
"Signedness check should not occur on a pointer operand.");
#endif
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicStore, 1, int_type, uint_type));
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicStore, 2, int_type, uint_type));
// OpAtomicIAdd
#ifndef NDEBUG
ASSERT_DEATH(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicIAdd, 0, int_type, uint_type),
"Signedness check should not occur on a pointer operand.");
#endif
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicIAdd, 1, int_type, uint_type));
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicIAdd, 2, int_type, uint_type));
ASSERT_FALSE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicIAdd, 3, int_type, uint_type));
// OpAtomicISub
#ifndef NDEBUG
ASSERT_DEATH(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicISub, 0, int_type, uint_type),
"Signedness check should not occur on a pointer operand.");
#endif
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicISub, 1, int_type, uint_type));
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicISub, 2, int_type, uint_type));
ASSERT_FALSE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicISub, 3, int_type, uint_type));
// OpAtomicSMin
#ifndef NDEBUG
ASSERT_DEATH(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicSMin, 0, int_type, uint_type),
"Signedness check should not occur on a pointer operand.");
#endif
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicSMin, 1, int_type, uint_type));
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicSMin, 2, int_type, uint_type));
ASSERT_FALSE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicSMin, 3, int_type, uint_type));
// OpAtomicUMin
#ifndef NDEBUG
ASSERT_DEATH(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicUMin, 0, int_type, uint_type),
"Signedness check should not occur on a pointer operand.");
#endif
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicUMin, 1, int_type, uint_type));
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicUMin, 2, int_type, uint_type));
ASSERT_FALSE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicUMin, 3, int_type, uint_type));
// OpAtomicSMax
#ifndef NDEBUG
ASSERT_DEATH(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicSMax, 0, int_type, uint_type),
"Signedness check should not occur on a pointer operand.");
#endif
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicSMax, 1, int_type, uint_type));
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicSMax, 2, int_type, uint_type));
ASSERT_FALSE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicSMax, 3, int_type, uint_type));
// OpAtomicUMax
#ifndef NDEBUG
ASSERT_DEATH(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicUMax, 0, int_type, uint_type),
"Signedness check should not occur on a pointer operand.");
#endif
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicUMax, 1, int_type, uint_type));
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicUMax, 2, int_type, uint_type));
ASSERT_FALSE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicUMax, 3, int_type, uint_type));
// OpAtomicAnd
#ifndef NDEBUG
ASSERT_DEATH(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicAnd, 0, int_type, uint_type),
"Signedness check should not occur on a pointer operand.");
#endif
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicAnd, 1, int_type, uint_type));
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicAnd, 2, int_type, uint_type));
ASSERT_FALSE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicAnd, 3, int_type, uint_type));
// OpAtomicOr
#ifndef NDEBUG
ASSERT_DEATH(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicOr, 0, int_type, uint_type),
"Signedness check should not occur on a pointer operand.");
#endif
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicOr, 1, int_type, uint_type));
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicOr, 2, int_type, uint_type));
ASSERT_FALSE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicOr, 3, int_type, uint_type));
// OpAtomicXor
#ifndef NDEBUG
ASSERT_DEATH(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicXor, 0, int_type, uint_type),
"Signedness check should not occur on a pointer operand.");
#endif
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicXor, 1, int_type, uint_type));
ASSERT_TRUE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicXor, 2, int_type, uint_type));
ASSERT_FALSE(TransformationReplaceIdWithSynonym::TypesAreCompatible(
context.get(), SpvOpAtomicXor, 3, int_type, uint_type));
}
} // namespace