1fd4e5da5Sopenharmony_ci// Copyright (c) 2018 LunarG 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#include <sstream> 16fd4e5da5Sopenharmony_ci#include <string> 17fd4e5da5Sopenharmony_ci 18fd4e5da5Sopenharmony_ci#include "gmock/gmock.h" 19fd4e5da5Sopenharmony_ci#include "test/unit_spirv.h" 20fd4e5da5Sopenharmony_ci#include "test/val/val_fixtures.h" 21fd4e5da5Sopenharmony_ci 22fd4e5da5Sopenharmony_cinamespace spvtools { 23fd4e5da5Sopenharmony_cinamespace val { 24fd4e5da5Sopenharmony_cinamespace { 25fd4e5da5Sopenharmony_ci 26fd4e5da5Sopenharmony_ciusing ::testing::HasSubstr; 27fd4e5da5Sopenharmony_ciusing ::testing::Not; 28fd4e5da5Sopenharmony_ci 29fd4e5da5Sopenharmony_ciusing ValidateAdjacency = spvtest::ValidateBase<bool>; 30fd4e5da5Sopenharmony_ci 31fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiBeginsModuleFail) { 32fd4e5da5Sopenharmony_ci const std::string module = R"( 33fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label 34fd4e5da5Sopenharmony_ciOpCapability Shader 35fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 36fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %main "main" 37fd4e5da5Sopenharmony_ciOpExecutionMode %main OriginUpperLeft 38fd4e5da5Sopenharmony_ci%void = OpTypeVoid 39fd4e5da5Sopenharmony_ci%bool = OpTypeBool 40fd4e5da5Sopenharmony_ci%true = OpConstantTrue %bool 41fd4e5da5Sopenharmony_ci%false = OpConstantFalse %bool 42fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void 43fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func 44fd4e5da5Sopenharmony_ci%main_entry = OpLabel 45fd4e5da5Sopenharmony_ciOpBranch %true_label 46fd4e5da5Sopenharmony_ci%true_label = OpLabel 47fd4e5da5Sopenharmony_ciOpBranch %false_label 48fd4e5da5Sopenharmony_ci%false_label = OpLabel 49fd4e5da5Sopenharmony_ciOpBranch %end_label 50fd4e5da5Sopenharmony_ciOpReturn 51fd4e5da5Sopenharmony_ciOpFunctionEnd 52fd4e5da5Sopenharmony_ci)"; 53fd4e5da5Sopenharmony_ci 54fd4e5da5Sopenharmony_ci CompileSuccessfully(module); 55fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 56fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 57fd4e5da5Sopenharmony_ci HasSubstr("ID '1[%bool]' has not been defined")); 58fd4e5da5Sopenharmony_ci} 59fd4e5da5Sopenharmony_ci 60fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpLoopMergeEndsModuleFail) { 61fd4e5da5Sopenharmony_ci const std::string module = R"( 62fd4e5da5Sopenharmony_ciOpCapability Shader 63fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 64fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %main "main" 65fd4e5da5Sopenharmony_ciOpExecutionMode %main OriginUpperLeft 66fd4e5da5Sopenharmony_ci%void = OpTypeVoid 67fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void 68fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func 69fd4e5da5Sopenharmony_ci%main_entry = OpLabel 70fd4e5da5Sopenharmony_ciOpBranch %loop 71fd4e5da5Sopenharmony_ci%loop = OpLabel 72fd4e5da5Sopenharmony_ciOpLoopMerge %end %loop None 73fd4e5da5Sopenharmony_ci)"; 74fd4e5da5Sopenharmony_ci 75fd4e5da5Sopenharmony_ci CompileSuccessfully(module); 76fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); 77fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 78fd4e5da5Sopenharmony_ci HasSubstr("Missing OpFunctionEnd at end of module")); 79fd4e5da5Sopenharmony_ci} 80fd4e5da5Sopenharmony_ci 81fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpSelectionMergeEndsModuleFail) { 82fd4e5da5Sopenharmony_ci const std::string module = R"( 83fd4e5da5Sopenharmony_ciOpCapability Shader 84fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 85fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %main "main" 86fd4e5da5Sopenharmony_ciOpExecutionMode %main OriginUpperLeft 87fd4e5da5Sopenharmony_ci%void = OpTypeVoid 88fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void 89fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func 90fd4e5da5Sopenharmony_ci%main_entry = OpLabel 91fd4e5da5Sopenharmony_ciOpBranch %merge 92fd4e5da5Sopenharmony_ci%merge = OpLabel 93fd4e5da5Sopenharmony_ciOpSelectionMerge %merge None 94fd4e5da5Sopenharmony_ci)"; 95fd4e5da5Sopenharmony_ci 96fd4e5da5Sopenharmony_ci CompileSuccessfully(module); 97fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); 98fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 99fd4e5da5Sopenharmony_ci HasSubstr("Missing OpFunctionEnd at end of module")); 100fd4e5da5Sopenharmony_ci} 101fd4e5da5Sopenharmony_ci 102fd4e5da5Sopenharmony_cistd::string GenerateShaderCode( 103fd4e5da5Sopenharmony_ci const std::string& body, 104fd4e5da5Sopenharmony_ci const std::string& capabilities_and_extensions = "OpCapability Shader", 105fd4e5da5Sopenharmony_ci const std::string& execution_model = "Fragment") { 106fd4e5da5Sopenharmony_ci std::ostringstream ss; 107fd4e5da5Sopenharmony_ci ss << capabilities_and_extensions << "\n"; 108fd4e5da5Sopenharmony_ci ss << "OpMemoryModel Logical GLSL450\n"; 109fd4e5da5Sopenharmony_ci ss << "OpEntryPoint " << execution_model << " %main \"main\"\n"; 110fd4e5da5Sopenharmony_ci if (execution_model == "Fragment") { 111fd4e5da5Sopenharmony_ci ss << "OpExecutionMode %main OriginUpperLeft\n"; 112fd4e5da5Sopenharmony_ci } 113fd4e5da5Sopenharmony_ci 114fd4e5da5Sopenharmony_ci ss << R"( 115fd4e5da5Sopenharmony_ci%string = OpString "" 116fd4e5da5Sopenharmony_ci%void = OpTypeVoid 117fd4e5da5Sopenharmony_ci%bool = OpTypeBool 118fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 119fd4e5da5Sopenharmony_ci%true = OpConstantTrue %bool 120fd4e5da5Sopenharmony_ci%false = OpConstantFalse %bool 121fd4e5da5Sopenharmony_ci%zero = OpConstant %int 0 122fd4e5da5Sopenharmony_ci%int_1 = OpConstant %int 1 123fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void 124fd4e5da5Sopenharmony_ci%func_int = OpTypePointer Function %int 125fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func 126fd4e5da5Sopenharmony_ci%main_entry = OpLabel 127fd4e5da5Sopenharmony_ci)"; 128fd4e5da5Sopenharmony_ci 129fd4e5da5Sopenharmony_ci ss << body; 130fd4e5da5Sopenharmony_ci 131fd4e5da5Sopenharmony_ci ss << R"( 132fd4e5da5Sopenharmony_ciOpReturn 133fd4e5da5Sopenharmony_ciOpFunctionEnd)"; 134fd4e5da5Sopenharmony_ci 135fd4e5da5Sopenharmony_ci return ss.str(); 136fd4e5da5Sopenharmony_ci} 137fd4e5da5Sopenharmony_ci 138fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiPreceededByOpLabelSuccess) { 139fd4e5da5Sopenharmony_ci const std::string body = R"( 140fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None 141fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label 142fd4e5da5Sopenharmony_ci%true_label = OpLabel 143fd4e5da5Sopenharmony_ciOpBranch %end_label 144fd4e5da5Sopenharmony_ci%false_label = OpLabel 145fd4e5da5Sopenharmony_ciOpBranch %end_label 146fd4e5da5Sopenharmony_ci%end_label = OpLabel 147fd4e5da5Sopenharmony_ciOpLine %string 0 0 148fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label 149fd4e5da5Sopenharmony_ci)"; 150fd4e5da5Sopenharmony_ci 151fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 152fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 153fd4e5da5Sopenharmony_ci} 154fd4e5da5Sopenharmony_ci 155fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiPreceededByOpPhiSuccess) { 156fd4e5da5Sopenharmony_ci const std::string body = R"( 157fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None 158fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label 159fd4e5da5Sopenharmony_ci%true_label = OpLabel 160fd4e5da5Sopenharmony_ciOpBranch %end_label 161fd4e5da5Sopenharmony_ci%false_label = OpLabel 162fd4e5da5Sopenharmony_ciOpBranch %end_label 163fd4e5da5Sopenharmony_ci%end_label = OpLabel 164fd4e5da5Sopenharmony_ci%1 = OpPhi %bool %true %true_label %false %false_label 165fd4e5da5Sopenharmony_ci%2 = OpPhi %bool %true %true_label %false %false_label 166fd4e5da5Sopenharmony_ci)"; 167fd4e5da5Sopenharmony_ci 168fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 169fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 170fd4e5da5Sopenharmony_ci} 171fd4e5da5Sopenharmony_ci 172fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiPreceededByOpLineSuccess) { 173fd4e5da5Sopenharmony_ci const std::string body = R"( 174fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None 175fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label 176fd4e5da5Sopenharmony_ci%true_label = OpLabel 177fd4e5da5Sopenharmony_ciOpBranch %end_label 178fd4e5da5Sopenharmony_ci%false_label = OpLabel 179fd4e5da5Sopenharmony_ciOpBranch %end_label 180fd4e5da5Sopenharmony_ci%end_label = OpLabel 181fd4e5da5Sopenharmony_ciOpLine %string 0 0 182fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label 183fd4e5da5Sopenharmony_ci)"; 184fd4e5da5Sopenharmony_ci 185fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 186fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 187fd4e5da5Sopenharmony_ci} 188fd4e5da5Sopenharmony_ci 189fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiPreceededByBadOpFail) { 190fd4e5da5Sopenharmony_ci const std::string body = R"( 191fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None 192fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label 193fd4e5da5Sopenharmony_ci%true_label = OpLabel 194fd4e5da5Sopenharmony_ciOpBranch %end_label 195fd4e5da5Sopenharmony_ci%false_label = OpLabel 196fd4e5da5Sopenharmony_ciOpBranch %end_label 197fd4e5da5Sopenharmony_ci%end_label = OpLabel 198fd4e5da5Sopenharmony_ciOpNop 199fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label 200fd4e5da5Sopenharmony_ci)"; 201fd4e5da5Sopenharmony_ci 202fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 203fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 204fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 205fd4e5da5Sopenharmony_ci HasSubstr("OpPhi must appear within a non-entry block before all " 206fd4e5da5Sopenharmony_ci "non-OpPhi instructions")); 207fd4e5da5Sopenharmony_ci} 208fd4e5da5Sopenharmony_ci 209fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiPreceededByOpLineAndBadOpFail) { 210fd4e5da5Sopenharmony_ci const std::string body = R"( 211fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None 212fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label 213fd4e5da5Sopenharmony_ci%true_label = OpLabel 214fd4e5da5Sopenharmony_ciOpBranch %end_label 215fd4e5da5Sopenharmony_ci%false_label = OpLabel 216fd4e5da5Sopenharmony_ciOpBranch %end_label 217fd4e5da5Sopenharmony_ci%end_label = OpLabel 218fd4e5da5Sopenharmony_ciOpNop 219fd4e5da5Sopenharmony_ciOpLine %string 1 1 220fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label 221fd4e5da5Sopenharmony_ci)"; 222fd4e5da5Sopenharmony_ci 223fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 224fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 225fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 226fd4e5da5Sopenharmony_ci HasSubstr("OpPhi must appear within a non-entry block before all " 227fd4e5da5Sopenharmony_ci "non-OpPhi instructions")); 228fd4e5da5Sopenharmony_ci} 229fd4e5da5Sopenharmony_ci 230fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiFollowedByOpLineGood) { 231fd4e5da5Sopenharmony_ci const std::string body = R"( 232fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None 233fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label 234fd4e5da5Sopenharmony_ci%true_label = OpLabel 235fd4e5da5Sopenharmony_ciOpBranch %end_label 236fd4e5da5Sopenharmony_ci%false_label = OpLabel 237fd4e5da5Sopenharmony_ciOpBranch %end_label 238fd4e5da5Sopenharmony_ci%end_label = OpLabel 239fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label 240fd4e5da5Sopenharmony_ciOpLine %string 1 1 241fd4e5da5Sopenharmony_ciOpNop 242fd4e5da5Sopenharmony_ciOpNop 243fd4e5da5Sopenharmony_ciOpLine %string 2 1 244fd4e5da5Sopenharmony_ciOpNop 245fd4e5da5Sopenharmony_ciOpLine %string 3 1 246fd4e5da5Sopenharmony_ci)"; 247fd4e5da5Sopenharmony_ci 248fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 249fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 250fd4e5da5Sopenharmony_ci} 251fd4e5da5Sopenharmony_ci 252fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiMultipleOpLineAndOpPhiFail) { 253fd4e5da5Sopenharmony_ci const std::string body = R"( 254fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None 255fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label 256fd4e5da5Sopenharmony_ci%true_label = OpLabel 257fd4e5da5Sopenharmony_ciOpBranch %end_label 258fd4e5da5Sopenharmony_ci%false_label = OpLabel 259fd4e5da5Sopenharmony_ciOpBranch %end_label 260fd4e5da5Sopenharmony_ci%end_label = OpLabel 261fd4e5da5Sopenharmony_ciOpLine %string 1 1 262fd4e5da5Sopenharmony_ci%value = OpPhi %int %zero %true_label %int_1 %false_label 263fd4e5da5Sopenharmony_ciOpNop 264fd4e5da5Sopenharmony_ciOpLine %string 2 1 265fd4e5da5Sopenharmony_ciOpNop 266fd4e5da5Sopenharmony_ciOpLine %string 3 1 267fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label 268fd4e5da5Sopenharmony_ci)"; 269fd4e5da5Sopenharmony_ci 270fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 271fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 272fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 273fd4e5da5Sopenharmony_ci HasSubstr("OpPhi must appear within a non-entry block before all " 274fd4e5da5Sopenharmony_ci "non-OpPhi instructions")); 275fd4e5da5Sopenharmony_ci} 276fd4e5da5Sopenharmony_ci 277fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiMultipleOpLineAndOpPhiGood) { 278fd4e5da5Sopenharmony_ci const std::string body = R"( 279fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None 280fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label 281fd4e5da5Sopenharmony_ci%true_label = OpLabel 282fd4e5da5Sopenharmony_ciOpBranch %end_label 283fd4e5da5Sopenharmony_ci%false_label = OpLabel 284fd4e5da5Sopenharmony_ciOpBranch %end_label 285fd4e5da5Sopenharmony_ci%end_label = OpLabel 286fd4e5da5Sopenharmony_ciOpLine %string 1 1 287fd4e5da5Sopenharmony_ci%value = OpPhi %int %zero %true_label %int_1 %false_label 288fd4e5da5Sopenharmony_ciOpLine %string 2 1 289fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label 290fd4e5da5Sopenharmony_ciOpLine %string 3 1 291fd4e5da5Sopenharmony_ciOpNop 292fd4e5da5Sopenharmony_ciOpNop 293fd4e5da5Sopenharmony_ciOpLine %string 4 1 294fd4e5da5Sopenharmony_ciOpNop 295fd4e5da5Sopenharmony_ci)"; 296fd4e5da5Sopenharmony_ci 297fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 298fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 299fd4e5da5Sopenharmony_ci} 300fd4e5da5Sopenharmony_ci 301fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpPhiInEntryBlockBad) { 302fd4e5da5Sopenharmony_ci const std::string body = R"( 303fd4e5da5Sopenharmony_ciOpLine %string 1 1 304fd4e5da5Sopenharmony_ci%value = OpPhi %int 305fd4e5da5Sopenharmony_ciOpLine %string 2 1 306fd4e5da5Sopenharmony_ciOpNop 307fd4e5da5Sopenharmony_ciOpLine %string 3 1 308fd4e5da5Sopenharmony_ciOpNop 309fd4e5da5Sopenharmony_ci)"; 310fd4e5da5Sopenharmony_ci 311fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 312fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 313fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 314fd4e5da5Sopenharmony_ci HasSubstr("OpPhi must appear within a non-entry block before all " 315fd4e5da5Sopenharmony_ci "non-OpPhi instructions")); 316fd4e5da5Sopenharmony_ci} 317fd4e5da5Sopenharmony_ci 318fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, NonSemanticBeforeOpPhiBad) { 319fd4e5da5Sopenharmony_ci const std::string body = R"( 320fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None 321fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label 322fd4e5da5Sopenharmony_ci%true_label = OpLabel 323fd4e5da5Sopenharmony_ciOpBranch %end_label 324fd4e5da5Sopenharmony_ci%false_label = OpLabel 325fd4e5da5Sopenharmony_ciOpBranch %end_label 326fd4e5da5Sopenharmony_ci%end_label = OpLabel 327fd4e5da5Sopenharmony_ci%placeholder = OpExtInst %void %extinst 123 %int_1 328fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label 329fd4e5da5Sopenharmony_ci)"; 330fd4e5da5Sopenharmony_ci 331fd4e5da5Sopenharmony_ci const std::string extra = R"(OpCapability Shader 332fd4e5da5Sopenharmony_ciOpExtension "SPV_KHR_non_semantic_info" 333fd4e5da5Sopenharmony_ci%extinst = OpExtInstImport "NonSemantic.Testing.Set" 334fd4e5da5Sopenharmony_ci)"; 335fd4e5da5Sopenharmony_ci 336fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body, extra)); 337fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 338fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 339fd4e5da5Sopenharmony_ci HasSubstr("OpPhi must appear within a non-entry block before all " 340fd4e5da5Sopenharmony_ci "non-OpPhi instructions")); 341fd4e5da5Sopenharmony_ci} 342fd4e5da5Sopenharmony_ci 343fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, NonSemanticBetweenOpPhiBad) { 344fd4e5da5Sopenharmony_ci const std::string body = R"( 345fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None 346fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label 347fd4e5da5Sopenharmony_ci%true_label = OpLabel 348fd4e5da5Sopenharmony_ciOpBranch %end_label 349fd4e5da5Sopenharmony_ci%false_label = OpLabel 350fd4e5da5Sopenharmony_ciOpBranch %end_label 351fd4e5da5Sopenharmony_ci%end_label = OpLabel 352fd4e5da5Sopenharmony_ci%result1 = OpPhi %bool %true %true_label %false %false_label 353fd4e5da5Sopenharmony_ci%placeholder = OpExtInst %void %extinst 123 %int_1 354fd4e5da5Sopenharmony_ci%result2 = OpPhi %bool %true %true_label %false %false_label 355fd4e5da5Sopenharmony_ci)"; 356fd4e5da5Sopenharmony_ci 357fd4e5da5Sopenharmony_ci const std::string extra = R"(OpCapability Shader 358fd4e5da5Sopenharmony_ciOpExtension "SPV_KHR_non_semantic_info" 359fd4e5da5Sopenharmony_ci%extinst = OpExtInstImport "NonSemantic.Testing.Set" 360fd4e5da5Sopenharmony_ci)"; 361fd4e5da5Sopenharmony_ci 362fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body, extra)); 363fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 364fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 365fd4e5da5Sopenharmony_ci HasSubstr("OpPhi must appear within a non-entry block before all " 366fd4e5da5Sopenharmony_ci "non-OpPhi instructions")); 367fd4e5da5Sopenharmony_ci} 368fd4e5da5Sopenharmony_ci 369fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, NonSemanticAfterOpPhiGood) { 370fd4e5da5Sopenharmony_ci const std::string body = R"( 371fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None 372fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label 373fd4e5da5Sopenharmony_ci%true_label = OpLabel 374fd4e5da5Sopenharmony_ciOpBranch %end_label 375fd4e5da5Sopenharmony_ci%false_label = OpLabel 376fd4e5da5Sopenharmony_ciOpBranch %end_label 377fd4e5da5Sopenharmony_ci%end_label = OpLabel 378fd4e5da5Sopenharmony_ciOpLine %string 0 0 379fd4e5da5Sopenharmony_ci%result = OpPhi %bool %true %true_label %false %false_label 380fd4e5da5Sopenharmony_ci%placeholder = OpExtInst %void %extinst 123 %int_1 381fd4e5da5Sopenharmony_ci)"; 382fd4e5da5Sopenharmony_ci 383fd4e5da5Sopenharmony_ci const std::string extra = R"(OpCapability Shader 384fd4e5da5Sopenharmony_ciOpExtension "SPV_KHR_non_semantic_info" 385fd4e5da5Sopenharmony_ci%extinst = OpExtInstImport "NonSemantic.Testing.Set" 386fd4e5da5Sopenharmony_ci)"; 387fd4e5da5Sopenharmony_ci 388fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body, extra)); 389fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 390fd4e5da5Sopenharmony_ci} 391fd4e5da5Sopenharmony_ci 392fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, NonSemanticBeforeOpFunctionParameterBad) { 393fd4e5da5Sopenharmony_ci const std::string body = R"( 394fd4e5da5Sopenharmony_ciOpCapability Shader 395fd4e5da5Sopenharmony_ciOpExtension "SPV_KHR_non_semantic_info" 396fd4e5da5Sopenharmony_ci%extinst = OpExtInstImport "NonSemantic.Testing.Set" 397fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 398fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %main "main" 399fd4e5da5Sopenharmony_ciOpExecutionMode %main OriginUpperLeft 400fd4e5da5Sopenharmony_ci 401fd4e5da5Sopenharmony_ci%string = OpString "" 402fd4e5da5Sopenharmony_ci%void = OpTypeVoid 403fd4e5da5Sopenharmony_ci%bool = OpTypeBool 404fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 405fd4e5da5Sopenharmony_ci%true = OpConstantTrue %bool 406fd4e5da5Sopenharmony_ci%false = OpConstantFalse %bool 407fd4e5da5Sopenharmony_ci%zero = OpConstant %int 0 408fd4e5da5Sopenharmony_ci%int_1 = OpConstant %int 1 409fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void 410fd4e5da5Sopenharmony_ci%func_int = OpTypePointer Function %int 411fd4e5da5Sopenharmony_ci%paramfunc_type = OpTypeFunction %void %int %int 412fd4e5da5Sopenharmony_ci 413fd4e5da5Sopenharmony_ci%paramfunc = OpFunction %void None %paramfunc_type 414fd4e5da5Sopenharmony_ci%placeholder = OpExtInst %void %extinst 123 %int_1 415fd4e5da5Sopenharmony_ci%a = OpFunctionParameter %int 416fd4e5da5Sopenharmony_ci%b = OpFunctionParameter %int 417fd4e5da5Sopenharmony_ci%paramfunc_entry = OpLabel 418fd4e5da5Sopenharmony_ciOpReturn 419fd4e5da5Sopenharmony_ciOpFunctionEnd 420fd4e5da5Sopenharmony_ci 421fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func 422fd4e5da5Sopenharmony_ci%main_entry = OpLabel 423fd4e5da5Sopenharmony_ciOpReturn 424fd4e5da5Sopenharmony_ciOpFunctionEnd 425fd4e5da5Sopenharmony_ci)"; 426fd4e5da5Sopenharmony_ci 427fd4e5da5Sopenharmony_ci CompileSuccessfully(body); 428fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); 429fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 430fd4e5da5Sopenharmony_ci HasSubstr("Non-semantic OpExtInst within function definition " 431fd4e5da5Sopenharmony_ci "must appear in a block")); 432fd4e5da5Sopenharmony_ci} 433fd4e5da5Sopenharmony_ci 434fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, NonSemanticBetweenOpFunctionParameterBad) { 435fd4e5da5Sopenharmony_ci const std::string body = R"( 436fd4e5da5Sopenharmony_ciOpCapability Shader 437fd4e5da5Sopenharmony_ciOpExtension "SPV_KHR_non_semantic_info" 438fd4e5da5Sopenharmony_ci%extinst = OpExtInstImport "NonSemantic.Testing.Set" 439fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 440fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %main "main" 441fd4e5da5Sopenharmony_ciOpExecutionMode %main OriginUpperLeft 442fd4e5da5Sopenharmony_ci 443fd4e5da5Sopenharmony_ci%string = OpString "" 444fd4e5da5Sopenharmony_ci%void = OpTypeVoid 445fd4e5da5Sopenharmony_ci%bool = OpTypeBool 446fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 447fd4e5da5Sopenharmony_ci%true = OpConstantTrue %bool 448fd4e5da5Sopenharmony_ci%false = OpConstantFalse %bool 449fd4e5da5Sopenharmony_ci%zero = OpConstant %int 0 450fd4e5da5Sopenharmony_ci%int_1 = OpConstant %int 1 451fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void 452fd4e5da5Sopenharmony_ci%func_int = OpTypePointer Function %int 453fd4e5da5Sopenharmony_ci%paramfunc_type = OpTypeFunction %void %int %int 454fd4e5da5Sopenharmony_ci 455fd4e5da5Sopenharmony_ci%paramfunc = OpFunction %void None %paramfunc_type 456fd4e5da5Sopenharmony_ci%a = OpFunctionParameter %int 457fd4e5da5Sopenharmony_ci%placeholder = OpExtInst %void %extinst 123 %int_1 458fd4e5da5Sopenharmony_ci%b = OpFunctionParameter %int 459fd4e5da5Sopenharmony_ci%paramfunc_entry = OpLabel 460fd4e5da5Sopenharmony_ciOpReturn 461fd4e5da5Sopenharmony_ciOpFunctionEnd 462fd4e5da5Sopenharmony_ci 463fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func 464fd4e5da5Sopenharmony_ci%main_entry = OpLabel 465fd4e5da5Sopenharmony_ciOpReturn 466fd4e5da5Sopenharmony_ciOpFunctionEnd 467fd4e5da5Sopenharmony_ci)"; 468fd4e5da5Sopenharmony_ci 469fd4e5da5Sopenharmony_ci CompileSuccessfully(body); 470fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_LAYOUT, ValidateInstructions()); 471fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 472fd4e5da5Sopenharmony_ci HasSubstr("Non-semantic OpExtInst within function definition " 473fd4e5da5Sopenharmony_ci "must appear in a block")); 474fd4e5da5Sopenharmony_ci} 475fd4e5da5Sopenharmony_ci 476fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, NonSemanticAfterOpFunctionParameterGood) { 477fd4e5da5Sopenharmony_ci const std::string body = R"( 478fd4e5da5Sopenharmony_ciOpCapability Shader 479fd4e5da5Sopenharmony_ciOpExtension "SPV_KHR_non_semantic_info" 480fd4e5da5Sopenharmony_ci%extinst = OpExtInstImport "NonSemantic.Testing.Set" 481fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 482fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %main "main" 483fd4e5da5Sopenharmony_ciOpExecutionMode %main OriginUpperLeft 484fd4e5da5Sopenharmony_ci 485fd4e5da5Sopenharmony_ci%string = OpString "" 486fd4e5da5Sopenharmony_ci%void = OpTypeVoid 487fd4e5da5Sopenharmony_ci%bool = OpTypeBool 488fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 489fd4e5da5Sopenharmony_ci%true = OpConstantTrue %bool 490fd4e5da5Sopenharmony_ci%false = OpConstantFalse %bool 491fd4e5da5Sopenharmony_ci%zero = OpConstant %int 0 492fd4e5da5Sopenharmony_ci%int_1 = OpConstant %int 1 493fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void 494fd4e5da5Sopenharmony_ci%func_int = OpTypePointer Function %int 495fd4e5da5Sopenharmony_ci%paramfunc_type = OpTypeFunction %void %int %int 496fd4e5da5Sopenharmony_ci 497fd4e5da5Sopenharmony_ci%paramfunc = OpFunction %void None %paramfunc_type 498fd4e5da5Sopenharmony_ci%a = OpFunctionParameter %int 499fd4e5da5Sopenharmony_ci%b = OpFunctionParameter %int 500fd4e5da5Sopenharmony_ci%paramfunc_entry = OpLabel 501fd4e5da5Sopenharmony_ci%placeholder = OpExtInst %void %extinst 123 %int_1 502fd4e5da5Sopenharmony_ciOpReturn 503fd4e5da5Sopenharmony_ciOpFunctionEnd 504fd4e5da5Sopenharmony_ci 505fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func 506fd4e5da5Sopenharmony_ci%main_entry = OpLabel 507fd4e5da5Sopenharmony_ciOpReturn 508fd4e5da5Sopenharmony_ciOpFunctionEnd 509fd4e5da5Sopenharmony_ci)"; 510fd4e5da5Sopenharmony_ci 511fd4e5da5Sopenharmony_ci CompileSuccessfully(body); 512fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 513fd4e5da5Sopenharmony_ci} 514fd4e5da5Sopenharmony_ci 515fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, NonSemanticBetweenFunctionsGood) { 516fd4e5da5Sopenharmony_ci const std::string body = R"( 517fd4e5da5Sopenharmony_ciOpCapability Shader 518fd4e5da5Sopenharmony_ciOpExtension "SPV_KHR_non_semantic_info" 519fd4e5da5Sopenharmony_ci%extinst = OpExtInstImport "NonSemantic.Testing.Set" 520fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 521fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %main "main" 522fd4e5da5Sopenharmony_ciOpExecutionMode %main OriginUpperLeft 523fd4e5da5Sopenharmony_ci 524fd4e5da5Sopenharmony_ci%string = OpString "" 525fd4e5da5Sopenharmony_ci%void = OpTypeVoid 526fd4e5da5Sopenharmony_ci%bool = OpTypeBool 527fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 528fd4e5da5Sopenharmony_ci%true = OpConstantTrue %bool 529fd4e5da5Sopenharmony_ci%false = OpConstantFalse %bool 530fd4e5da5Sopenharmony_ci%zero = OpConstant %int 0 531fd4e5da5Sopenharmony_ci%int_1 = OpConstant %int 1 532fd4e5da5Sopenharmony_ci%func = OpTypeFunction %void 533fd4e5da5Sopenharmony_ci%func_int = OpTypePointer Function %int 534fd4e5da5Sopenharmony_ci%paramfunc_type = OpTypeFunction %void %int %int 535fd4e5da5Sopenharmony_ci 536fd4e5da5Sopenharmony_ci%paramfunc = OpFunction %void None %paramfunc_type 537fd4e5da5Sopenharmony_ci%a = OpFunctionParameter %int 538fd4e5da5Sopenharmony_ci%b = OpFunctionParameter %int 539fd4e5da5Sopenharmony_ci%paramfunc_entry = OpLabel 540fd4e5da5Sopenharmony_ciOpReturn 541fd4e5da5Sopenharmony_ciOpFunctionEnd 542fd4e5da5Sopenharmony_ci 543fd4e5da5Sopenharmony_ci%placeholder = OpExtInst %void %extinst 123 %int_1 544fd4e5da5Sopenharmony_ci 545fd4e5da5Sopenharmony_ci%main = OpFunction %void None %func 546fd4e5da5Sopenharmony_ci%main_entry = OpLabel 547fd4e5da5Sopenharmony_ciOpReturn 548fd4e5da5Sopenharmony_ciOpFunctionEnd 549fd4e5da5Sopenharmony_ci)"; 550fd4e5da5Sopenharmony_ci 551fd4e5da5Sopenharmony_ci CompileSuccessfully(body); 552fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 553fd4e5da5Sopenharmony_ci} 554fd4e5da5Sopenharmony_ci 555fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpVariableInFunctionGood) { 556fd4e5da5Sopenharmony_ci const std::string body = R"( 557fd4e5da5Sopenharmony_ciOpLine %string 1 1 558fd4e5da5Sopenharmony_ci%var = OpVariable %func_int Function 559fd4e5da5Sopenharmony_ciOpLine %string 2 1 560fd4e5da5Sopenharmony_ciOpNop 561fd4e5da5Sopenharmony_ciOpLine %string 3 1 562fd4e5da5Sopenharmony_ciOpNop 563fd4e5da5Sopenharmony_ci)"; 564fd4e5da5Sopenharmony_ci 565fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 566fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 567fd4e5da5Sopenharmony_ci} 568fd4e5da5Sopenharmony_ci 569fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpVariableInFunctionMultipleGood) { 570fd4e5da5Sopenharmony_ci const std::string body = R"( 571fd4e5da5Sopenharmony_ciOpLine %string 1 1 572fd4e5da5Sopenharmony_ci%1 = OpVariable %func_int Function 573fd4e5da5Sopenharmony_ciOpLine %string 2 1 574fd4e5da5Sopenharmony_ci%2 = OpVariable %func_int Function 575fd4e5da5Sopenharmony_ci%3 = OpVariable %func_int Function 576fd4e5da5Sopenharmony_ciOpNop 577fd4e5da5Sopenharmony_ciOpLine %string 3 1 578fd4e5da5Sopenharmony_ciOpNop 579fd4e5da5Sopenharmony_ci)"; 580fd4e5da5Sopenharmony_ci 581fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 582fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 583fd4e5da5Sopenharmony_ci} 584fd4e5da5Sopenharmony_ci 585fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpVariableInFunctionBad) { 586fd4e5da5Sopenharmony_ci const std::string body = R"( 587fd4e5da5Sopenharmony_ci%1 = OpUndef %int 588fd4e5da5Sopenharmony_ci%2 = OpVariable %func_int Function 589fd4e5da5Sopenharmony_ci)"; 590fd4e5da5Sopenharmony_ci 591fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 592fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 593fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 594fd4e5da5Sopenharmony_ci HasSubstr("All OpVariable instructions in a function must be the " 595fd4e5da5Sopenharmony_ci "first instructions")); 596fd4e5da5Sopenharmony_ci} 597fd4e5da5Sopenharmony_ci 598fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpVariableInFunctionMultipleBad) { 599fd4e5da5Sopenharmony_ci const std::string body = R"( 600fd4e5da5Sopenharmony_ciOpNop 601fd4e5da5Sopenharmony_ci%1 = OpVariable %func_int Function 602fd4e5da5Sopenharmony_ciOpLine %string 1 1 603fd4e5da5Sopenharmony_ci%2 = OpVariable %func_int Function 604fd4e5da5Sopenharmony_ciOpNop 605fd4e5da5Sopenharmony_ciOpNop 606fd4e5da5Sopenharmony_ciOpLine %string 2 1 607fd4e5da5Sopenharmony_ci%3 = OpVariable %func_int Function 608fd4e5da5Sopenharmony_ci)"; 609fd4e5da5Sopenharmony_ci 610fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 611fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 612fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 613fd4e5da5Sopenharmony_ci HasSubstr("All OpVariable instructions in a function must be the " 614fd4e5da5Sopenharmony_ci "first instructions")); 615fd4e5da5Sopenharmony_ci} 616fd4e5da5Sopenharmony_ci 617fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpLoopMergePreceedsOpBranchSuccess) { 618fd4e5da5Sopenharmony_ci const std::string body = R"( 619fd4e5da5Sopenharmony_ciOpBranch %loop 620fd4e5da5Sopenharmony_ci%loop = OpLabel 621fd4e5da5Sopenharmony_ciOpLoopMerge %end %loop None 622fd4e5da5Sopenharmony_ciOpBranch %loop 623fd4e5da5Sopenharmony_ci%end = OpLabel 624fd4e5da5Sopenharmony_ci)"; 625fd4e5da5Sopenharmony_ci 626fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 627fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 628fd4e5da5Sopenharmony_ci} 629fd4e5da5Sopenharmony_ci 630fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpLoopMergePreceedsOpBranchConditionalSuccess) { 631fd4e5da5Sopenharmony_ci const std::string body = R"( 632fd4e5da5Sopenharmony_ciOpBranch %loop 633fd4e5da5Sopenharmony_ci%loop = OpLabel 634fd4e5da5Sopenharmony_ciOpLoopMerge %end %loop None 635fd4e5da5Sopenharmony_ciOpBranchConditional %true %loop %end 636fd4e5da5Sopenharmony_ci%end = OpLabel 637fd4e5da5Sopenharmony_ci)"; 638fd4e5da5Sopenharmony_ci 639fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 640fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 641fd4e5da5Sopenharmony_ci} 642fd4e5da5Sopenharmony_ci 643fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpLoopMergePreceedsBadOpFail) { 644fd4e5da5Sopenharmony_ci const std::string body = R"( 645fd4e5da5Sopenharmony_ciOpBranch %loop 646fd4e5da5Sopenharmony_ci%loop = OpLabel 647fd4e5da5Sopenharmony_ciOpLoopMerge %end %loop None 648fd4e5da5Sopenharmony_ciOpNop 649fd4e5da5Sopenharmony_ciOpBranchConditional %true %loop %end 650fd4e5da5Sopenharmony_ci%end = OpLabel 651fd4e5da5Sopenharmony_ci)"; 652fd4e5da5Sopenharmony_ci 653fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 654fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 655fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 656fd4e5da5Sopenharmony_ci HasSubstr("OpLoopMerge must immediately precede either an " 657fd4e5da5Sopenharmony_ci "OpBranch or OpBranchConditional instruction.")); 658fd4e5da5Sopenharmony_ci} 659fd4e5da5Sopenharmony_ci 660fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpSelectionMergePreceedsOpBranchConditionalSuccess) { 661fd4e5da5Sopenharmony_ci const std::string body = R"( 662fd4e5da5Sopenharmony_ciOpSelectionMerge %end_label None 663fd4e5da5Sopenharmony_ciOpBranchConditional %true %true_label %false_label 664fd4e5da5Sopenharmony_ci%true_label = OpLabel 665fd4e5da5Sopenharmony_ciOpBranch %end_label 666fd4e5da5Sopenharmony_ci%false_label = OpLabel 667fd4e5da5Sopenharmony_ciOpBranch %end_label 668fd4e5da5Sopenharmony_ci%end_label = OpLabel 669fd4e5da5Sopenharmony_ci)"; 670fd4e5da5Sopenharmony_ci 671fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 672fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 673fd4e5da5Sopenharmony_ci} 674fd4e5da5Sopenharmony_ci 675fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpSelectionMergePreceedsOpSwitchSuccess) { 676fd4e5da5Sopenharmony_ci const std::string body = R"( 677fd4e5da5Sopenharmony_ciOpSelectionMerge %merge None 678fd4e5da5Sopenharmony_ciOpSwitch %zero %merge 0 %label 679fd4e5da5Sopenharmony_ci%label = OpLabel 680fd4e5da5Sopenharmony_ciOpBranch %merge 681fd4e5da5Sopenharmony_ci%merge = OpLabel 682fd4e5da5Sopenharmony_ci)"; 683fd4e5da5Sopenharmony_ci 684fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 685fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 686fd4e5da5Sopenharmony_ci} 687fd4e5da5Sopenharmony_ci 688fd4e5da5Sopenharmony_ciTEST_F(ValidateAdjacency, OpSelectionMergePreceedsBadOpFail) { 689fd4e5da5Sopenharmony_ci const std::string body = R"( 690fd4e5da5Sopenharmony_ciOpSelectionMerge %merge None 691fd4e5da5Sopenharmony_ciOpNop 692fd4e5da5Sopenharmony_ciOpSwitch %zero %merge 0 %label 693fd4e5da5Sopenharmony_ci%label = OpLabel 694fd4e5da5Sopenharmony_ciOpBranch %merge 695fd4e5da5Sopenharmony_ci%merge = OpLabel 696fd4e5da5Sopenharmony_ci)"; 697fd4e5da5Sopenharmony_ci 698fd4e5da5Sopenharmony_ci CompileSuccessfully(GenerateShaderCode(body)); 699fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 700fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 701fd4e5da5Sopenharmony_ci HasSubstr("OpSelectionMerge must immediately precede either an " 702fd4e5da5Sopenharmony_ci "OpBranchConditional or OpSwitch instruction")); 703fd4e5da5Sopenharmony_ci} 704fd4e5da5Sopenharmony_ci 705fd4e5da5Sopenharmony_ci} // namespace 706fd4e5da5Sopenharmony_ci} // namespace val 707fd4e5da5Sopenharmony_ci} // namespace spvtools 708