// Copyright (c) 2015-2016 The Khronos Group Inc. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and/or associated documentation files (the // "Materials"), to deal in the Materials without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Materials, and to // permit persons to whom the Materials are furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Materials. // // MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS // KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS // SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT // https://www.khronos.org/registry/ // // THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE // MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. // Validation tests for SSA #include "UnitSPIRV.h" #include "ValidateFixtures.h" #include "gmock/gmock.h" #include #include #include using ::testing::HasSubstr; using std::string; using std::pair; using std::stringstream; namespace { using Validate = spvtest::ValidateBase, SPV_VALIDATE_SSA_BIT | SPV_VALIDATE_LAYOUT_BIT>; TEST_F(Validate, Default) { char str[] = R"( OpMemoryModel Logical GLSL450 OpEntryPoint GLCompute %3 "" OpExecutionMode %3 LocalSize 1 1 1 %1 = OpTypeVoid %2 = OpTypeFunction %1 %3 = OpFunction %1 None %2 %4 = OpLabel OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(Validate, IdUndefinedBad) { char str[] = R"( OpMemoryModel Logical GLSL450 OpName %missing "missing" %voidt = OpTypeVoid %vfunct = OpTypeFunction %voidt %func = OpFunction %vfunct None %missing %flabel = OpLabel OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("missing")); } TEST_F(Validate, IdRedefinedBad) { char str[] = R"( OpMemoryModel Logical GLSL450 OpName %2 "redefined" %1 = OpTypeVoid %2 = OpTypeFunction %1 %2 = OpFunction %1 None %2 %4 = OpLabel OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); } TEST_F(Validate, DominateUsageBad) { char str[] = R"( OpMemoryModel Logical GLSL450 OpName %1 "not_dominant" %2 = OpTypeFunction %1 ; uses %1 before it's definition %1 = OpTypeVoid )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("not_dominant")); } TEST_F(Validate, ForwardNameGood) { char str[] = R"( OpMemoryModel Logical GLSL450 OpName %3 "main" %1 = OpTypeVoid %2 = OpTypeFunction %1 %3 = OpFunction %1 None %2 %4 = OpLabel OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(Validate, ForwardNameMissingTargetBad) { char str[] = R"( OpMemoryModel Logical GLSL450 OpName %5 "main" ; Target never defined )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("main")); } TEST_F(Validate, ForwardMemberNameGood) { char str[] = R"( OpMemoryModel Logical GLSL450 OpMemberName %struct 0 "value" OpMemberName %struct 1 "size" %intt = OpTypeInt 32 1 %uintt = OpTypeInt 32 0 %struct = OpTypeStruct %intt %uintt )"; CompileSuccessfully(str); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(Validate, ForwardMemberNameMissingTargetBad) { char str[] = R"( OpMemoryModel Logical GLSL450 OpMemberName %struct 0 "value" OpMemberName %bad 1 "size" ; Target is not defined %intt = OpTypeInt 32 1 %uintt = OpTypeInt 32 0 %struct = OpTypeStruct %intt %uintt )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("size")); } TEST_F(Validate, ForwardDecorateGood) { char str[] = R"( OpMemoryModel Logical GLSL450 OpDecorate %var Restrict %intt = OpTypeInt 32 1 %ptrt = OpTypePointer UniformConstant %intt %var = OpVariable %ptrt UniformConstant )"; CompileSuccessfully(str); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(Validate, ForwardDecorateInvalidIDBad) { char str[] = R"( OpMemoryModel Logical GLSL450 OpName %missing "missing" OpDecorate %missing Restrict ;Missing ID %voidt = OpTypeVoid %intt = OpTypeInt 32 1 %ptrt = OpTypePointer UniformConstant %intt %var = OpVariable %ptrt UniformConstant %2 = OpTypeFunction %voidt %3 = OpFunction %voidt None %2 %4 = OpLabel OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("missing")); } TEST_F(Validate, ForwardMemberDecorateGood) { char str[] = R"( OpCapability Matrix OpMemoryModel Logical GLSL450 OpMemberDecorate %struct 1 RowMajor %intt = OpTypeInt 32 1 %vec3 = OpTypeVector %intt 3 %mat33 = OpTypeMatrix %vec3 3 %struct = OpTypeStruct %intt %mat33 )"; CompileSuccessfully(str); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(Validate, ForwardMemberDecorateInvalidIdBad) { char str[] = R"( OpCapability Matrix OpMemoryModel Logical GLSL450 OpName %missing "missing" OpMemberDecorate %missing 1 RowMajor ; Target not defined %intt = OpTypeInt 32 1 %vec3 = OpTypeVector %intt 3 %mat33 = OpTypeMatrix %vec3 3 %struct = OpTypeStruct %intt %mat33 )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("missing")); } TEST_F(Validate, ForwardGroupDecorateGood) { char str[] = R"( OpCapability Matrix OpMemoryModel Logical GLSL450 OpDecorate %dgrp RowMajor %dgrp = OpDecorationGroup OpGroupDecorate %dgrp %mat33 %mat44 %intt = OpTypeInt 32 1 %vec3 = OpTypeVector %intt 3 %vec4 = OpTypeVector %intt 4 %mat33 = OpTypeMatrix %vec3 3 %mat44 = OpTypeMatrix %vec4 4 )"; CompileSuccessfully(str); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(Validate, ForwardGroupDecorateMissingGroupBad) { char str[] = R"( OpCapability Matrix OpMemoryModel Logical GLSL450 OpName %missing "missing" OpDecorate %dgrp RowMajor %dgrp = OpDecorationGroup OpGroupDecorate %missing %mat33 %mat44 ; Target not defined %intt = OpTypeInt 32 1 %vec3 = OpTypeVector %intt 3 %vec4 = OpTypeVector %intt 4 %mat33 = OpTypeMatrix %vec3 3 %mat44 = OpTypeMatrix %vec4 4 )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("missing")); } TEST_F(Validate, ForwardGroupDecorateMissingTargetBad) { char str[] = R"( OpCapability Matrix OpMemoryModel Logical GLSL450 OpName %missing "missing" OpDecorate %dgrp RowMajor %dgrp = OpDecorationGroup OpGroupDecorate %dgrp %missing %mat44 ; Target not defined %intt = OpTypeInt 32 1 %vec3 = OpTypeVector %intt 3 %vec4 = OpTypeVector %intt 4 %mat33 = OpTypeMatrix %vec3 3 %mat44 = OpTypeMatrix %vec4 4 )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("missing")); } TEST_F(Validate, ForwardGroupDecorateDecorationGroupDominateBad) { char str[] = R"( OpCapability Matrix OpMemoryModel Logical GLSL450 OpName %dgrp "group" OpDecorate %dgrp RowMajor OpGroupDecorate %dgrp %mat33 %mat44 ; Decoration group does not dominate usage %dgrp = OpDecorationGroup %intt = OpTypeInt 32 1 %vec3 = OpTypeVector %intt 3 %vec4 = OpTypeVector %intt 4 %mat33 = OpTypeMatrix %vec3 3 %mat44 = OpTypeMatrix %vec4 4 )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("group")); } TEST_F(Validate, ForwardDecorateInvalidIdBad) { char str[] = R"( OpMemoryModel Logical GLSL450 OpName %missing "missing" OpDecorate %missing Restrict ; Missing target %voidt = OpTypeVoid %intt = OpTypeInt 32 1 %ptrt = OpTypePointer UniformConstant %intt %var = OpVariable %ptrt UniformConstant %2 = OpTypeFunction %voidt %3 = OpFunction %voidt None %2 %4 = OpLabel OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("missing")); } TEST_F(Validate, FunctionCallGood) { char str[] = R"( OpMemoryModel Logical GLSL450 %1 = OpTypeVoid %2 = OpTypeInt 32 1 %3 = OpTypeInt 32 0 %4 = OpTypeFunction %1 %8 = OpTypeFunction %1 %2 %3 %four = OpConstant %2 4 %five = OpConstant %3 5 %9 = OpFunction %1 None %8 %10 = OpFunctionParameter %2 %11 = OpFunctionParameter %3 %12 = OpLabel OpReturn OpFunctionEnd %5 = OpFunction %1 None %4 %6 = OpLabel %7 = OpFunctionCall %1 %9 %four %five OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(Validate, ForwardFunctionCallGood) { char str[] = R"( OpMemoryModel Logical GLSL450 %1 = OpTypeVoid %2 = OpTypeInt 32 1 %3 = OpTypeInt 32 0 %four = OpConstant %2 4 %five = OpConstant %3 5 %8 = OpTypeFunction %1 %2 %3 %4 = OpTypeFunction %1 %5 = OpFunction %1 None %4 %6 = OpLabel %7 = OpFunctionCall %1 %9 %four %five OpReturn OpFunctionEnd %9 = OpFunction %1 None %8 %10 = OpFunctionParameter %2 %11 = OpFunctionParameter %3 %12 = OpLabel OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(Validate, ForwardBranchConditionalGood) { char str[] = R"( OpMemoryModel Logical GLSL450 %voidt = OpTypeVoid %boolt = OpTypeBool %vfunct = OpTypeFunction %voidt %true = OpConstantTrue %boolt %main = OpFunction %voidt None %vfunct %mainl = OpLabel OpSelectionMerge %endl None OpBranchConditional %true %truel %falsel %truel = OpLabel OpNop OpBranch %endl %falsel = OpLabel OpNop OpBranch %endl %endl = OpLabel OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(Validate, ForwardBranchConditionalWithWeightsGood) { char str[] = R"( OpMemoryModel Logical GLSL450 %voidt = OpTypeVoid %boolt = OpTypeBool %vfunct = OpTypeFunction %voidt %true = OpConstantTrue %boolt %main = OpFunction %voidt None %vfunct %mainl = OpLabel OpSelectionMerge %endl None OpBranchConditional %true %truel %falsel 1 9 %truel = OpLabel OpNop OpBranch %endl %falsel = OpLabel OpNop OpBranch %endl %endl = OpLabel OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(Validate, ForwardBranchConditionalNonDominantConditionBad) { char str[] = R"( OpMemoryModel Logical GLSL450 OpName %tcpy "conditional" %voidt = OpTypeVoid %boolt = OpTypeBool %vfunct = OpTypeFunction %voidt %true = OpConstantTrue %boolt %main = OpFunction %voidt None %vfunct %mainl = OpLabel OpSelectionMerge %endl None OpBranchConditional %tcpy %truel %falsel ; %truel = OpLabel OpNop OpBranch %endl %falsel = OpLabel OpNop OpBranch %endl %endl = OpLabel %tcpy = OpCopyObject %boolt %true OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("conditional")); } TEST_F(Validate, ForwardBranchConditionalMissingTargetBad) { char str[] = R"( OpMemoryModel Logical GLSL450 OpName %missing "missing" %voidt = OpTypeVoid %boolt = OpTypeBool %vfunct = OpTypeFunction %voidt %true = OpConstantTrue %boolt %main = OpFunction %voidt None %vfunct %mainl = OpLabel OpSelectionMerge %endl None OpBranchConditional %true %missing %falsel %truel = OpLabel OpNop OpBranch %endl %falsel = OpLabel OpNop OpBranch %endl %endl = OpLabel OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("missing")); } const string kHeader = R"( OpCapability Int8 OpCapability DeviceEnqueue OpMemoryModel Logical GLSL450 )"; const string kBasicTypes = R"( %voidt = OpTypeVoid %boolt = OpTypeBool %int8t = OpTypeInt 8 0 %intt = OpTypeInt 32 1 %uintt = OpTypeInt 32 0 %vfunct = OpTypeFunction %voidt )"; const string kKernelTypesAndConstants = R"( %queuet = OpTypeQueue %three = OpConstant %uintt 3 %arr3t = OpTypeArray %intt %three %ndt = OpTypeStruct %intt %arr3t %arr3t %arr3t %eventt = OpTypeEvent %intptrt = OpTypePointer UniformConstant %int8t %offset = OpConstant %intt 0 %local = OpConstant %intt 1 %gl = OpConstant %intt 1 %nevent = OpConstant %intt 0 %event = OpConstantNull %eventt %firstp = OpConstant %int8t 0 %psize = OpConstant %intt 0 %palign = OpConstant %intt 32 %lsize = OpConstant %intt 1 %flags = OpConstant %intt 0 ; NoWait %kfunct = OpTypeFunction %voidt %intptrt )"; const string kKernelSetup = R"( %dqueue = OpGetDefaultQueue %queuet %ndval = OpBuildNDRange %ndt %gl %local %offset %revent = OpUndef %eventt )"; const string kKernelDefinition = R"( %kfunc = OpFunction %voidt None %kfunct %iparam = OpFunctionParameter %intptrt %kfuncl = OpLabel OpNop OpReturn OpFunctionEnd )"; TEST_F(Validate, EnqueueKernelGood) { string str = kHeader + kBasicTypes + kKernelTypesAndConstants + kKernelDefinition + R"( %main = OpFunction %voidt None %vfunct %mainl = OpLabel )" + kKernelSetup + R"( %err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent %event %revent %kfunc %firstp %psize %palign %lsize OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(Validate, ForwardEnqueueKernelGood) { string str = kHeader + kBasicTypes + kKernelTypesAndConstants + R"( %main = OpFunction %voidt None %vfunct %mainl = OpLabel )" + kKernelSetup + R"( %err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent %event %revent %kfunc %firstp %psize %palign %lsize OpReturn OpFunctionEnd )" + kKernelDefinition; CompileSuccessfully(str); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(Validate, EnqueueMissingFunctionBad) { string str = kHeader + "OpName %kfunc \"kfunc\"" + kBasicTypes + kKernelTypesAndConstants + R"( %main = OpFunction %voidt None %vfunct %mainl = OpLabel )" + kKernelSetup + R"( %err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent %event %revent %kfunc %firstp %psize %palign %lsize OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("kfunc")); } string forwardKernelNonDominantParameterBaseCode(string name = string()) { string op_name; if (name.empty()) { op_name = ""; } else { op_name = "\nOpName %" + name + " \"" + name + "\"\n"; } string out = kHeader + op_name + kBasicTypes + kKernelTypesAndConstants + kKernelDefinition + R"( %main = OpFunction %voidt None %vfunct %mainl = OpLabel )" + kKernelSetup; return out; } TEST_F(Validate, ForwardEnqueueKernelMissingParameter1Bad) { string str = forwardKernelNonDominantParameterBaseCode("missing") + R"( %err = OpEnqueueKernel %missing %dqueue %flags %ndval %nevent %event %revent %kfunc %firstp %psize %palign %lsize OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("missing")); } TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter2Bad) { string str = forwardKernelNonDominantParameterBaseCode("dqueue2") + R"( %err = OpEnqueueKernel %uintt %dqueue2 %flags %ndval %nevent %event %revent %kfunc %firstp %psize %palign %lsize %dqueue2 = OpGetDefaultQueue %queuet OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("dqueue2")); } TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter3Bad) { string str = forwardKernelNonDominantParameterBaseCode("ndval2") + R"( %err = OpEnqueueKernel %uintt %dqueue %flags %ndval2 %nevent %event %revent %kfunc %firstp %psize %palign %lsize %ndval2 = OpBuildNDRange %ndt %gl %local %offset OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("ndval2")); } TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter4Bad) { string str = forwardKernelNonDominantParameterBaseCode("nevent2") + R"( %err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent2 %event %revent %kfunc %firstp %psize %palign %lsize %nevent2 = OpCopyObject %intt %nevent OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("nevent2")); } TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter5Bad) { string str = forwardKernelNonDominantParameterBaseCode("event2") + R"( %err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent %event2 %revent %kfunc %firstp %psize %palign %lsize %event2 = OpCopyObject %eventt %event OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("event2")); } TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter6Bad) { string str = forwardKernelNonDominantParameterBaseCode("revent2") + R"( %err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent %event %revent2 %kfunc %firstp %psize %palign %lsize %revent2 = OpCopyObject %eventt %revent OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("revent2")); } TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter8Bad) { string str = forwardKernelNonDominantParameterBaseCode("firstp2") + R"( %err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent %event %revent %kfunc %firstp2 %psize %palign %lsize %firstp2 = OpCopyObject %int8t %firstp OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("firstp2")); } TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter9Bad) { string str = forwardKernelNonDominantParameterBaseCode("psize2") + R"( %err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent %event %revent %kfunc %firstp %psize2 %palign %lsize %psize2 = OpCopyObject %intt %psize OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("psize2")); } TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter10Bad) { string str = forwardKernelNonDominantParameterBaseCode("palign2") + R"( %err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent %event %revent %kfunc %firstp %psize %palign2 %lsize %palign2 = OpCopyObject %intt %palign OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("palign2")); } TEST_F(Validate, ForwardEnqueueKernelNonDominantParameter11Bad) { string str = forwardKernelNonDominantParameterBaseCode("lsize2") + R"( %err = OpEnqueueKernel %uintt %dqueue %flags %ndval %nevent %event %revent %kfunc %firstp %psize %palign %lsize2 %lsize2 = OpCopyObject %intt %lsize OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("lsize2")); } static const bool kWithNDrange = true; static const bool kNoNDrange = false; pair cases[] = { {"OpGetKernelNDrangeSubGroupCount", kWithNDrange}, {"OpGetKernelNDrangeMaxSubGroupSize", kWithNDrange}, {"OpGetKernelWorkGroupSize", kNoNDrange}, {"OpGetKernelPreferredWorkGroupSizeMultiple", kNoNDrange}}; INSTANTIATE_TEST_CASE_P(KernelArgs, Validate, ::testing::ValuesIn(cases)); static const string return_instructions = R"( OpReturn OpFunctionEnd )"; TEST_P(Validate, GetKernelGood) { string instruction = GetParam().first; bool with_ndrange = GetParam().second; string ndrange_param = with_ndrange ? " %ndval " : " "; stringstream ss; // clang-format off ss << forwardKernelNonDominantParameterBaseCode() + " %numsg = " << instruction + " %uintt" + ndrange_param + "%kfunc %firstp %psize %palign" << return_instructions; // clang-format on CompileSuccessfully(ss.str()); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_P(Validate, ForwardGetKernelGood) { string instruction = GetParam().first; bool with_ndrange = GetParam().second; string ndrange_param = with_ndrange ? " %ndval " : " "; // clang-format off string str = kHeader + kBasicTypes + kKernelTypesAndConstants + R"( %main = OpFunction %voidt None %vfunct %mainl = OpLabel )" + kKernelSetup + " %numsg = " + instruction + " %uintt" + ndrange_param + "%kfunc %firstp %psize %palign" + return_instructions + kKernelDefinition; // clang-format on CompileSuccessfully(str); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_P(Validate, ForwardGetKernelMissingDefinitionBad) { string instruction = GetParam().first; bool with_ndrange = GetParam().second; string ndrange_param = with_ndrange ? " %ndval " : " "; stringstream ss; // clang-format off ss << forwardKernelNonDominantParameterBaseCode("missing") + " %numsg = " << instruction + " %uintt" + ndrange_param + "%missing %firstp %psize %palign" << return_instructions; // clang-format on CompileSuccessfully(ss.str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("missing")); } TEST_P(Validate, ForwardGetKernelNDrangeSubGroupCountMissingParameter1Bad) { string instruction = GetParam().first; bool with_ndrange = GetParam().second; string ndrange_param = with_ndrange ? " %ndval " : " "; stringstream ss; // clang-format off ss << forwardKernelNonDominantParameterBaseCode("missing") + " %numsg = " << instruction + " %missing" + ndrange_param + "%kfunc %firstp %psize %palign" << return_instructions; // clang-format on CompileSuccessfully(ss.str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("missing")); } TEST_P(Validate, ForwardGetKernelNDrangeSubGroupCountNonDominantParameter2Bad) { string instruction = GetParam().first; bool with_ndrange = GetParam().second; string ndrange_param = with_ndrange ? " %ndval2 " : " "; stringstream ss; // clang-format off ss << forwardKernelNonDominantParameterBaseCode("ndval2") + " %numsg = " << instruction + " %uintt" + ndrange_param + "%kfunc %firstp %psize %palign" << "\n %ndval2 = OpBuildNDRange %ndt %gl %local %offset" << return_instructions; // clang-format on if (GetParam().second) { CompileSuccessfully(ss.str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("ndval2")); } } TEST_P(Validate, ForwardGetKernelNDrangeSubGroupCountNonDominantParameter4Bad) { string instruction = GetParam().first; bool with_ndrange = GetParam().second; string ndrange_param = with_ndrange ? " %ndval " : " "; stringstream ss; // clang-format off ss << forwardKernelNonDominantParameterBaseCode("firstp2") + " %numsg = " << instruction + " %uintt" + ndrange_param + "%kfunc %firstp2 %psize %palign" << "\n %firstp2 = OpCopyObject %int8t %firstp" << return_instructions; // clang-format on CompileSuccessfully(ss.str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("firstp2")); } TEST_P(Validate, ForwardGetKernelNDrangeSubGroupCountNonDominantParameter5Bad) { string instruction = GetParam().first; bool with_ndrange = GetParam().second; string ndrange_param = with_ndrange ? " %ndval " : " "; stringstream ss; // clang-format off ss << forwardKernelNonDominantParameterBaseCode("psize2") + " %numsg = " << instruction + " %uintt" + ndrange_param + "%kfunc %firstp %psize2 %palign" << "\n %psize2 = OpCopyObject %intt %psize" << return_instructions; // clang-format on CompileSuccessfully(ss.str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("psize2")); } TEST_P(Validate, ForwardGetKernelNDrangeSubGroupCountNonDominantParameter6Bad) { string instruction = GetParam().first; bool with_ndrange = GetParam().second; string ndrange_param = with_ndrange ? " %ndval " : " "; stringstream ss; // clang-format off ss << forwardKernelNonDominantParameterBaseCode("palign2") + " %numsg = " << instruction + " %uintt" + ndrange_param + "%kfunc %firstp %psize %palign2" << "\n %palign2 = OpCopyObject %intt %palign" << return_instructions; // clang-format on if (GetParam().second) { CompileSuccessfully(ss.str()); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("palign2")); } } TEST_F(Validate, PhiGood) { string str = kHeader + kBasicTypes + R"( %zero = OpConstant %intt 0 %one = OpConstant %intt 1 %ten = OpConstant %intt 10 %func = OpFunction %voidt None %vfunct %preheader = OpLabel %init = OpCopyObject %intt %zero OpBranch %loop %loop = OpLabel %i = OpPhi %intt %init %preheader %loopi %loop %loopi = OpIAdd %intt %i %one OpNop %cond = OpSLessThan %boolt %i %ten OpLoopMerge %endl %loop None OpBranchConditional %cond %loop %endl %endl = OpLabel OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); } TEST_F(Validate, PhiMissingTypeBad) { string str = kHeader + "OpName %missing \"missing\"" + kBasicTypes + R"( %zero = OpConstant %intt 0 %one = OpConstant %intt 1 %ten = OpConstant %intt 10 %func = OpFunction %voidt None %vfunct %preheader = OpLabel %init = OpCopyObject %intt %zero OpBranch %loop %loop = OpLabel %i = OpPhi %missing %init %preheader %loopi %loop %loopi = OpIAdd %intt %i %one OpNop %cond = OpSLessThan %boolt %i %ten OpLoopMerge %endl %loop None OpBranchConditional %cond %loop %endl %endl = OpLabel OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("missing")); } TEST_F(Validate, PhiMissingIdBad) { string str = kHeader + "OpName %missing \"missing\"" + kBasicTypes + R"( %zero = OpConstant %intt 0 %one = OpConstant %intt 1 %ten = OpConstant %intt 10 %func = OpFunction %voidt None %vfunct %preheader = OpLabel %init = OpCopyObject %intt %zero OpBranch %loop %loop = OpLabel %i = OpPhi %intt %missing %preheader %loopi %loop %loopi = OpIAdd %intt %i %one OpNop %cond = OpSLessThan %boolt %i %ten OpLoopMerge %endl %loop None OpBranchConditional %cond %loop %endl %endl = OpLabel OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("missing")); } TEST_F(Validate, PhiMissingLabelBad) { string str = kHeader + "OpName %missing \"missing\"" + kBasicTypes + R"( %zero = OpConstant %intt 0 %one = OpConstant %intt 1 %ten = OpConstant %intt 10 %func = OpFunction %voidt None %vfunct %preheader = OpLabel %init = OpCopyObject %intt %zero OpBranch %loop %loop = OpLabel %i = OpPhi %intt %init %missing %loopi %loop %loopi = OpIAdd %intt %i %one OpNop %cond = OpSLessThan %boolt %i %ten OpLoopMerge %endl %loop None OpBranchConditional %cond %loop %endl %endl = OpLabel OpReturn OpFunctionEnd )"; CompileSuccessfully(str); ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); EXPECT_THAT(getDiagnosticString(), HasSubstr("missing")); } // TODO(umar): OpGroupMemberDecorate }