SPIRV-Tools/test/Validate.SSA.cpp
2016-01-14 09:48:29 -05:00

1009 lines
32 KiB
C++

// 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 <sstream>
#include <string>
#include <utility>
using ::testing::HasSubstr;
using std::string;
using std::pair;
using std::stringstream;
namespace {
using Validate =
spvtest::ValidateBase<pair<string, bool>,
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<string, bool> 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
}