// Copyright (c) 2017 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include "gmock/gmock.h" #include "unit_spirv.h" #include "val_fixtures.h" namespace { using ::testing::HasSubstr; using ::testing::Not; using ValidateAtomics = spvtest::ValidateBase; std::string GenerateShaderCode( const std::string& body, const std::string& capabilities_and_extensions = "") { std::ostringstream ss; ss << R"( OpCapability Shader OpCapability Linkage OpCapability Int64 )"; ss << capabilities_and_extensions; ss << R"( OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %main "main" %void = OpTypeVoid %func = OpTypeFunction %void %bool = OpTypeBool %f32 = OpTypeFloat 32 %u32 = OpTypeInt 32 0 %u64 = OpTypeInt 64 0 %f32vec4 = OpTypeVector %f32 4 %f32_0 = OpConstant %f32 0 %f32_1 = OpConstant %f32 1 %u32_0 = OpConstant %u32 0 %u32_1 = OpConstant %u32 1 %u64_1 = OpConstant %u64 1 %f32vec4_0000 = OpConstantComposite %f32vec4 %f32_0 %f32_0 %f32_0 %f32_0 %scope = OpConstant %u32 1 %relaxed = OpConstant %u32 0 %acquire = OpConstant %u32 2 %release = OpConstant %u32 4 %acquire_release = OpConstant %u32 8 %acquire_and_release = OpConstant %u32 6 %sequentially_consistent = OpConstant %u32 16 %acquire_release_uniform_workgroup = OpConstant %u32 328 %f32_ptr = OpTypePointer Workgroup %f32 %f32_var = OpVariable %f32_ptr Workgroup %u32_ptr = OpTypePointer Workgroup %u32 %u32_var = OpVariable %u32_ptr Workgroup %u64_ptr = OpTypePointer Workgroup %u64 %u64_var = OpVariable %u64_ptr Workgroup %f32vec4_ptr = OpTypePointer Workgroup %f32vec4 %f32vec4_var = OpVariable %f32vec4_ptr Workgroup %f32_ptr_function = OpTypePointer Function %f32 %main = OpFunction %void None %func %main_entry = OpLabel )"; ss << body; ss << R"( OpReturn OpFunctionEnd)"; return ss.str(); } std::string GenerateKernelCode( const std::string& body, const std::string& capabilities_and_extensions = "") { std::ostringstream ss; ss << R"( OpCapability Addresses OpCapability Kernel OpCapability Linkage OpCapability Int64 )"; ss << capabilities_and_extensions; ss << R"( OpMemoryModel Physical32 OpenCL %void = OpTypeVoid %func = OpTypeFunction %void %bool = OpTypeBool %f32 = OpTypeFloat 32 %u32 = OpTypeInt 32 0 %u64 = OpTypeInt 64 0 %f32vec4 = OpTypeVector %f32 4 %f32_0 = OpConstant %f32 0 %f32_1 = OpConstant %f32 1 %u32_0 = OpConstant %u32 0 %u32_1 = OpConstant %u32 1 %u64_1 = OpConstant %u64 1 %f32vec4_0000 = OpConstantComposite %f32vec4 %f32_0 %f32_0 %f32_0 %f32_0 %scope = OpConstant %u32 1 %relaxed = OpConstant %u32 0 %acquire = OpConstant %u32 2 %release = OpConstant %u32 4 %acquire_release = OpConstant %u32 8 %acquire_and_release = OpConstant %u32 6 %sequentially_consistent = OpConstant %u32 16 %acquire_release_uniform_workgroup = OpConstant %u32 328 %acquire_release_atomic_counter_workgroup = OpConstant %u32 1288 %f32_ptr = OpTypePointer Workgroup %f32 %f32_var = OpVariable %f32_ptr Workgroup %u32_ptr = OpTypePointer Workgroup %u32 %u32_var = OpVariable %u32_ptr Workgroup %u64_ptr = OpTypePointer Workgroup %u64 %u64_var = OpVariable %u64_ptr Workgroup %f32vec4_ptr = OpTypePointer Workgroup %f32vec4 %f32vec4_var = OpVariable %f32vec4_ptr Workgroup %f32_ptr_function = OpTypePointer Function %f32 %main = OpFunction %void None %func %main_entry = OpLabel )"; ss << body; ss << R"( OpReturn OpFunctionEnd)"; return ss.str(); } TEST_F(ValidateAtomics, AtomicLoadShaderSuccess) { const std::string body = R"( %val1 = OpAtomicLoad %u32 %u32_var %scope %relaxed )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateAtomics, AtomicLoadKernelSuccess) { const std::string body = R"( %val1 = OpAtomicLoad %f32 %f32_var %scope %relaxed %val2 = OpAtomicLoad %u32 %u32_var %scope %relaxed %val3 = OpAtomicLoad %u64 %u64_var %scope %acquire )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateAtomics, AtomicLoadShaderFloat) { const std::string body = R"( %val1 = OpAtomicLoad %f32 %f32_var %scope %relaxed )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicLoad: " "expected Result Type to be int scalar type")); } TEST_F(ValidateAtomics, AtomicLoadWrongResultType) { const std::string body = R"( %val1 = OpAtomicLoad %f32vec4 %f32vec4_var %scope %relaxed )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicLoad: " "expected Result Type to be int or float scalar type")); } TEST_F(ValidateAtomics, AtomicLoadWrongPointerType) { const std::string body = R"( %val1 = OpAtomicLoad %f32 %f32_ptr %scope %relaxed )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicLoad: expected Pointer to be of type OpTypePointer")); } TEST_F(ValidateAtomics, AtomicLoadWrongPointerDataType) { const std::string body = R"( %val1 = OpAtomicLoad %u32 %f32_var %scope %relaxed )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicLoad: " "expected Pointer to point to a value of type Result Type")); } TEST_F(ValidateAtomics, AtomicLoadWrongScopeType) { const std::string body = R"( %val1 = OpAtomicLoad %f32 %f32_var %f32_1 %relaxed )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicLoad: expected Scope to be 32-bit int")); } TEST_F(ValidateAtomics, AtomicLoadWrongMemorySemanticsType) { const std::string body = R"( %val1 = OpAtomicLoad %f32 %f32_var %scope %u64_1 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicLoad: expected Memory Semantics to be 32-bit int")); } TEST_F(ValidateAtomics, AtomicStoreSuccess) { const std::string body = R"( OpAtomicStore %f32_var %scope %relaxed %f32_1 %val2 = OpAtomicStore %u32_var %scope %relaxed %u32_1 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateAtomics, AtomicStoreWrongPointerType) { const std::string body = R"( OpAtomicStore %f32_1 %scope %relaxed %f32_1 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicStore: expected Pointer to be of type OpTypePointer")); } TEST_F(ValidateAtomics, AtomicStoreWrongPointerDataType) { const std::string body = R"( OpAtomicStore %f32vec4_var %scope %relaxed %f32_1 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicStore: " "expected Pointer to be a pointer to int or float scalar " "type")); } TEST_F(ValidateAtomics, AtomicStoreWrongPointerStorageType) { const std::string body = R"( %f32_var_function = OpVariable %f32_ptr_function Function OpAtomicStore %f32_var_function %scope %relaxed %f32_1 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicStore: expected Pointer Storage Class to be Uniform, " "Workgroup, CrossWorkgroup, Generic, AtomicCounter, Image or " "StorageBuffer")); } TEST_F(ValidateAtomics, AtomicStoreWrongScopeType) { const std::string body = R"( OpAtomicStore %f32_var %f32_1 %relaxed %f32_1 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicStore: expected Scope to be 32-bit int")); } TEST_F(ValidateAtomics, AtomicStoreWrongMemorySemanticsType) { const std::string body = R"( OpAtomicStore %f32_var %scope %f32_1 %f32_1 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicStore: expected Memory Semantics to be 32-bit int")); } TEST_F(ValidateAtomics, AtomicStoreWrongValueType) { const std::string body = R"( OpAtomicStore %f32_var %scope %relaxed %u32_1 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicStore: " "expected Value type and the type pointed to by Pointer to " "be the same")); } TEST_F(ValidateAtomics, AtomicExchangeShaderSuccess) { const std::string body = R"( %val1 = OpAtomicStore %u32_var %scope %relaxed %u32_1 %val2 = OpAtomicExchange %u32 %u32_var %scope %relaxed %u32_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateAtomics, AtomicExchangeKernelSuccess) { const std::string body = R"( OpAtomicStore %f32_var %scope %relaxed %f32_1 %val2 = OpAtomicExchange %f32 %f32_var %scope %relaxed %f32_0 %val3 = OpAtomicStore %u32_var %scope %relaxed %u32_1 %val4 = OpAtomicExchange %u32 %u32_var %scope %relaxed %u32_0 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateAtomics, AtomicExchangeShaderFloat) { const std::string body = R"( OpAtomicStore %f32_var %scope %relaxed %f32_1 %val2 = OpAtomicExchange %f32 %f32_var %scope %relaxed %f32_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicExchange: " "expected Result Type to be int scalar type")); } TEST_F(ValidateAtomics, AtomicExchangeWrongResultType) { const std::string body = R"( %val1 = OpStore %f32vec4_var %f32vec4_0000 %val2 = OpAtomicExchange %f32vec4 %f32vec4_var %scope %relaxed %f32vec4_0000 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicExchange: " "expected Result Type to be int or float scalar type")); } TEST_F(ValidateAtomics, AtomicExchangeWrongPointerType) { const std::string body = R"( %val2 = OpAtomicExchange %f32 %f32vec4_ptr %scope %relaxed %f32vec4_0000 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr( "AtomicExchange: expected Pointer to be of type OpTypePointer")); } TEST_F(ValidateAtomics, AtomicExchangeWrongPointerDataType) { const std::string body = R"( %val1 = OpStore %f32vec4_var %f32vec4_0000 %val2 = OpAtomicExchange %f32 %f32vec4_var %scope %relaxed %f32vec4_0000 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicExchange: " "expected Pointer to point to a value of type Result Type")); } TEST_F(ValidateAtomics, AtomicExchangeWrongScopeType) { const std::string body = R"( OpAtomicStore %f32_var %scope %relaxed %f32_1 %val2 = OpAtomicExchange %f32 %f32_var %f32_1 %relaxed %f32_0 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicExchange: expected Scope to be 32-bit int")); } TEST_F(ValidateAtomics, AtomicExchangeWrongMemorySemanticsType) { const std::string body = R"( OpAtomicStore %f32_var %scope %relaxed %f32_1 %val2 = OpAtomicExchange %f32 %f32_var %scope %f32_1 %f32_0 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicExchange: expected Memory Semantics to be 32-bit int")); } TEST_F(ValidateAtomics, AtomicExchangeWrongValueType) { const std::string body = R"( OpAtomicStore %f32_var %scope %relaxed %f32_1 %val2 = OpAtomicExchange %f32 %f32_var %scope %relaxed %u32_0 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicExchange: " "expected Value to be of type Result Type")); } TEST_F(ValidateAtomics, AtomicCompareExchangeShaderSuccess) { const std::string body = R"( %val1 = OpAtomicStore %u32_var %scope %relaxed %u32_1 %val2 = OpAtomicCompareExchange %u32 %u32_var %scope %relaxed %relaxed %u32_0 %u32_0 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateAtomics, AtomicCompareExchangeKernelSuccess) { const std::string body = R"( OpAtomicStore %f32_var %scope %relaxed %f32_1 %val2 = OpAtomicCompareExchange %f32 %f32_var %scope %relaxed %relaxed %f32_0 %f32_1 %val3 = OpAtomicStore %u32_var %scope %relaxed %u32_1 %val4 = OpAtomicCompareExchange %u32 %u32_var %scope %relaxed %relaxed %u32_0 %u32_0 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateAtomics, AtomicCompareExchangeShaderFloat) { const std::string body = R"( OpAtomicStore %f32_var %scope %relaxed %f32_1 %val1 = OpAtomicCompareExchange %f32 %f32_var %scope %relaxed %relaxed %f32_0 %f32_1 )"; CompileSuccessfully(GenerateShaderCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicCompareExchange: " "expected Result Type to be int scalar type")); } TEST_F(ValidateAtomics, AtomicCompareExchangeWrongResultType) { const std::string body = R"( %val1 = OpStore %f32vec4_var %f32vec4_0000 %val2 = OpAtomicCompareExchange %f32vec4 %f32vec4_var %scope %relaxed %relaxed %f32vec4_0000 %f32vec4_0000 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicCompareExchange: " "expected Result Type to be int or float scalar type")); } TEST_F(ValidateAtomics, AtomicCompareExchangeWrongPointerType) { const std::string body = R"( %val2 = OpAtomicCompareExchange %f32 %f32vec4_ptr %scope %relaxed %relaxed %f32vec4_0000 %f32vec4_0000 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicCompareExchange: expected Pointer to be of type " "OpTypePointer")); } TEST_F(ValidateAtomics, AtomicCompareExchangeWrongPointerDataType) { const std::string body = R"( %val1 = OpStore %f32vec4_var %f32vec4_0000 %val2 = OpAtomicCompareExchange %f32 %f32vec4_var %scope %relaxed %relaxed %f32_0 %f32_1 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicCompareExchange: " "expected Pointer to point to a value of type Result Type")); } TEST_F(ValidateAtomics, AtomicCompareExchangeWrongScopeType) { const std::string body = R"( OpAtomicStore %f32_var %scope %relaxed %f32_1 %val2 = OpAtomicCompareExchange %f32 %f32_var %f32_1 %relaxed %relaxed %f32_0 %f32_0 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicCompareExchange: expected Scope to be 32-bit int")); } TEST_F(ValidateAtomics, AtomicCompareExchangeWrongMemorySemanticsType1) { const std::string body = R"( OpAtomicStore %f32_var %scope %relaxed %f32_1 %val2 = OpAtomicCompareExchange %f32 %f32_var %scope %f32_1 %relaxed %f32_0 %f32_0 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr( "AtomicCompareExchange: expected Memory Semantics to be 32-bit int")); } TEST_F(ValidateAtomics, AtomicCompareExchangeWrongMemorySemanticsType2) { const std::string body = R"( OpAtomicStore %f32_var %scope %relaxed %f32_1 %val2 = OpAtomicCompareExchange %f32 %f32_var %scope %relaxed %f32_1 %f32_0 %f32_0 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr( "AtomicCompareExchange: expected Memory Semantics to be 32-bit int")); } TEST_F(ValidateAtomics, AtomicCompareExchangeUnequalRelease) { const std::string body = R"( OpAtomicStore %f32_var %scope %relaxed %f32_1 %val2 = OpAtomicCompareExchange %f32 %f32_var %scope %relaxed %release %f32_0 %f32_0 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicCompareExchange: Memory Semantics Release and " "AcquireRelease cannot be used for operand Unequal")); } TEST_F(ValidateAtomics, AtomicCompareExchangeWrongValueType) { const std::string body = R"( OpAtomicStore %f32_var %scope %relaxed %f32_1 %val2 = OpAtomicCompareExchange %f32 %f32_var %scope %relaxed %relaxed %u32_0 %f32_1 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicCompareExchange: " "expected Value to be of type Result Type")); } TEST_F(ValidateAtomics, AtomicCompareExchangeWrongComparatorType) { const std::string body = R"( OpAtomicStore %f32_var %scope %relaxed %f32_1 %val2 = OpAtomicCompareExchange %f32 %f32_var %scope %relaxed %relaxed %f32_0 %u32_1 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicCompareExchange: " "expected Comparator to be of type Result Type")); } TEST_F(ValidateAtomics, AtomicCompareExchangeWeakSuccess) { const std::string body = R"( %val3 = OpAtomicStore %u32_var %scope %relaxed %u32_1 %val4 = OpAtomicCompareExchangeWeak %u32 %u32_var %scope %relaxed %relaxed %u32_0 %u32_0 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateAtomics, AtomicCompareExchangeWeakWrongResultType) { const std::string body = R"( OpAtomicStore %f32_var %scope %relaxed %f32_1 %val2 = OpAtomicCompareExchangeWeak %f32 %f32_var %scope %relaxed %relaxed %f32_0 %f32_1 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicCompareExchangeWeak: " "expected Result Type to be int scalar type")); } TEST_F(ValidateAtomics, AtomicArithmeticsSuccess) { const std::string body = R"( OpAtomicStore %u32_var %scope %relaxed %u32_1 %val1 = OpAtomicIIncrement %u32 %u32_var %scope %acquire_release %val2 = OpAtomicIDecrement %u32 %u32_var %scope %acquire_release %val3 = OpAtomicIAdd %u32 %u32_var %scope %acquire_release %u32_1 %val4 = OpAtomicISub %u32 %u32_var %scope %acquire_release %u32_1 %val5 = OpAtomicUMin %u32 %u32_var %scope %acquire_release %u32_1 %val6 = OpAtomicUMax %u32 %u32_var %scope %acquire_release %u32_1 %val7 = OpAtomicSMin %u32 %u32_var %scope %sequentially_consistent %u32_1 %val8 = OpAtomicSMax %u32 %u32_var %scope %sequentially_consistent %u32_1 %val9 = OpAtomicAnd %u32 %u32_var %scope %sequentially_consistent %u32_1 %val10 = OpAtomicOr %u32 %u32_var %scope %sequentially_consistent %u32_1 %val11 = OpAtomicXor %u32 %u32_var %scope %sequentially_consistent %u32_1 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateAtomics, AtomicFlagsSuccess) { const std::string body = R"( OpAtomicFlagClear %u32_var %scope %release %val1 = OpAtomicFlagTestAndSet %bool %u32_var %scope %relaxed )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateAtomics, AtomicFlagTestAndSetWrongResultType) { const std::string body = R"( %val1 = OpAtomicFlagTestAndSet %u32 %u32_var %scope %relaxed )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicFlagTestAndSet: " "expected Result Type to be bool scalar type")); } TEST_F(ValidateAtomics, AtomicFlagTestAndSetNotPointer) { const std::string body = R"( %val1 = OpAtomicFlagTestAndSet %bool %u32_1 %scope %relaxed )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicFlagTestAndSet: " "expected Pointer to be of type OpTypePointer")); } TEST_F(ValidateAtomics, AtomicFlagTestAndSetNotIntPointer) { const std::string body = R"( %val1 = OpAtomicFlagTestAndSet %bool %f32_var %scope %relaxed )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicFlagTestAndSet: " "expected Pointer to point to a value of 32-bit int type")); } TEST_F(ValidateAtomics, AtomicFlagTestAndSetNotInt32Pointer) { const std::string body = R"( %val1 = OpAtomicFlagTestAndSet %bool %u64_var %scope %relaxed )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicFlagTestAndSet: " "expected Pointer to point to a value of 32-bit int type")); } TEST_F(ValidateAtomics, AtomicFlagTestAndSetWrongScopeType) { const std::string body = R"( %val1 = OpAtomicFlagTestAndSet %bool %u32_var %u64_1 %relaxed )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicFlagTestAndSet: " "expected Scope to be 32-bit int")); } TEST_F(ValidateAtomics, AtomicFlagTestAndSetWrongMemorySemanticsType) { const std::string body = R"( %val1 = OpAtomicFlagTestAndSet %bool %u32_var %scope %u64_1 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicFlagTestAndSet: " "expected Memory Semantics to be 32-bit int")); } TEST_F(ValidateAtomics, AtomicFlagClearAcquire) { const std::string body = R"( OpAtomicFlagClear %u32_var %scope %acquire )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("Memory Semantics Acquire and AcquireRelease cannot be " "used with AtomicFlagClear")); } TEST_F(ValidateAtomics, AtomicFlagClearNotPointer) { const std::string body = R"( OpAtomicFlagClear %u32_1 %scope %relaxed )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicFlagClear: " "expected Pointer to be of type OpTypePointer")); } TEST_F(ValidateAtomics, AtomicFlagClearNotIntPointer) { const std::string body = R"( OpAtomicFlagClear %f32_var %scope %relaxed )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicFlagClear: " "expected Pointer to point to a value of 32-bit int type")); } TEST_F(ValidateAtomics, AtomicFlagClearNotInt32Pointer) { const std::string body = R"( OpAtomicFlagClear %u64_var %scope %relaxed )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicFlagClear: " "expected Pointer to point to a value of 32-bit int type")); } TEST_F(ValidateAtomics, AtomicFlagClearWrongScopeType) { const std::string body = R"( OpAtomicFlagClear %u32_var %u64_1 %relaxed )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicFlagClear: expected Scope to be 32-bit int")); } TEST_F(ValidateAtomics, AtomicFlagClearWrongMemorySemanticsType) { const std::string body = R"( OpAtomicFlagClear %u32_var %scope %u64_1 )"; CompileSuccessfully(GenerateKernelCode(body).c_str()); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicFlagClear: expected Memory Semantics to be 32-bit int")); } TEST_F(ValidateAtomics, AtomicIIncrementAcquireAndRelease) { const std::string body = R"( OpAtomicStore %u32_var %scope %relaxed %u32_1 %val1 = OpAtomicIIncrement %u32 %u32_var %scope %acquire_and_release )"; CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT( getDiagnosticString(), HasSubstr("AtomicIIncrement: no more than one of the following Memory " "Semantics bits can be set at the same time: Acquire, Release, " "AcquireRelease or SequentiallyConsistent")); } TEST_F(ValidateAtomics, AtomicUniformMemorySemanticsShader) { const std::string body = R"( OpAtomicStore %u32_var %scope %relaxed %u32_1 %val1 = OpAtomicIIncrement %u32 %u32_var %scope %acquire_release_uniform_workgroup )"; CompileSuccessfully(GenerateShaderCode(body)); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(ValidateAtomics, AtomicUniformMemorySemanticsKernel) { const std::string body = R"( OpAtomicStore %u32_var %scope %relaxed %u32_1 %val1 = OpAtomicIIncrement %u32 %u32_var %scope %acquire_release_uniform_workgroup )"; CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicIIncrement: Memory Semantics UniformMemory " "requires capability Shader")); } TEST_F(ValidateAtomics, AtomicCounterMemorySemanticsNoCapability) { const std::string body = R"( OpAtomicStore %u32_var %scope %relaxed %u32_1 %val1 = OpAtomicIIncrement %u32 %u32_var %scope %acquire_release_atomic_counter_workgroup )"; CompileSuccessfully(GenerateKernelCode(body)); ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("AtomicIIncrement: Memory Semantics UniformMemory " "requires capability AtomicStorage")); } TEST_F(ValidateAtomics, AtomicCounterMemorySemanticsWithCapability) { const std::string body = R"( OpAtomicStore %u32_var %scope %relaxed %u32_1 %val1 = OpAtomicIIncrement %u32 %u32_var %scope %acquire_release_atomic_counter_workgroup )"; CompileSuccessfully(GenerateKernelCode(body, "OpCapability AtomicStorage\n")); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } } // anonymous namespace