| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755 |
- // Copyright (c) 2015-2016 The Khronos Group Inc.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- // Validation tests for Logical Layout
- #include <functional>
- #include <string>
- #include <tuple>
- #include <utility>
- #include <vector>
- #include "gmock/gmock.h"
- #include "source/diagnostic.h"
- #include "test/unit_spirv.h"
- #include "test/val/val_fixtures.h"
- namespace spvtools {
- namespace val {
- namespace {
- using ::testing::Eq;
- using ::testing::HasSubstr;
- using ::testing::StrEq;
- using pred_type = std::function<spv_result_t(int)>;
- using ValidateLayout = spvtest::ValidateBase<
- std::tuple<int, std::tuple<std::string, pred_type, pred_type>>>;
- // returns true if order is equal to VAL
- template <int VAL, spv_result_t RET = SPV_ERROR_INVALID_LAYOUT>
- spv_result_t Equals(int order) {
- return order == VAL ? SPV_SUCCESS : RET;
- }
- // returns true if order is between MIN and MAX(inclusive)
- template <int MIN, int MAX, spv_result_t RET = SPV_ERROR_INVALID_LAYOUT>
- struct Range {
- explicit Range(bool inverse = false) : inverse_(inverse) {}
- spv_result_t operator()(int order) {
- return (inverse_ ^ (order >= MIN && order <= MAX)) ? SPV_SUCCESS : RET;
- }
- private:
- bool inverse_;
- };
- // SPIRV source used to test the logical layout
- const std::vector<std::string>& getInstructions() {
- // clang-format off
- static const std::vector<std::string> instructions = {
- "OpCapability Shader",
- "OpExtension \"TestExtension\"",
- "%inst = OpExtInstImport \"GLSL.std.450\"",
- "OpMemoryModel Logical GLSL450",
- "OpEntryPoint GLCompute %func \"\"",
- "OpExecutionMode %func LocalSize 1 1 1",
- "OpExecutionModeId %func LocalSizeId %one %one %one",
- "%str = OpString \"Test String\"",
- "%str2 = OpString \"blabla\"",
- "OpSource GLSL 450 %str \"uniform vec3 var = vec3(4.0);\"",
- "OpSourceContinued \"void main(){return;}\"",
- "OpSourceExtension \"Test extension\"",
- "OpName %func \"MyFunction\"",
- "OpMemberName %struct 1 \"my_member\"",
- "OpDecorate %dgrp RowMajor",
- "OpMemberDecorate %struct 1 RowMajor",
- "%dgrp = OpDecorationGroup",
- "OpGroupDecorate %dgrp %mat33 %mat44",
- "%intt = OpTypeInt 32 1",
- "%floatt = OpTypeFloat 32",
- "%voidt = OpTypeVoid",
- "%boolt = OpTypeBool",
- "%vec4 = OpTypeVector %floatt 4",
- "%vec3 = OpTypeVector %floatt 3",
- "%mat33 = OpTypeMatrix %vec3 3",
- "%mat44 = OpTypeMatrix %vec4 4",
- "%struct = OpTypeStruct %intt %mat33",
- "%vfunct = OpTypeFunction %voidt",
- "%viifunct = OpTypeFunction %voidt %intt %intt",
- "%one = OpConstant %intt 1",
- // TODO(umar): OpConstant fails because the type is not defined
- // TODO(umar): OpGroupMemberDecorate
- "OpLine %str 3 4",
- "OpNoLine",
- "%func = OpFunction %voidt None %vfunct",
- "%l = OpLabel",
- "OpReturn ; %func return",
- "OpFunctionEnd ; %func end",
- "%func2 = OpFunction %voidt None %viifunct",
- "%funcp1 = OpFunctionParameter %intt",
- "%funcp2 = OpFunctionParameter %intt",
- "%fLabel = OpLabel",
- "OpNop",
- "OpReturn ; %func2 return",
- "OpFunctionEnd"
- };
- return instructions;
- }
- static const int kRangeEnd = 1000;
- pred_type All = Range<0, kRangeEnd>();
- INSTANTIATE_TEST_SUITE_P(InstructionsOrder,
- ValidateLayout,
- ::testing::Combine(::testing::Range((int)0, (int)getInstructions().size()),
- // Note: Because of ID dependencies between instructions, some instructions
- // are not free to be placed anywhere without triggering an non-layout
- // validation error. Therefore, "Lines to compile" for some instructions
- // are not "All" in the below.
- //
- // | Instruction | Line(s) valid | Lines to compile
- ::testing::Values(std::make_tuple(std::string("OpCapability") , Equals<0> , Range<0, 2>())
- , std::make_tuple(std::string("OpExtension") , Equals<1> , All)
- , std::make_tuple(std::string("OpExtInstImport") , Equals<2> , All)
- , std::make_tuple(std::string("OpMemoryModel") , Equals<3> , Range<1, kRangeEnd>())
- , std::make_tuple(std::string("OpEntryPoint") , Equals<4> , All)
- , std::make_tuple(std::string("OpExecutionMode ") , Range<5, 6>() , All)
- , std::make_tuple(std::string("OpExecutionModeId") , Range<5, 6>() , All)
- , std::make_tuple(std::string("OpSource ") , Range<7, 11>() , Range<8, kRangeEnd>())
- , std::make_tuple(std::string("OpSourceContinued ") , Range<7, 11>() , All)
- , std::make_tuple(std::string("OpSourceExtension ") , Range<7, 11>() , All)
- , std::make_tuple(std::string("%str2 = OpString ") , Range<7, 11>() , All)
- , std::make_tuple(std::string("OpName ") , Range<12, 13>() , All)
- , std::make_tuple(std::string("OpMemberName ") , Range<12, 13>() , All)
- , std::make_tuple(std::string("OpDecorate ") , Range<14, 17>() , All)
- , std::make_tuple(std::string("OpMemberDecorate ") , Range<14, 17>() , All)
- , std::make_tuple(std::string("OpGroupDecorate ") , Range<14, 17>() , Range<17, kRangeEnd>())
- , std::make_tuple(std::string("OpDecorationGroup") , Range<14, 17>() , Range<0, 16>())
- , std::make_tuple(std::string("OpTypeBool") , Range<18, 31>() , All)
- , std::make_tuple(std::string("OpTypeVoid") , Range<18, 31>() , Range<0, 26>())
- , std::make_tuple(std::string("OpTypeFloat") , Range<18, 31>() , Range<0,21>())
- , std::make_tuple(std::string("OpTypeInt") , Range<18, 31>() , Range<0, 21>())
- , std::make_tuple(std::string("OpTypeVector %floatt 4") , Range<18, 31>() , Range<20, 24>())
- , std::make_tuple(std::string("OpTypeMatrix %vec4 4") , Range<18, 31>() , Range<23, kRangeEnd>())
- , std::make_tuple(std::string("OpTypeStruct") , Range<18, 31>() , Range<25, kRangeEnd>())
- , std::make_tuple(std::string("%vfunct = OpTypeFunction"), Range<18, 31>() , Range<21, 31>())
- , std::make_tuple(std::string("OpConstant") , Range<18, 31>() , Range<21, kRangeEnd>())
- , std::make_tuple(std::string("OpLine ") , Range<18, kRangeEnd>() , Range<8, kRangeEnd>())
- , std::make_tuple(std::string("OpNoLine") , Range<18, kRangeEnd>() , All)
- , std::make_tuple(std::string("%fLabel = OpLabel") , Equals<39> , All)
- , std::make_tuple(std::string("OpNop") , Equals<40> , Range<40,kRangeEnd>())
- , std::make_tuple(std::string("OpReturn ; %func2 return") , Equals<41> , All)
- )));
- // clang-format on
- // Creates a new vector which removes the string if the substr is found in the
- // instructions vector and reinserts it in the location specified by order.
- // NOTE: This will not work correctly if there are two instances of substr in
- // instructions
- std::vector<std::string> GenerateCode(std::string substr, int order) {
- std::vector<std::string> code(getInstructions().size());
- std::vector<std::string> inst(1);
- partition_copy(std::begin(getInstructions()), std::end(getInstructions()),
- std::begin(code), std::begin(inst),
- [=](const std::string& str) {
- return std::string::npos == str.find(substr);
- });
- code.insert(std::begin(code) + order, inst.front());
- return code;
- }
- // This test will check the logical layout of a binary by removing each
- // instruction in the pair of the INSTANTIATE_TEST_SUITE_P call and moving it in
- // the SPIRV source formed by combining the vector "instructions".
- TEST_P(ValidateLayout, Layout) {
- int order;
- std::string instruction;
- pred_type pred;
- pred_type test_pred; // Predicate to determine if the test should be build
- std::tuple<std::string, pred_type, pred_type> testCase;
- std::tie(order, testCase) = GetParam();
- std::tie(instruction, pred, test_pred) = testCase;
- // Skip test which break the code generation
- if (test_pred(order)) return;
- std::vector<std::string> code = GenerateCode(instruction, order);
- std::stringstream ss;
- std::copy(std::begin(code), std::end(code),
- std::ostream_iterator<std::string>(ss, "\n"));
- const auto env = SPV_ENV_UNIVERSAL_1_3;
- // printf("code: \n%s\n", ss.str().c_str());
- CompileSuccessfully(ss.str(), env);
- spv_result_t result;
- // clang-format off
- ASSERT_EQ(pred(order), result = ValidateInstructions(env))
- << "Actual: " << spvResultToString(result)
- << "\nExpected: " << spvResultToString(pred(order))
- << "\nOrder: " << order
- << "\nInstruction: " << instruction
- << "\nCode: \n" << ss.str();
- // clang-format on
- }
- TEST_F(ValidateLayout, MemoryModelMissingBeforeEntryPoint) {
- std::string str = R"(
- OpCapability Matrix
- OpExtension "TestExtension"
- %inst = OpExtInstImport "GLSL.std.450"
- OpEntryPoint GLCompute %func ""
- OpExecutionMode %func LocalSize 1 1 1
- )";
- CompileSuccessfully(str);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr(
- "EntryPoint cannot appear before the memory model instruction"));
- }
- TEST_F(ValidateLayout, MemoryModelMissing) {
- char str[] = R"(OpCapability Linkage)";
- CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
- ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Missing required OpMemoryModel instruction"));
- }
- TEST_F(ValidateLayout, MemoryModelSpecifiedTwice) {
- char str[] = R"(
- OpCapability Linkage
- OpCapability Shader
- OpMemoryModel Logical Simple
- OpMemoryModel Logical Simple
- )";
- CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
- ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("OpMemoryModel should only be provided once"));
- }
- TEST_F(ValidateLayout, FunctionDefinitionBeforeDeclarationBad) {
- char str[] = R"(
- OpCapability Shader
- OpMemoryModel Logical GLSL450
- OpDecorate %var Restrict
- %intt = OpTypeInt 32 1
- %voidt = OpTypeVoid
- %vfunct = OpTypeFunction %voidt
- %vifunct = OpTypeFunction %voidt %intt
- %ptrt = OpTypePointer Function %intt
- %func = OpFunction %voidt None %vfunct
- %funcl = OpLabel
- OpNop
- OpReturn
- OpFunctionEnd
- %func2 = OpFunction %voidt None %vifunct ; must appear before definition
- %func2p = OpFunctionParameter %intt
- OpFunctionEnd
- )";
- CompileSuccessfully(str);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr(
- "Function declarations must appear before function definitions."));
- }
- // TODO(umar): Passes but gives incorrect error message. Should be fixed after
- // type checking
- TEST_F(ValidateLayout, LabelBeforeFunctionParameterBad) {
- char str[] = R"(
- OpCapability Shader
- OpMemoryModel Logical GLSL450
- OpDecorate %var Restrict
- %intt = OpTypeInt 32 1
- %voidt = OpTypeVoid
- %vfunct = OpTypeFunction %voidt
- %vifunct = OpTypeFunction %voidt %intt
- %ptrt = OpTypePointer Function %intt
- %func = OpFunction %voidt None %vifunct
- %funcl = OpLabel ; Label appears before function parameter
- %func2p = OpFunctionParameter %intt
- OpNop
- OpReturn
- OpFunctionEnd
- )";
- CompileSuccessfully(str);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Function parameters must only appear immediately "
- "after the function definition"));
- }
- TEST_F(ValidateLayout, FuncParameterNotImmediatlyAfterFuncBad) {
- char str[] = R"(
- OpCapability Shader
- OpMemoryModel Logical GLSL450
- OpDecorate %var Restrict
- %intt = OpTypeInt 32 1
- %voidt = OpTypeVoid
- %vfunct = OpTypeFunction %voidt
- %vifunct = OpTypeFunction %voidt %intt
- %ptrt = OpTypePointer Function %intt
- %func = OpFunction %voidt None %vifunct
- %funcl = OpLabel
- OpNop
- OpBranch %next
- %func2p = OpFunctionParameter %intt ;FunctionParameter appears in a function but not immediately afterwards
- %next = OpLabel
- OpNop
- OpReturn
- OpFunctionEnd
- )";
- CompileSuccessfully(str);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Function parameters must only appear immediately "
- "after the function definition"));
- }
- TEST_F(ValidateLayout, OpUndefCanAppearInTypeDeclarationSection) {
- std::string str = R"(
- OpCapability Kernel
- OpCapability Linkage
- OpMemoryModel Logical OpenCL
- %voidt = OpTypeVoid
- %uintt = OpTypeInt 32 0
- %funct = OpTypeFunction %voidt
- %udef = OpUndef %uintt
- %func = OpFunction %voidt None %funct
- %entry = OpLabel
- OpReturn
- OpFunctionEnd
- )";
- CompileSuccessfully(str);
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
- }
- TEST_F(ValidateLayout, OpUndefCanAppearInBlock) {
- std::string str = R"(
- OpCapability Kernel
- OpCapability Linkage
- OpMemoryModel Logical OpenCL
- %voidt = OpTypeVoid
- %uintt = OpTypeInt 32 0
- %funct = OpTypeFunction %voidt
- %func = OpFunction %voidt None %funct
- %entry = OpLabel
- %udef = OpUndef %uintt
- OpReturn
- OpFunctionEnd
- )";
- CompileSuccessfully(str);
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
- }
- TEST_F(ValidateLayout, MissingFunctionEndForFunctionWithBody) {
- const auto s = R"(
- OpCapability Shader
- OpCapability Linkage
- OpMemoryModel Logical GLSL450
- %void = OpTypeVoid
- %tf = OpTypeFunction %void
- %f = OpFunction %void None %tf
- %l = OpLabel
- OpReturn
- )";
- CompileSuccessfully(s);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(),
- StrEq("Missing OpFunctionEnd at end of module."));
- }
- TEST_F(ValidateLayout, MissingFunctionEndForFunctionPrototype) {
- const auto s = R"(
- OpCapability Shader
- OpCapability Linkage
- OpMemoryModel Logical GLSL450
- %void = OpTypeVoid
- %tf = OpTypeFunction %void
- %f = OpFunction %void None %tf
- )";
- CompileSuccessfully(s);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(),
- StrEq("Missing OpFunctionEnd at end of module."));
- }
- using ValidateOpFunctionParameter = spvtest::ValidateBase<int>;
- TEST_F(ValidateOpFunctionParameter, OpLineBetweenParameters) {
- const auto s = R"(
- OpCapability Shader
- OpCapability Linkage
- OpMemoryModel Logical GLSL450
- %foo_frag = OpString "foo.frag"
- %i32 = OpTypeInt 32 1
- %tf = OpTypeFunction %i32 %i32 %i32
- %c = OpConstant %i32 123
- %f = OpFunction %i32 None %tf
- OpLine %foo_frag 1 1
- %p1 = OpFunctionParameter %i32
- OpNoLine
- %p2 = OpFunctionParameter %i32
- %l = OpLabel
- OpReturnValue %c
- OpFunctionEnd
- )";
- CompileSuccessfully(s);
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
- }
- TEST_F(ValidateOpFunctionParameter, TooManyParameters) {
- const auto s = R"(
- OpCapability Shader
- OpCapability Linkage
- OpMemoryModel Logical GLSL450
- %i32 = OpTypeInt 32 1
- %tf = OpTypeFunction %i32 %i32 %i32
- %c = OpConstant %i32 123
- %f = OpFunction %i32 None %tf
- %p1 = OpFunctionParameter %i32
- %p2 = OpFunctionParameter %i32
- %xp3 = OpFunctionParameter %i32
- %xp4 = OpFunctionParameter %i32
- %xp5 = OpFunctionParameter %i32
- %xp6 = OpFunctionParameter %i32
- %xp7 = OpFunctionParameter %i32
- %l = OpLabel
- OpReturnValue %c
- OpFunctionEnd
- )";
- CompileSuccessfully(s);
- ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions());
- }
- using ValidateEntryPoint = spvtest::ValidateBase<bool>;
- // Tests that not having OpEntryPoint causes an error.
- TEST_F(ValidateEntryPoint, NoEntryPointBad) {
- std::string spirv = R"(
- OpCapability Shader
- OpMemoryModel Logical GLSL450)";
- CompileSuccessfully(spirv);
- EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("No OpEntryPoint instruction was found. This is only "
- "allowed if the Linkage capability is being used."));
- }
- // Invalid. A function may not be a target of both OpEntryPoint and
- // OpFunctionCall.
- TEST_F(ValidateEntryPoint, FunctionIsTargetOfEntryPointAndFunctionCallBad) {
- std::string spirv = R"(
- OpCapability Shader
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %foo "foo"
- OpExecutionMode %foo OriginUpperLeft
- %voidt = OpTypeVoid
- %funct = OpTypeFunction %voidt
- %foo = OpFunction %voidt None %funct
- %entry = OpLabel
- %recurse = OpFunctionCall %voidt %foo
- OpReturn
- OpFunctionEnd
- )";
- CompileSuccessfully(spirv);
- EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions());
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("A function (1) may not be targeted by both an OpEntryPoint "
- "instruction and an OpFunctionCall instruction."));
- }
- // Invalid. Must be within a function to make a function call.
- TEST_F(ValidateEntryPoint, FunctionCallOutsideFunctionBody) {
- std::string spirv = R"(
- OpCapability Shader
- %1 = OpExtInstImport "GLSL.std.450"
- OpMemoryModel Logical GLSL450
- OpName %variableName "variableName"
- %34 = OpFunctionCall %variableName %1
- )";
- CompileSuccessfully(spirv);
- EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions());
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("FunctionCall must happen within a function body."));
- }
- // Valid. Module with a function but no entry point is valid when Linkage
- // Capability is used.
- TEST_F(ValidateEntryPoint, NoEntryPointWithLinkageCapGood) {
- std::string spirv = R"(
- OpCapability Shader
- OpCapability Linkage
- OpMemoryModel Logical GLSL450
- %voidt = OpTypeVoid
- %funct = OpTypeFunction %voidt
- %foo = OpFunction %voidt None %funct
- %entry = OpLabel
- OpReturn
- OpFunctionEnd
- )";
- CompileSuccessfully(spirv);
- EXPECT_EQ(SPV_SUCCESS, ValidateInstructions());
- }
- TEST_F(ValidateLayout, ModuleProcessedInvalidIn10) {
- char str[] = R"(
- OpCapability Shader
- OpCapability Linkage
- OpMemoryModel Logical GLSL450
- OpName %void "void"
- OpModuleProcessed "this is ok in 1.1 and later"
- %void = OpTypeVoid
- )";
- CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
- ASSERT_EQ(SPV_ERROR_WRONG_VERSION,
- ValidateInstructions(SPV_ENV_UNIVERSAL_1_0));
- // In a 1.0 environment the version check fails.
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Invalid SPIR-V binary version 1.1 for target "
- "environment SPIR-V 1.0."));
- }
- TEST_F(ValidateLayout, ModuleProcessedValidIn11) {
- char str[] = R"(
- OpCapability Shader
- OpCapability Linkage
- OpMemoryModel Logical GLSL450
- OpName %void "void"
- OpModuleProcessed "this is ok in 1.1 and later"
- %void = OpTypeVoid
- )";
- CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
- EXPECT_THAT(getDiagnosticString(), Eq(""));
- }
- TEST_F(ValidateLayout, LayoutOrderMixedUp) {
- char str[] = R"(
- OpCapability Shader
- OpCapability Linkage
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %fragmentFloat "fragmentFloat"
- OpExecutionMode %fragmentFloat OriginUpperLeft
- OpEntryPoint Fragment %fragmentUint "fragmentUint"
- OpExecutionMode %fragmentUint OriginUpperLeft
- )";
- CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
- ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
- // By the mechanics of the validator, we assume ModuleProcessed is in the
- // right spot, but then that OpName is in the wrong spot.
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("EntryPoint is in an invalid layout section"));
- }
- TEST_F(ValidateLayout, ModuleProcessedBeforeLastNameIsTooEarly) {
- char str[] = R"(
- OpCapability Shader
- OpCapability Linkage
- OpMemoryModel Logical GLSL450
- OpModuleProcessed "this is too early"
- OpName %void "void"
- %void = OpTypeVoid
- )";
- CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
- ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
- // By the mechanics of the validator, we assume ModuleProcessed is in the
- // right spot, but then that OpName is in the wrong spot.
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("Name is in an invalid layout section"));
- }
- TEST_F(ValidateLayout, ModuleProcessedInvalidAfterFirstAnnotation) {
- char str[] = R"(
- OpCapability Shader
- OpCapability Linkage
- OpMemoryModel Logical GLSL450
- OpDecorate %void Volatile ; this is bogus, but keeps the example short
- OpModuleProcessed "this is too late"
- %void = OpTypeVoid
- )";
- CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
- ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
- EXPECT_THAT(getDiagnosticString(),
- HasSubstr("ModuleProcessed is in an invalid layout section"));
- }
- TEST_F(ValidateLayout, ModuleProcessedInvalidInFunctionBeforeLabel) {
- char str[] = R"(
- OpCapability Shader
- OpMemoryModel Logical GLSL450
- OpEntryPoint GLCompute %main "main"
- %void = OpTypeVoid
- %voidfn = OpTypeFunction %void
- %main = OpFunction %void None %voidfn
- OpModuleProcessed "this is too late, in function before label"
- %entry = OpLabel
- OpReturn
- OpFunctionEnd
- )";
- CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
- ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("ModuleProcessed cannot appear in a function declaration"));
- }
- TEST_F(ValidateLayout, ModuleProcessedInvalidInBasicBlock) {
- char str[] = R"(
- OpCapability Shader
- OpMemoryModel Logical GLSL450
- OpEntryPoint GLCompute %main "main"
- %void = OpTypeVoid
- %voidfn = OpTypeFunction %void
- %main = OpFunction %void None %voidfn
- %entry = OpLabel
- OpModuleProcessed "this is too late, in basic block"
- OpReturn
- OpFunctionEnd
- )";
- CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
- ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("ModuleProcessed cannot appear in a function declaration"));
- }
- // TODO(umar): Test optional instructions
- TEST_F(ValidateLayout, ValidNVBindlessTexturelayout) {
- std::string str = R"(
- OpCapability Shader
- OpCapability BindlessTextureNV
- OpExtension "SPV_NV_bindless_texture"
- OpMemoryModel Logical GLSL450
- OpSamplerImageAddressingModeNV 64
- OpEntryPoint GLCompute %func "main"
- %voidt = OpTypeVoid
- %uintt = OpTypeInt 32 0
- %funct = OpTypeFunction %voidt
- %func = OpFunction %voidt None %funct
- %entry = OpLabel
- %udef = OpUndef %uintt
- OpReturn
- OpFunctionEnd
- )";
- CompileSuccessfully(str);
- ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
- }
- TEST_F(ValidateLayout, InvalidValidNVBindlessTexturelayout) {
- std::string str = R"(
- OpCapability Shader
- OpCapability BindlessTextureNV
- OpExtension "SPV_NV_bindless_texture"
- OpMemoryModel Logical GLSL450
- OpEntryPoint GLCompute %func "main"
- OpSamplerImageAddressingModeNV 64
- %voidt = OpTypeVoid
- %uintt = OpTypeInt 32 0
- %funct = OpTypeFunction %voidt
- %func = OpFunction %voidt None %funct
- %entry = OpLabel
- %udef = OpUndef %uintt
- OpReturn
- OpFunctionEnd
- )";
- CompileSuccessfully(str);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
- ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr(
- "SamplerImageAddressingModeNV is in an invalid layout section"));
- }
- TEST_F(ValidateLayout, MissingNVBindlessAddressModeFromLayout) {
- std::string str = R"(
- OpCapability Shader
- OpCapability BindlessTextureNV
- OpExtension "SPV_NV_bindless_texture"
- OpMemoryModel Logical GLSL450
- OpEntryPoint GLCompute %func "main"
- %voidt = OpTypeVoid
- %uintt = OpTypeInt 32 0
- %funct = OpTypeFunction %voidt
- %func = OpFunction %voidt None %funct
- %entry = OpLabel
- %udef = OpUndef %uintt
- OpReturn
- OpFunctionEnd
- )";
- CompileSuccessfully(str);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
- ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("Missing required OpSamplerImageAddressingModeNV instruction"));
- }
- TEST_F(ValidateLayout, NVBindlessAddressModeFromLayoutSpecifiedTwice) {
- std::string str = R"(
- OpCapability Shader
- OpCapability BindlessTextureNV
- OpExtension "SPV_NV_bindless_texture"
- OpMemoryModel Logical GLSL450
- OpSamplerImageAddressingModeNV 64
- OpSamplerImageAddressingModeNV 64
- )";
- CompileSuccessfully(str);
- ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT,
- ValidateInstructions(SPV_ENV_UNIVERSAL_1_3));
- EXPECT_THAT(
- getDiagnosticString(),
- HasSubstr("OpSamplerImageAddressingModeNV should only be provided once"));
- }
- } // namespace
- } // namespace val
- } // namespace spvtools
|