1fd4e5da5Sopenharmony_ci// Copyright (c) 2015-2016 The Khronos Group Inc. 2fd4e5da5Sopenharmony_ci// 3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License. 5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at 6fd4e5da5Sopenharmony_ci// 7fd4e5da5Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 8fd4e5da5Sopenharmony_ci// 9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and 13fd4e5da5Sopenharmony_ci// limitations under the License. 14fd4e5da5Sopenharmony_ci 15fd4e5da5Sopenharmony_ci// Validation tests for Logical Layout 16fd4e5da5Sopenharmony_ci 17fd4e5da5Sopenharmony_ci#include <functional> 18fd4e5da5Sopenharmony_ci#include <string> 19fd4e5da5Sopenharmony_ci#include <tuple> 20fd4e5da5Sopenharmony_ci#include <utility> 21fd4e5da5Sopenharmony_ci#include <vector> 22fd4e5da5Sopenharmony_ci 23fd4e5da5Sopenharmony_ci#include "gmock/gmock.h" 24fd4e5da5Sopenharmony_ci#include "source/diagnostic.h" 25fd4e5da5Sopenharmony_ci#include "test/unit_spirv.h" 26fd4e5da5Sopenharmony_ci#include "test/val/val_fixtures.h" 27fd4e5da5Sopenharmony_ci 28fd4e5da5Sopenharmony_cinamespace spvtools { 29fd4e5da5Sopenharmony_cinamespace val { 30fd4e5da5Sopenharmony_cinamespace { 31fd4e5da5Sopenharmony_ci 32fd4e5da5Sopenharmony_ciusing ::testing::Eq; 33fd4e5da5Sopenharmony_ciusing ::testing::HasSubstr; 34fd4e5da5Sopenharmony_ciusing ::testing::StrEq; 35fd4e5da5Sopenharmony_ci 36fd4e5da5Sopenharmony_ciusing pred_type = std::function<spv_result_t(int)>; 37fd4e5da5Sopenharmony_ciusing ValidateLayout = spvtest::ValidateBase< 38fd4e5da5Sopenharmony_ci std::tuple<int, std::tuple<std::string, pred_type, pred_type>>>; 39fd4e5da5Sopenharmony_ci 40fd4e5da5Sopenharmony_ci// returns true if order is equal to VAL 41fd4e5da5Sopenharmony_citemplate <int VAL, spv_result_t RET = SPV_ERROR_INVALID_LAYOUT> 42fd4e5da5Sopenharmony_cispv_result_t Equals(int order) { 43fd4e5da5Sopenharmony_ci return order == VAL ? SPV_SUCCESS : RET; 44fd4e5da5Sopenharmony_ci} 45fd4e5da5Sopenharmony_ci 46fd4e5da5Sopenharmony_ci// returns true if order is between MIN and MAX(inclusive) 47fd4e5da5Sopenharmony_citemplate <int MIN, int MAX, spv_result_t RET = SPV_ERROR_INVALID_LAYOUT> 48fd4e5da5Sopenharmony_cistruct Range { 49fd4e5da5Sopenharmony_ci explicit Range(bool inverse = false) : inverse_(inverse) {} 50fd4e5da5Sopenharmony_ci spv_result_t operator()(int order) { 51fd4e5da5Sopenharmony_ci return (inverse_ ^ (order >= MIN && order <= MAX)) ? SPV_SUCCESS : RET; 52fd4e5da5Sopenharmony_ci } 53fd4e5da5Sopenharmony_ci 54fd4e5da5Sopenharmony_ci private: 55fd4e5da5Sopenharmony_ci bool inverse_; 56fd4e5da5Sopenharmony_ci}; 57fd4e5da5Sopenharmony_ci 58fd4e5da5Sopenharmony_ci// SPIRV source used to test the logical layout 59fd4e5da5Sopenharmony_ciconst std::vector<std::string>& getInstructions() { 60fd4e5da5Sopenharmony_ci // clang-format off 61fd4e5da5Sopenharmony_ci static const std::vector<std::string> instructions = { 62fd4e5da5Sopenharmony_ci "OpCapability Shader", 63fd4e5da5Sopenharmony_ci "OpExtension \"TestExtension\"", 64fd4e5da5Sopenharmony_ci "%inst = OpExtInstImport \"GLSL.std.450\"", 65fd4e5da5Sopenharmony_ci "OpMemoryModel Logical GLSL450", 66fd4e5da5Sopenharmony_ci "OpEntryPoint GLCompute %func \"\"", 67fd4e5da5Sopenharmony_ci "OpExecutionMode %func LocalSize 1 1 1", 68fd4e5da5Sopenharmony_ci "OpExecutionModeId %func LocalSizeId %one %one %one", 69fd4e5da5Sopenharmony_ci "%str = OpString \"Test String\"", 70fd4e5da5Sopenharmony_ci "%str2 = OpString \"blabla\"", 71fd4e5da5Sopenharmony_ci "OpSource GLSL 450 %str \"uniform vec3 var = vec3(4.0);\"", 72fd4e5da5Sopenharmony_ci "OpSourceContinued \"void main(){return;}\"", 73fd4e5da5Sopenharmony_ci "OpSourceExtension \"Test extension\"", 74fd4e5da5Sopenharmony_ci "OpName %func \"MyFunction\"", 75fd4e5da5Sopenharmony_ci "OpMemberName %struct 1 \"my_member\"", 76fd4e5da5Sopenharmony_ci "OpDecorate %dgrp RowMajor", 77fd4e5da5Sopenharmony_ci "OpMemberDecorate %struct 1 RowMajor", 78fd4e5da5Sopenharmony_ci "%dgrp = OpDecorationGroup", 79fd4e5da5Sopenharmony_ci "OpGroupDecorate %dgrp %mat33 %mat44", 80fd4e5da5Sopenharmony_ci "%intt = OpTypeInt 32 1", 81fd4e5da5Sopenharmony_ci "%floatt = OpTypeFloat 32", 82fd4e5da5Sopenharmony_ci "%voidt = OpTypeVoid", 83fd4e5da5Sopenharmony_ci "%boolt = OpTypeBool", 84fd4e5da5Sopenharmony_ci "%vec4 = OpTypeVector %floatt 4", 85fd4e5da5Sopenharmony_ci "%vec3 = OpTypeVector %floatt 3", 86fd4e5da5Sopenharmony_ci "%mat33 = OpTypeMatrix %vec3 3", 87fd4e5da5Sopenharmony_ci "%mat44 = OpTypeMatrix %vec4 4", 88fd4e5da5Sopenharmony_ci "%struct = OpTypeStruct %intt %mat33", 89fd4e5da5Sopenharmony_ci "%vfunct = OpTypeFunction %voidt", 90fd4e5da5Sopenharmony_ci "%viifunct = OpTypeFunction %voidt %intt %intt", 91fd4e5da5Sopenharmony_ci "%one = OpConstant %intt 1", 92fd4e5da5Sopenharmony_ci // TODO(umar): OpConstant fails because the type is not defined 93fd4e5da5Sopenharmony_ci // TODO(umar): OpGroupMemberDecorate 94fd4e5da5Sopenharmony_ci "OpLine %str 3 4", 95fd4e5da5Sopenharmony_ci "OpNoLine", 96fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %vfunct", 97fd4e5da5Sopenharmony_ci "%l = OpLabel", 98fd4e5da5Sopenharmony_ci "OpReturn ; %func return", 99fd4e5da5Sopenharmony_ci "OpFunctionEnd ; %func end", 100fd4e5da5Sopenharmony_ci "%func2 = OpFunction %voidt None %viifunct", 101fd4e5da5Sopenharmony_ci "%funcp1 = OpFunctionParameter %intt", 102fd4e5da5Sopenharmony_ci "%funcp2 = OpFunctionParameter %intt", 103fd4e5da5Sopenharmony_ci "%fLabel = OpLabel", 104fd4e5da5Sopenharmony_ci "OpNop", 105fd4e5da5Sopenharmony_ci "OpReturn ; %func2 return", 106fd4e5da5Sopenharmony_ci "OpFunctionEnd" 107fd4e5da5Sopenharmony_ci }; 108fd4e5da5Sopenharmony_ci return instructions; 109fd4e5da5Sopenharmony_ci} 110fd4e5da5Sopenharmony_ci 111fd4e5da5Sopenharmony_cistatic const int kRangeEnd = 1000; 112fd4e5da5Sopenharmony_cipred_type All = Range<0, kRangeEnd>(); 113fd4e5da5Sopenharmony_ci 114fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P(InstructionsOrder, 115fd4e5da5Sopenharmony_ci ValidateLayout, 116fd4e5da5Sopenharmony_ci ::testing::Combine(::testing::Range((int)0, (int)getInstructions().size()), 117fd4e5da5Sopenharmony_ci // Note: Because of ID dependencies between instructions, some instructions 118fd4e5da5Sopenharmony_ci // are not free to be placed anywhere without triggering an non-layout 119fd4e5da5Sopenharmony_ci // validation error. Therefore, "Lines to compile" for some instructions 120fd4e5da5Sopenharmony_ci // are not "All" in the below. 121fd4e5da5Sopenharmony_ci // 122fd4e5da5Sopenharmony_ci // | Instruction | Line(s) valid | Lines to compile 123fd4e5da5Sopenharmony_ci ::testing::Values(std::make_tuple(std::string("OpCapability") , Equals<0> , Range<0, 2>()) 124fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpExtension") , Equals<1> , All) 125fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpExtInstImport") , Equals<2> , All) 126fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpMemoryModel") , Equals<3> , Range<1, kRangeEnd>()) 127fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpEntryPoint") , Equals<4> , All) 128fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpExecutionMode ") , Range<5, 6>() , All) 129fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpExecutionModeId") , Range<5, 6>() , All) 130fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpSource ") , Range<7, 11>() , Range<8, kRangeEnd>()) 131fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpSourceContinued ") , Range<7, 11>() , All) 132fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpSourceExtension ") , Range<7, 11>() , All) 133fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("%str2 = OpString ") , Range<7, 11>() , All) 134fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpName ") , Range<12, 13>() , All) 135fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpMemberName ") , Range<12, 13>() , All) 136fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpDecorate ") , Range<14, 17>() , All) 137fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpMemberDecorate ") , Range<14, 17>() , All) 138fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpGroupDecorate ") , Range<14, 17>() , Range<17, kRangeEnd>()) 139fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpDecorationGroup") , Range<14, 17>() , Range<0, 16>()) 140fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpTypeBool") , Range<18, 31>() , All) 141fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpTypeVoid") , Range<18, 31>() , Range<0, 26>()) 142fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpTypeFloat") , Range<18, 31>() , Range<0,21>()) 143fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpTypeInt") , Range<18, 31>() , Range<0, 21>()) 144fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpTypeVector %floatt 4") , Range<18, 31>() , Range<20, 24>()) 145fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpTypeMatrix %vec4 4") , Range<18, 31>() , Range<23, kRangeEnd>()) 146fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpTypeStruct") , Range<18, 31>() , Range<25, kRangeEnd>()) 147fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("%vfunct = OpTypeFunction"), Range<18, 31>() , Range<21, 31>()) 148fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpConstant") , Range<18, 31>() , Range<21, kRangeEnd>()) 149fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpLine ") , Range<18, kRangeEnd>() , Range<8, kRangeEnd>()) 150fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpNoLine") , Range<18, kRangeEnd>() , All) 151fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("%fLabel = OpLabel") , Equals<39> , All) 152fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpNop") , Equals<40> , Range<40,kRangeEnd>()) 153fd4e5da5Sopenharmony_ci , std::make_tuple(std::string("OpReturn ; %func2 return") , Equals<41> , All) 154fd4e5da5Sopenharmony_ci ))); 155fd4e5da5Sopenharmony_ci// clang-format on 156fd4e5da5Sopenharmony_ci 157fd4e5da5Sopenharmony_ci// Creates a new vector which removes the string if the substr is found in the 158fd4e5da5Sopenharmony_ci// instructions vector and reinserts it in the location specified by order. 159fd4e5da5Sopenharmony_ci// NOTE: This will not work correctly if there are two instances of substr in 160fd4e5da5Sopenharmony_ci// instructions 161fd4e5da5Sopenharmony_cistd::vector<std::string> GenerateCode(std::string substr, int order) { 162fd4e5da5Sopenharmony_ci std::vector<std::string> code(getInstructions().size()); 163fd4e5da5Sopenharmony_ci std::vector<std::string> inst(1); 164fd4e5da5Sopenharmony_ci partition_copy(std::begin(getInstructions()), std::end(getInstructions()), 165fd4e5da5Sopenharmony_ci std::begin(code), std::begin(inst), 166fd4e5da5Sopenharmony_ci [=](const std::string& str) { 167fd4e5da5Sopenharmony_ci return std::string::npos == str.find(substr); 168fd4e5da5Sopenharmony_ci }); 169fd4e5da5Sopenharmony_ci 170fd4e5da5Sopenharmony_ci code.insert(std::begin(code) + order, inst.front()); 171fd4e5da5Sopenharmony_ci return code; 172fd4e5da5Sopenharmony_ci} 173fd4e5da5Sopenharmony_ci 174fd4e5da5Sopenharmony_ci// This test will check the logical layout of a binary by removing each 175fd4e5da5Sopenharmony_ci// instruction in the pair of the INSTANTIATE_TEST_SUITE_P call and moving it in 176fd4e5da5Sopenharmony_ci// the SPIRV source formed by combining the vector "instructions". 177fd4e5da5Sopenharmony_ciTEST_P(ValidateLayout, Layout) { 178fd4e5da5Sopenharmony_ci int order; 179fd4e5da5Sopenharmony_ci std::string instruction; 180fd4e5da5Sopenharmony_ci pred_type pred; 181fd4e5da5Sopenharmony_ci pred_type test_pred; // Predicate to determine if the test should be build 182fd4e5da5Sopenharmony_ci std::tuple<std::string, pred_type, pred_type> testCase; 183fd4e5da5Sopenharmony_ci 184fd4e5da5Sopenharmony_ci std::tie(order, testCase) = GetParam(); 185fd4e5da5Sopenharmony_ci std::tie(instruction, pred, test_pred) = testCase; 186fd4e5da5Sopenharmony_ci 187fd4e5da5Sopenharmony_ci // Skip test which break the code generation 188fd4e5da5Sopenharmony_ci if (test_pred(order)) return; 189fd4e5da5Sopenharmony_ci 190fd4e5da5Sopenharmony_ci std::vector<std::string> code = GenerateCode(instruction, order); 191fd4e5da5Sopenharmony_ci 192fd4e5da5Sopenharmony_ci std::stringstream ss; 193fd4e5da5Sopenharmony_ci std::copy(std::begin(code), std::end(code), 194fd4e5da5Sopenharmony_ci std::ostream_iterator<std::string>(ss, "\n")); 195fd4e5da5Sopenharmony_ci 196fd4e5da5Sopenharmony_ci const auto env = SPV_ENV_UNIVERSAL_1_3; 197fd4e5da5Sopenharmony_ci // printf("code: \n%s\n", ss.str().c_str()); 198fd4e5da5Sopenharmony_ci CompileSuccessfully(ss.str(), env); 199fd4e5da5Sopenharmony_ci spv_result_t result; 200fd4e5da5Sopenharmony_ci // clang-format off 201fd4e5da5Sopenharmony_ci ASSERT_EQ(pred(order), result = ValidateInstructions(env)) 202fd4e5da5Sopenharmony_ci << "Actual: " << spvResultToString(result) 203fd4e5da5Sopenharmony_ci << "\nExpected: " << spvResultToString(pred(order)) 204fd4e5da5Sopenharmony_ci << "\nOrder: " << order 205fd4e5da5Sopenharmony_ci << "\nInstruction: " << instruction 206fd4e5da5Sopenharmony_ci << "\nCode: \n" << ss.str(); 207fd4e5da5Sopenharmony_ci // clang-format on 208fd4e5da5Sopenharmony_ci} 209fd4e5da5Sopenharmony_ci 210fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, MemoryModelMissingBeforeEntryPoint) { 211fd4e5da5Sopenharmony_ci std::string str = R"( 212fd4e5da5Sopenharmony_ci OpCapability Matrix 213fd4e5da5Sopenharmony_ci OpExtension "TestExtension" 214fd4e5da5Sopenharmony_ci %inst = OpExtInstImport "GLSL.std.450" 215fd4e5da5Sopenharmony_ci OpEntryPoint GLCompute %func "" 216fd4e5da5Sopenharmony_ci OpExecutionMode %func LocalSize 1 1 1 217fd4e5da5Sopenharmony_ci )"; 218fd4e5da5Sopenharmony_ci 219fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 220fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); 221fd4e5da5Sopenharmony_ci EXPECT_THAT( 222fd4e5da5Sopenharmony_ci getDiagnosticString(), 223fd4e5da5Sopenharmony_ci HasSubstr( 224fd4e5da5Sopenharmony_ci "EntryPoint cannot appear before the memory model instruction")); 225fd4e5da5Sopenharmony_ci} 226fd4e5da5Sopenharmony_ci 227fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, MemoryModelMissing) { 228fd4e5da5Sopenharmony_ci char str[] = R"(OpCapability Linkage)"; 229fd4e5da5Sopenharmony_ci CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1); 230fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, 231fd4e5da5Sopenharmony_ci ValidateInstructions(SPV_ENV_UNIVERSAL_1_1)); 232fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 233fd4e5da5Sopenharmony_ci HasSubstr("Missing required OpMemoryModel instruction")); 234fd4e5da5Sopenharmony_ci} 235fd4e5da5Sopenharmony_ci 236fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, MemoryModelSpecifiedTwice) { 237fd4e5da5Sopenharmony_ci char str[] = R"( 238fd4e5da5Sopenharmony_ci OpCapability Linkage 239fd4e5da5Sopenharmony_ci OpCapability Shader 240fd4e5da5Sopenharmony_ci OpMemoryModel Logical Simple 241fd4e5da5Sopenharmony_ci OpMemoryModel Logical Simple 242fd4e5da5Sopenharmony_ci )"; 243fd4e5da5Sopenharmony_ci 244fd4e5da5Sopenharmony_ci CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1); 245fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, 246fd4e5da5Sopenharmony_ci ValidateInstructions(SPV_ENV_UNIVERSAL_1_1)); 247fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 248fd4e5da5Sopenharmony_ci HasSubstr("OpMemoryModel should only be provided once")); 249fd4e5da5Sopenharmony_ci} 250fd4e5da5Sopenharmony_ci 251fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, FunctionDefinitionBeforeDeclarationBad) { 252fd4e5da5Sopenharmony_ci char str[] = R"( 253fd4e5da5Sopenharmony_ci OpCapability Shader 254fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 255fd4e5da5Sopenharmony_ci OpDecorate %var Restrict 256fd4e5da5Sopenharmony_ci%intt = OpTypeInt 32 1 257fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid 258fd4e5da5Sopenharmony_ci%vfunct = OpTypeFunction %voidt 259fd4e5da5Sopenharmony_ci%vifunct = OpTypeFunction %voidt %intt 260fd4e5da5Sopenharmony_ci%ptrt = OpTypePointer Function %intt 261fd4e5da5Sopenharmony_ci%func = OpFunction %voidt None %vfunct 262fd4e5da5Sopenharmony_ci%funcl = OpLabel 263fd4e5da5Sopenharmony_ci OpNop 264fd4e5da5Sopenharmony_ci OpReturn 265fd4e5da5Sopenharmony_ci OpFunctionEnd 266fd4e5da5Sopenharmony_ci%func2 = OpFunction %voidt None %vifunct ; must appear before definition 267fd4e5da5Sopenharmony_ci%func2p = OpFunctionParameter %intt 268fd4e5da5Sopenharmony_ci OpFunctionEnd 269fd4e5da5Sopenharmony_ci)"; 270fd4e5da5Sopenharmony_ci 271fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 272fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); 273fd4e5da5Sopenharmony_ci EXPECT_THAT( 274fd4e5da5Sopenharmony_ci getDiagnosticString(), 275fd4e5da5Sopenharmony_ci HasSubstr( 276fd4e5da5Sopenharmony_ci "Function declarations must appear before function definitions.")); 277fd4e5da5Sopenharmony_ci} 278fd4e5da5Sopenharmony_ci 279fd4e5da5Sopenharmony_ci// TODO(umar): Passes but gives incorrect error message. Should be fixed after 280fd4e5da5Sopenharmony_ci// type checking 281fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, LabelBeforeFunctionParameterBad) { 282fd4e5da5Sopenharmony_ci char str[] = R"( 283fd4e5da5Sopenharmony_ci OpCapability Shader 284fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 285fd4e5da5Sopenharmony_ci OpDecorate %var Restrict 286fd4e5da5Sopenharmony_ci%intt = OpTypeInt 32 1 287fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid 288fd4e5da5Sopenharmony_ci%vfunct = OpTypeFunction %voidt 289fd4e5da5Sopenharmony_ci%vifunct = OpTypeFunction %voidt %intt 290fd4e5da5Sopenharmony_ci%ptrt = OpTypePointer Function %intt 291fd4e5da5Sopenharmony_ci%func = OpFunction %voidt None %vifunct 292fd4e5da5Sopenharmony_ci%funcl = OpLabel ; Label appears before function parameter 293fd4e5da5Sopenharmony_ci%func2p = OpFunctionParameter %intt 294fd4e5da5Sopenharmony_ci OpNop 295fd4e5da5Sopenharmony_ci OpReturn 296fd4e5da5Sopenharmony_ci OpFunctionEnd 297fd4e5da5Sopenharmony_ci)"; 298fd4e5da5Sopenharmony_ci 299fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 300fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); 301fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 302fd4e5da5Sopenharmony_ci HasSubstr("Function parameters must only appear immediately " 303fd4e5da5Sopenharmony_ci "after the function definition")); 304fd4e5da5Sopenharmony_ci} 305fd4e5da5Sopenharmony_ci 306fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, FuncParameterNotImmediatlyAfterFuncBad) { 307fd4e5da5Sopenharmony_ci char str[] = R"( 308fd4e5da5Sopenharmony_ci OpCapability Shader 309fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 310fd4e5da5Sopenharmony_ci OpDecorate %var Restrict 311fd4e5da5Sopenharmony_ci%intt = OpTypeInt 32 1 312fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid 313fd4e5da5Sopenharmony_ci%vfunct = OpTypeFunction %voidt 314fd4e5da5Sopenharmony_ci%vifunct = OpTypeFunction %voidt %intt 315fd4e5da5Sopenharmony_ci%ptrt = OpTypePointer Function %intt 316fd4e5da5Sopenharmony_ci%func = OpFunction %voidt None %vifunct 317fd4e5da5Sopenharmony_ci%funcl = OpLabel 318fd4e5da5Sopenharmony_ci OpNop 319fd4e5da5Sopenharmony_ci OpBranch %next 320fd4e5da5Sopenharmony_ci%func2p = OpFunctionParameter %intt ;FunctionParameter appears in a function but not immediately afterwards 321fd4e5da5Sopenharmony_ci%next = OpLabel 322fd4e5da5Sopenharmony_ci OpNop 323fd4e5da5Sopenharmony_ci OpReturn 324fd4e5da5Sopenharmony_ci OpFunctionEnd 325fd4e5da5Sopenharmony_ci)"; 326fd4e5da5Sopenharmony_ci 327fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 328fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); 329fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 330fd4e5da5Sopenharmony_ci HasSubstr("Function parameters must only appear immediately " 331fd4e5da5Sopenharmony_ci "after the function definition")); 332fd4e5da5Sopenharmony_ci} 333fd4e5da5Sopenharmony_ci 334fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, OpUndefCanAppearInTypeDeclarationSection) { 335fd4e5da5Sopenharmony_ci std::string str = R"( 336fd4e5da5Sopenharmony_ci OpCapability Kernel 337fd4e5da5Sopenharmony_ci OpCapability Linkage 338fd4e5da5Sopenharmony_ci OpMemoryModel Logical OpenCL 339fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid 340fd4e5da5Sopenharmony_ci%uintt = OpTypeInt 32 0 341fd4e5da5Sopenharmony_ci%funct = OpTypeFunction %voidt 342fd4e5da5Sopenharmony_ci%udef = OpUndef %uintt 343fd4e5da5Sopenharmony_ci%func = OpFunction %voidt None %funct 344fd4e5da5Sopenharmony_ci%entry = OpLabel 345fd4e5da5Sopenharmony_ci OpReturn 346fd4e5da5Sopenharmony_ci OpFunctionEnd 347fd4e5da5Sopenharmony_ci)"; 348fd4e5da5Sopenharmony_ci 349fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 350fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 351fd4e5da5Sopenharmony_ci} 352fd4e5da5Sopenharmony_ci 353fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, OpUndefCanAppearInBlock) { 354fd4e5da5Sopenharmony_ci std::string str = R"( 355fd4e5da5Sopenharmony_ci OpCapability Kernel 356fd4e5da5Sopenharmony_ci OpCapability Linkage 357fd4e5da5Sopenharmony_ci OpMemoryModel Logical OpenCL 358fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid 359fd4e5da5Sopenharmony_ci%uintt = OpTypeInt 32 0 360fd4e5da5Sopenharmony_ci%funct = OpTypeFunction %voidt 361fd4e5da5Sopenharmony_ci%func = OpFunction %voidt None %funct 362fd4e5da5Sopenharmony_ci%entry = OpLabel 363fd4e5da5Sopenharmony_ci%udef = OpUndef %uintt 364fd4e5da5Sopenharmony_ci OpReturn 365fd4e5da5Sopenharmony_ci OpFunctionEnd 366fd4e5da5Sopenharmony_ci)"; 367fd4e5da5Sopenharmony_ci 368fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 369fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 370fd4e5da5Sopenharmony_ci} 371fd4e5da5Sopenharmony_ci 372fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, MissingFunctionEndForFunctionWithBody) { 373fd4e5da5Sopenharmony_ci const auto s = R"( 374fd4e5da5Sopenharmony_ciOpCapability Shader 375fd4e5da5Sopenharmony_ciOpCapability Linkage 376fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 377fd4e5da5Sopenharmony_ci%void = OpTypeVoid 378fd4e5da5Sopenharmony_ci%tf = OpTypeFunction %void 379fd4e5da5Sopenharmony_ci%f = OpFunction %void None %tf 380fd4e5da5Sopenharmony_ci%l = OpLabel 381fd4e5da5Sopenharmony_ciOpReturn 382fd4e5da5Sopenharmony_ci)"; 383fd4e5da5Sopenharmony_ci 384fd4e5da5Sopenharmony_ci CompileSuccessfully(s); 385fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); 386fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 387fd4e5da5Sopenharmony_ci StrEq("Missing OpFunctionEnd at end of module.")); 388fd4e5da5Sopenharmony_ci} 389fd4e5da5Sopenharmony_ci 390fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, MissingFunctionEndForFunctionPrototype) { 391fd4e5da5Sopenharmony_ci const auto s = R"( 392fd4e5da5Sopenharmony_ciOpCapability Shader 393fd4e5da5Sopenharmony_ciOpCapability Linkage 394fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 395fd4e5da5Sopenharmony_ci%void = OpTypeVoid 396fd4e5da5Sopenharmony_ci%tf = OpTypeFunction %void 397fd4e5da5Sopenharmony_ci%f = OpFunction %void None %tf 398fd4e5da5Sopenharmony_ci)"; 399fd4e5da5Sopenharmony_ci 400fd4e5da5Sopenharmony_ci CompileSuccessfully(s); 401fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); 402fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 403fd4e5da5Sopenharmony_ci StrEq("Missing OpFunctionEnd at end of module.")); 404fd4e5da5Sopenharmony_ci} 405fd4e5da5Sopenharmony_ci 406fd4e5da5Sopenharmony_ciusing ValidateOpFunctionParameter = spvtest::ValidateBase<int>; 407fd4e5da5Sopenharmony_ci 408fd4e5da5Sopenharmony_ciTEST_F(ValidateOpFunctionParameter, OpLineBetweenParameters) { 409fd4e5da5Sopenharmony_ci const auto s = R"( 410fd4e5da5Sopenharmony_ciOpCapability Shader 411fd4e5da5Sopenharmony_ciOpCapability Linkage 412fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 413fd4e5da5Sopenharmony_ci%foo_frag = OpString "foo.frag" 414fd4e5da5Sopenharmony_ci%i32 = OpTypeInt 32 1 415fd4e5da5Sopenharmony_ci%tf = OpTypeFunction %i32 %i32 %i32 416fd4e5da5Sopenharmony_ci%c = OpConstant %i32 123 417fd4e5da5Sopenharmony_ci%f = OpFunction %i32 None %tf 418fd4e5da5Sopenharmony_ciOpLine %foo_frag 1 1 419fd4e5da5Sopenharmony_ci%p1 = OpFunctionParameter %i32 420fd4e5da5Sopenharmony_ciOpNoLine 421fd4e5da5Sopenharmony_ci%p2 = OpFunctionParameter %i32 422fd4e5da5Sopenharmony_ci%l = OpLabel 423fd4e5da5Sopenharmony_ciOpReturnValue %c 424fd4e5da5Sopenharmony_ciOpFunctionEnd 425fd4e5da5Sopenharmony_ci)"; 426fd4e5da5Sopenharmony_ci CompileSuccessfully(s); 427fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 428fd4e5da5Sopenharmony_ci} 429fd4e5da5Sopenharmony_ci 430fd4e5da5Sopenharmony_ciTEST_F(ValidateOpFunctionParameter, TooManyParameters) { 431fd4e5da5Sopenharmony_ci const auto s = R"( 432fd4e5da5Sopenharmony_ciOpCapability Shader 433fd4e5da5Sopenharmony_ciOpCapability Linkage 434fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 435fd4e5da5Sopenharmony_ci%i32 = OpTypeInt 32 1 436fd4e5da5Sopenharmony_ci%tf = OpTypeFunction %i32 %i32 %i32 437fd4e5da5Sopenharmony_ci%c = OpConstant %i32 123 438fd4e5da5Sopenharmony_ci%f = OpFunction %i32 None %tf 439fd4e5da5Sopenharmony_ci%p1 = OpFunctionParameter %i32 440fd4e5da5Sopenharmony_ci%p2 = OpFunctionParameter %i32 441fd4e5da5Sopenharmony_ci%xp3 = OpFunctionParameter %i32 442fd4e5da5Sopenharmony_ci%xp4 = OpFunctionParameter %i32 443fd4e5da5Sopenharmony_ci%xp5 = OpFunctionParameter %i32 444fd4e5da5Sopenharmony_ci%xp6 = OpFunctionParameter %i32 445fd4e5da5Sopenharmony_ci%xp7 = OpFunctionParameter %i32 446fd4e5da5Sopenharmony_ci%l = OpLabel 447fd4e5da5Sopenharmony_ciOpReturnValue %c 448fd4e5da5Sopenharmony_ciOpFunctionEnd 449fd4e5da5Sopenharmony_ci)"; 450fd4e5da5Sopenharmony_ci CompileSuccessfully(s); 451fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 452fd4e5da5Sopenharmony_ci} 453fd4e5da5Sopenharmony_ci 454fd4e5da5Sopenharmony_ciusing ValidateEntryPoint = spvtest::ValidateBase<bool>; 455fd4e5da5Sopenharmony_ci 456fd4e5da5Sopenharmony_ci// Tests that not having OpEntryPoint causes an error. 457fd4e5da5Sopenharmony_ciTEST_F(ValidateEntryPoint, NoEntryPointBad) { 458fd4e5da5Sopenharmony_ci std::string spirv = R"( 459fd4e5da5Sopenharmony_ci OpCapability Shader 460fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450)"; 461fd4e5da5Sopenharmony_ci CompileSuccessfully(spirv); 462fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions()); 463fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 464fd4e5da5Sopenharmony_ci HasSubstr("No OpEntryPoint instruction was found. This is only " 465fd4e5da5Sopenharmony_ci "allowed if the Linkage capability is being used.")); 466fd4e5da5Sopenharmony_ci} 467fd4e5da5Sopenharmony_ci 468fd4e5da5Sopenharmony_ci// Invalid. A function may not be a target of both OpEntryPoint and 469fd4e5da5Sopenharmony_ci// OpFunctionCall. 470fd4e5da5Sopenharmony_ciTEST_F(ValidateEntryPoint, FunctionIsTargetOfEntryPointAndFunctionCallBad) { 471fd4e5da5Sopenharmony_ci std::string spirv = R"( 472fd4e5da5Sopenharmony_ci OpCapability Shader 473fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 474fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %foo "foo" 475fd4e5da5Sopenharmony_ci OpExecutionMode %foo OriginUpperLeft 476fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid 477fd4e5da5Sopenharmony_ci%funct = OpTypeFunction %voidt 478fd4e5da5Sopenharmony_ci%foo = OpFunction %voidt None %funct 479fd4e5da5Sopenharmony_ci%entry = OpLabel 480fd4e5da5Sopenharmony_ci%recurse = OpFunctionCall %voidt %foo 481fd4e5da5Sopenharmony_ci OpReturn 482fd4e5da5Sopenharmony_ci OpFunctionEnd 483fd4e5da5Sopenharmony_ci )"; 484fd4e5da5Sopenharmony_ci CompileSuccessfully(spirv); 485fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_BINARY, ValidateInstructions()); 486fd4e5da5Sopenharmony_ci EXPECT_THAT( 487fd4e5da5Sopenharmony_ci getDiagnosticString(), 488fd4e5da5Sopenharmony_ci HasSubstr("A function (1) may not be targeted by both an OpEntryPoint " 489fd4e5da5Sopenharmony_ci "instruction and an OpFunctionCall instruction.")); 490fd4e5da5Sopenharmony_ci} 491fd4e5da5Sopenharmony_ci 492fd4e5da5Sopenharmony_ci// Invalid. Must be within a function to make a function call. 493fd4e5da5Sopenharmony_ciTEST_F(ValidateEntryPoint, FunctionCallOutsideFunctionBody) { 494fd4e5da5Sopenharmony_ci std::string spirv = R"( 495fd4e5da5Sopenharmony_ci OpCapability Shader 496fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 497fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 498fd4e5da5Sopenharmony_ci OpName %variableName "variableName" 499fd4e5da5Sopenharmony_ci %34 = OpFunctionCall %variableName %1 500fd4e5da5Sopenharmony_ci )"; 501fd4e5da5Sopenharmony_ci CompileSuccessfully(spirv); 502fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); 503fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 504fd4e5da5Sopenharmony_ci HasSubstr("FunctionCall must happen within a function body.")); 505fd4e5da5Sopenharmony_ci} 506fd4e5da5Sopenharmony_ci 507fd4e5da5Sopenharmony_ci// Valid. Module with a function but no entry point is valid when Linkage 508fd4e5da5Sopenharmony_ci// Capability is used. 509fd4e5da5Sopenharmony_ciTEST_F(ValidateEntryPoint, NoEntryPointWithLinkageCapGood) { 510fd4e5da5Sopenharmony_ci std::string spirv = R"( 511fd4e5da5Sopenharmony_ci OpCapability Shader 512fd4e5da5Sopenharmony_ci OpCapability Linkage 513fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 514fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid 515fd4e5da5Sopenharmony_ci%funct = OpTypeFunction %voidt 516fd4e5da5Sopenharmony_ci%foo = OpFunction %voidt None %funct 517fd4e5da5Sopenharmony_ci%entry = OpLabel 518fd4e5da5Sopenharmony_ci OpReturn 519fd4e5da5Sopenharmony_ci OpFunctionEnd 520fd4e5da5Sopenharmony_ci )"; 521fd4e5da5Sopenharmony_ci CompileSuccessfully(spirv); 522fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 523fd4e5da5Sopenharmony_ci} 524fd4e5da5Sopenharmony_ci 525fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, ModuleProcessedInvalidIn10) { 526fd4e5da5Sopenharmony_ci char str[] = R"( 527fd4e5da5Sopenharmony_ci OpCapability Shader 528fd4e5da5Sopenharmony_ci OpCapability Linkage 529fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 530fd4e5da5Sopenharmony_ci OpName %void "void" 531fd4e5da5Sopenharmony_ci OpModuleProcessed "this is ok in 1.1 and later" 532fd4e5da5Sopenharmony_ci%void = OpTypeVoid 533fd4e5da5Sopenharmony_ci)"; 534fd4e5da5Sopenharmony_ci 535fd4e5da5Sopenharmony_ci CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1); 536fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_WRONG_VERSION, 537fd4e5da5Sopenharmony_ci ValidateInstructions(SPV_ENV_UNIVERSAL_1_0)); 538fd4e5da5Sopenharmony_ci // In a 1.0 environment the version check fails. 539fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 540fd4e5da5Sopenharmony_ci HasSubstr("Invalid SPIR-V binary version 1.1 for target " 541fd4e5da5Sopenharmony_ci "environment SPIR-V 1.0.")); 542fd4e5da5Sopenharmony_ci} 543fd4e5da5Sopenharmony_ci 544fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, ModuleProcessedValidIn11) { 545fd4e5da5Sopenharmony_ci char str[] = R"( 546fd4e5da5Sopenharmony_ci OpCapability Shader 547fd4e5da5Sopenharmony_ci OpCapability Linkage 548fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 549fd4e5da5Sopenharmony_ci OpName %void "void" 550fd4e5da5Sopenharmony_ci OpModuleProcessed "this is ok in 1.1 and later" 551fd4e5da5Sopenharmony_ci%void = OpTypeVoid 552fd4e5da5Sopenharmony_ci)"; 553fd4e5da5Sopenharmony_ci 554fd4e5da5Sopenharmony_ci CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1); 555fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_1)); 556fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), Eq("")); 557fd4e5da5Sopenharmony_ci} 558fd4e5da5Sopenharmony_ci 559fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, LayoutOrderMixedUp) { 560fd4e5da5Sopenharmony_ci char str[] = R"( 561fd4e5da5Sopenharmony_ci OpCapability Shader 562fd4e5da5Sopenharmony_ci OpCapability Linkage 563fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 564fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %fragmentFloat "fragmentFloat" 565fd4e5da5Sopenharmony_ci OpExecutionMode %fragmentFloat OriginUpperLeft 566fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %fragmentUint "fragmentUint" 567fd4e5da5Sopenharmony_ci OpExecutionMode %fragmentUint OriginUpperLeft 568fd4e5da5Sopenharmony_ci)"; 569fd4e5da5Sopenharmony_ci 570fd4e5da5Sopenharmony_ci CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1); 571fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, 572fd4e5da5Sopenharmony_ci ValidateInstructions(SPV_ENV_UNIVERSAL_1_1)); 573fd4e5da5Sopenharmony_ci // By the mechanics of the validator, we assume ModuleProcessed is in the 574fd4e5da5Sopenharmony_ci // right spot, but then that OpName is in the wrong spot. 575fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 576fd4e5da5Sopenharmony_ci HasSubstr("EntryPoint is in an invalid layout section")); 577fd4e5da5Sopenharmony_ci} 578fd4e5da5Sopenharmony_ci 579fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, ModuleProcessedBeforeLastNameIsTooEarly) { 580fd4e5da5Sopenharmony_ci char str[] = R"( 581fd4e5da5Sopenharmony_ci OpCapability Shader 582fd4e5da5Sopenharmony_ci OpCapability Linkage 583fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 584fd4e5da5Sopenharmony_ci OpModuleProcessed "this is too early" 585fd4e5da5Sopenharmony_ci OpName %void "void" 586fd4e5da5Sopenharmony_ci%void = OpTypeVoid 587fd4e5da5Sopenharmony_ci)"; 588fd4e5da5Sopenharmony_ci 589fd4e5da5Sopenharmony_ci CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1); 590fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, 591fd4e5da5Sopenharmony_ci ValidateInstructions(SPV_ENV_UNIVERSAL_1_1)); 592fd4e5da5Sopenharmony_ci // By the mechanics of the validator, we assume ModuleProcessed is in the 593fd4e5da5Sopenharmony_ci // right spot, but then that OpName is in the wrong spot. 594fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 595fd4e5da5Sopenharmony_ci HasSubstr("Name is in an invalid layout section")); 596fd4e5da5Sopenharmony_ci} 597fd4e5da5Sopenharmony_ci 598fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, ModuleProcessedInvalidAfterFirstAnnotation) { 599fd4e5da5Sopenharmony_ci char str[] = R"( 600fd4e5da5Sopenharmony_ci OpCapability Shader 601fd4e5da5Sopenharmony_ci OpCapability Linkage 602fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 603fd4e5da5Sopenharmony_ci OpDecorate %void Volatile ; this is bogus, but keeps the example short 604fd4e5da5Sopenharmony_ci OpModuleProcessed "this is too late" 605fd4e5da5Sopenharmony_ci%void = OpTypeVoid 606fd4e5da5Sopenharmony_ci)"; 607fd4e5da5Sopenharmony_ci 608fd4e5da5Sopenharmony_ci CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1); 609fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, 610fd4e5da5Sopenharmony_ci ValidateInstructions(SPV_ENV_UNIVERSAL_1_1)); 611fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 612fd4e5da5Sopenharmony_ci HasSubstr("ModuleProcessed is in an invalid layout section")); 613fd4e5da5Sopenharmony_ci} 614fd4e5da5Sopenharmony_ci 615fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, ModuleProcessedInvalidInFunctionBeforeLabel) { 616fd4e5da5Sopenharmony_ci char str[] = R"( 617fd4e5da5Sopenharmony_ci OpCapability Shader 618fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 619fd4e5da5Sopenharmony_ci OpEntryPoint GLCompute %main "main" 620fd4e5da5Sopenharmony_ci%void = OpTypeVoid 621fd4e5da5Sopenharmony_ci%voidfn = OpTypeFunction %void 622fd4e5da5Sopenharmony_ci%main = OpFunction %void None %voidfn 623fd4e5da5Sopenharmony_ci OpModuleProcessed "this is too late, in function before label" 624fd4e5da5Sopenharmony_ci%entry = OpLabel 625fd4e5da5Sopenharmony_ci OpReturn 626fd4e5da5Sopenharmony_ci OpFunctionEnd 627fd4e5da5Sopenharmony_ci)"; 628fd4e5da5Sopenharmony_ci 629fd4e5da5Sopenharmony_ci CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1); 630fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, 631fd4e5da5Sopenharmony_ci ValidateInstructions(SPV_ENV_UNIVERSAL_1_1)); 632fd4e5da5Sopenharmony_ci EXPECT_THAT( 633fd4e5da5Sopenharmony_ci getDiagnosticString(), 634fd4e5da5Sopenharmony_ci HasSubstr("ModuleProcessed cannot appear in a function declaration")); 635fd4e5da5Sopenharmony_ci} 636fd4e5da5Sopenharmony_ci 637fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, ModuleProcessedInvalidInBasicBlock) { 638fd4e5da5Sopenharmony_ci char str[] = R"( 639fd4e5da5Sopenharmony_ci OpCapability Shader 640fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 641fd4e5da5Sopenharmony_ci OpEntryPoint GLCompute %main "main" 642fd4e5da5Sopenharmony_ci%void = OpTypeVoid 643fd4e5da5Sopenharmony_ci%voidfn = OpTypeFunction %void 644fd4e5da5Sopenharmony_ci%main = OpFunction %void None %voidfn 645fd4e5da5Sopenharmony_ci%entry = OpLabel 646fd4e5da5Sopenharmony_ci OpModuleProcessed "this is too late, in basic block" 647fd4e5da5Sopenharmony_ci OpReturn 648fd4e5da5Sopenharmony_ci OpFunctionEnd 649fd4e5da5Sopenharmony_ci)"; 650fd4e5da5Sopenharmony_ci 651fd4e5da5Sopenharmony_ci CompileSuccessfully(str, SPV_ENV_UNIVERSAL_1_1); 652fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, 653fd4e5da5Sopenharmony_ci ValidateInstructions(SPV_ENV_UNIVERSAL_1_1)); 654fd4e5da5Sopenharmony_ci EXPECT_THAT( 655fd4e5da5Sopenharmony_ci getDiagnosticString(), 656fd4e5da5Sopenharmony_ci HasSubstr("ModuleProcessed cannot appear in a function declaration")); 657fd4e5da5Sopenharmony_ci} 658fd4e5da5Sopenharmony_ci 659fd4e5da5Sopenharmony_ci// TODO(umar): Test optional instructions 660fd4e5da5Sopenharmony_ci 661fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, ValidNVBindlessTexturelayout) { 662fd4e5da5Sopenharmony_ci std::string str = R"( 663fd4e5da5Sopenharmony_ci OpCapability Shader 664fd4e5da5Sopenharmony_ci OpCapability BindlessTextureNV 665fd4e5da5Sopenharmony_ci OpExtension "SPV_NV_bindless_texture" 666fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 667fd4e5da5Sopenharmony_ci OpSamplerImageAddressingModeNV 64 668fd4e5da5Sopenharmony_ci OpEntryPoint GLCompute %func "main" 669fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid 670fd4e5da5Sopenharmony_ci%uintt = OpTypeInt 32 0 671fd4e5da5Sopenharmony_ci%funct = OpTypeFunction %voidt 672fd4e5da5Sopenharmony_ci%func = OpFunction %voidt None %funct 673fd4e5da5Sopenharmony_ci%entry = OpLabel 674fd4e5da5Sopenharmony_ci%udef = OpUndef %uintt 675fd4e5da5Sopenharmony_ci OpReturn 676fd4e5da5Sopenharmony_ci OpFunctionEnd 677fd4e5da5Sopenharmony_ci)"; 678fd4e5da5Sopenharmony_ci 679fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 680fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 681fd4e5da5Sopenharmony_ci} 682fd4e5da5Sopenharmony_ci 683fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, InvalidValidNVBindlessTexturelayout) { 684fd4e5da5Sopenharmony_ci std::string str = R"( 685fd4e5da5Sopenharmony_ci OpCapability Shader 686fd4e5da5Sopenharmony_ci OpCapability BindlessTextureNV 687fd4e5da5Sopenharmony_ci OpExtension "SPV_NV_bindless_texture" 688fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 689fd4e5da5Sopenharmony_ci OpEntryPoint GLCompute %func "main" 690fd4e5da5Sopenharmony_ci OpSamplerImageAddressingModeNV 64 691fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid 692fd4e5da5Sopenharmony_ci%uintt = OpTypeInt 32 0 693fd4e5da5Sopenharmony_ci%funct = OpTypeFunction %voidt 694fd4e5da5Sopenharmony_ci%func = OpFunction %voidt None %funct 695fd4e5da5Sopenharmony_ci%entry = OpLabel 696fd4e5da5Sopenharmony_ci%udef = OpUndef %uintt 697fd4e5da5Sopenharmony_ci OpReturn 698fd4e5da5Sopenharmony_ci OpFunctionEnd 699fd4e5da5Sopenharmony_ci)"; 700fd4e5da5Sopenharmony_ci 701fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 702fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, 703fd4e5da5Sopenharmony_ci ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); 704fd4e5da5Sopenharmony_ci EXPECT_THAT( 705fd4e5da5Sopenharmony_ci getDiagnosticString(), 706fd4e5da5Sopenharmony_ci HasSubstr( 707fd4e5da5Sopenharmony_ci "SamplerImageAddressingModeNV is in an invalid layout section")); 708fd4e5da5Sopenharmony_ci} 709fd4e5da5Sopenharmony_ci 710fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, MissingNVBindlessAddressModeFromLayout) { 711fd4e5da5Sopenharmony_ci std::string str = R"( 712fd4e5da5Sopenharmony_ci OpCapability Shader 713fd4e5da5Sopenharmony_ci OpCapability BindlessTextureNV 714fd4e5da5Sopenharmony_ci OpExtension "SPV_NV_bindless_texture" 715fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 716fd4e5da5Sopenharmony_ci OpEntryPoint GLCompute %func "main" 717fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid 718fd4e5da5Sopenharmony_ci%uintt = OpTypeInt 32 0 719fd4e5da5Sopenharmony_ci%funct = OpTypeFunction %voidt 720fd4e5da5Sopenharmony_ci%func = OpFunction %voidt None %funct 721fd4e5da5Sopenharmony_ci%entry = OpLabel 722fd4e5da5Sopenharmony_ci%udef = OpUndef %uintt 723fd4e5da5Sopenharmony_ci OpReturn 724fd4e5da5Sopenharmony_ci OpFunctionEnd 725fd4e5da5Sopenharmony_ci)"; 726fd4e5da5Sopenharmony_ci 727fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 728fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, 729fd4e5da5Sopenharmony_ci ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); 730fd4e5da5Sopenharmony_ci EXPECT_THAT( 731fd4e5da5Sopenharmony_ci getDiagnosticString(), 732fd4e5da5Sopenharmony_ci HasSubstr("Missing required OpSamplerImageAddressingModeNV instruction")); 733fd4e5da5Sopenharmony_ci} 734fd4e5da5Sopenharmony_ci 735fd4e5da5Sopenharmony_ciTEST_F(ValidateLayout, NVBindlessAddressModeFromLayoutSpecifiedTwice) { 736fd4e5da5Sopenharmony_ci std::string str = R"( 737fd4e5da5Sopenharmony_ci OpCapability Shader 738fd4e5da5Sopenharmony_ci OpCapability BindlessTextureNV 739fd4e5da5Sopenharmony_ci OpExtension "SPV_NV_bindless_texture" 740fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 741fd4e5da5Sopenharmony_ci OpSamplerImageAddressingModeNV 64 742fd4e5da5Sopenharmony_ci OpSamplerImageAddressingModeNV 64 743fd4e5da5Sopenharmony_ci)"; 744fd4e5da5Sopenharmony_ci 745fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 746fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_LAYOUT, 747fd4e5da5Sopenharmony_ci ValidateInstructions(SPV_ENV_UNIVERSAL_1_3)); 748fd4e5da5Sopenharmony_ci EXPECT_THAT( 749fd4e5da5Sopenharmony_ci getDiagnosticString(), 750fd4e5da5Sopenharmony_ci HasSubstr("OpSamplerImageAddressingModeNV should only be provided once")); 751fd4e5da5Sopenharmony_ci} 752fd4e5da5Sopenharmony_ci 753fd4e5da5Sopenharmony_ci} // namespace 754fd4e5da5Sopenharmony_ci} // namespace val 755fd4e5da5Sopenharmony_ci} // namespace spvtools 756