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 Control Flow Graph 16fd4e5da5Sopenharmony_ci 17fd4e5da5Sopenharmony_ci#include <array> 18fd4e5da5Sopenharmony_ci#include <functional> 19fd4e5da5Sopenharmony_ci#include <sstream> 20fd4e5da5Sopenharmony_ci#include <string> 21fd4e5da5Sopenharmony_ci#include <utility> 22fd4e5da5Sopenharmony_ci#include <vector> 23fd4e5da5Sopenharmony_ci 24fd4e5da5Sopenharmony_ci#include "gmock/gmock.h" 25fd4e5da5Sopenharmony_ci#include "source/spirv_target_env.h" 26fd4e5da5Sopenharmony_ci#include "source/val/validate.h" 27fd4e5da5Sopenharmony_ci#include "test/test_fixture.h" 28fd4e5da5Sopenharmony_ci#include "test/unit_spirv.h" 29fd4e5da5Sopenharmony_ci#include "test/val/val_fixtures.h" 30fd4e5da5Sopenharmony_ci 31fd4e5da5Sopenharmony_cinamespace spvtools { 32fd4e5da5Sopenharmony_cinamespace val { 33fd4e5da5Sopenharmony_cinamespace { 34fd4e5da5Sopenharmony_ci 35fd4e5da5Sopenharmony_ciusing ::testing::HasSubstr; 36fd4e5da5Sopenharmony_ciusing ::testing::MatchesRegex; 37fd4e5da5Sopenharmony_ci 38fd4e5da5Sopenharmony_ciusing ValidateCFG = spvtest::ValidateBase<spv::Capability>; 39fd4e5da5Sopenharmony_ciusing spvtest::ScopedContext; 40fd4e5da5Sopenharmony_ci 41fd4e5da5Sopenharmony_cistd::string nameOps() { return ""; } 42fd4e5da5Sopenharmony_ci 43fd4e5da5Sopenharmony_citemplate <typename... Args> 44fd4e5da5Sopenharmony_cistd::string nameOps(std::pair<std::string, std::string> head, Args... names) { 45fd4e5da5Sopenharmony_ci return "OpName %" + head.first + " \"" + head.second + "\"\n" + 46fd4e5da5Sopenharmony_ci nameOps(names...); 47fd4e5da5Sopenharmony_ci} 48fd4e5da5Sopenharmony_ci 49fd4e5da5Sopenharmony_citemplate <typename... Args> 50fd4e5da5Sopenharmony_cistd::string nameOps(std::string head, Args... names) { 51fd4e5da5Sopenharmony_ci return "OpName %" + head + " \"" + head + "\"\n" + nameOps(names...); 52fd4e5da5Sopenharmony_ci} 53fd4e5da5Sopenharmony_ci 54fd4e5da5Sopenharmony_ci/// This class allows the easy creation of complex control flow without writing 55fd4e5da5Sopenharmony_ci/// SPIR-V. This class is used in the test cases below. 56fd4e5da5Sopenharmony_ciclass Block { 57fd4e5da5Sopenharmony_ci std::string label_; 58fd4e5da5Sopenharmony_ci std::string body_; 59fd4e5da5Sopenharmony_ci spv::Op type_; 60fd4e5da5Sopenharmony_ci std::vector<Block> successors_; 61fd4e5da5Sopenharmony_ci 62fd4e5da5Sopenharmony_ci public: 63fd4e5da5Sopenharmony_ci /// Creates a Block with a given label 64fd4e5da5Sopenharmony_ci /// 65fd4e5da5Sopenharmony_ci /// @param[in]: label the label id of the block 66fd4e5da5Sopenharmony_ci /// @param[in]: type the branch instruction that ends the block 67fd4e5da5Sopenharmony_ci explicit Block(std::string label, spv::Op type = spv::Op::OpBranch) 68fd4e5da5Sopenharmony_ci : label_(label), body_(), type_(type), successors_() {} 69fd4e5da5Sopenharmony_ci 70fd4e5da5Sopenharmony_ci /// Sets the instructions which will appear in the body of the block 71fd4e5da5Sopenharmony_ci Block& SetBody(std::string body) { 72fd4e5da5Sopenharmony_ci body_ = body; 73fd4e5da5Sopenharmony_ci return *this; 74fd4e5da5Sopenharmony_ci } 75fd4e5da5Sopenharmony_ci 76fd4e5da5Sopenharmony_ci Block& AppendBody(std::string body) { 77fd4e5da5Sopenharmony_ci body_ += body; 78fd4e5da5Sopenharmony_ci return *this; 79fd4e5da5Sopenharmony_ci } 80fd4e5da5Sopenharmony_ci 81fd4e5da5Sopenharmony_ci /// Converts the block into a SPIR-V string 82fd4e5da5Sopenharmony_ci operator std::string() { 83fd4e5da5Sopenharmony_ci std::stringstream out; 84fd4e5da5Sopenharmony_ci out << std::setw(8) << "%" + label_ + " = OpLabel \n"; 85fd4e5da5Sopenharmony_ci if (!body_.empty()) { 86fd4e5da5Sopenharmony_ci out << body_; 87fd4e5da5Sopenharmony_ci } 88fd4e5da5Sopenharmony_ci 89fd4e5da5Sopenharmony_ci switch (type_) { 90fd4e5da5Sopenharmony_ci case spv::Op::OpBranchConditional: 91fd4e5da5Sopenharmony_ci out << "OpBranchConditional %cond "; 92fd4e5da5Sopenharmony_ci for (Block& b : successors_) { 93fd4e5da5Sopenharmony_ci out << "%" + b.label_ + " "; 94fd4e5da5Sopenharmony_ci } 95fd4e5da5Sopenharmony_ci break; 96fd4e5da5Sopenharmony_ci case spv::Op::OpSwitch: { 97fd4e5da5Sopenharmony_ci out << "OpSwitch %one %" + successors_.front().label_; 98fd4e5da5Sopenharmony_ci std::stringstream ss; 99fd4e5da5Sopenharmony_ci for (size_t i = 1; i < successors_.size(); i++) { 100fd4e5da5Sopenharmony_ci ss << " " << i << " %" << successors_[i].label_; 101fd4e5da5Sopenharmony_ci } 102fd4e5da5Sopenharmony_ci out << ss.str(); 103fd4e5da5Sopenharmony_ci } break; 104fd4e5da5Sopenharmony_ci case spv::Op::OpLoopMerge: { 105fd4e5da5Sopenharmony_ci assert(successors_.size() == 2); 106fd4e5da5Sopenharmony_ci out << "OpLoopMerge %" + successors_[0].label_ + " %" + 107fd4e5da5Sopenharmony_ci successors_[0].label_ + "None"; 108fd4e5da5Sopenharmony_ci } break; 109fd4e5da5Sopenharmony_ci 110fd4e5da5Sopenharmony_ci case spv::Op::OpReturn: 111fd4e5da5Sopenharmony_ci assert(successors_.size() == 0); 112fd4e5da5Sopenharmony_ci out << "OpReturn\n"; 113fd4e5da5Sopenharmony_ci break; 114fd4e5da5Sopenharmony_ci case spv::Op::OpUnreachable: 115fd4e5da5Sopenharmony_ci assert(successors_.size() == 0); 116fd4e5da5Sopenharmony_ci out << "OpUnreachable\n"; 117fd4e5da5Sopenharmony_ci break; 118fd4e5da5Sopenharmony_ci case spv::Op::OpBranch: 119fd4e5da5Sopenharmony_ci assert(successors_.size() == 1); 120fd4e5da5Sopenharmony_ci out << "OpBranch %" + successors_.front().label_; 121fd4e5da5Sopenharmony_ci break; 122fd4e5da5Sopenharmony_ci case spv::Op::OpKill: 123fd4e5da5Sopenharmony_ci assert(successors_.size() == 0); 124fd4e5da5Sopenharmony_ci out << "OpKill\n"; 125fd4e5da5Sopenharmony_ci break; 126fd4e5da5Sopenharmony_ci default: 127fd4e5da5Sopenharmony_ci assert(1 == 0 && "Unhandled"); 128fd4e5da5Sopenharmony_ci } 129fd4e5da5Sopenharmony_ci out << "\n"; 130fd4e5da5Sopenharmony_ci 131fd4e5da5Sopenharmony_ci return out.str(); 132fd4e5da5Sopenharmony_ci } 133fd4e5da5Sopenharmony_ci friend Block& operator>>(Block& curr, std::vector<Block> successors); 134fd4e5da5Sopenharmony_ci friend Block& operator>>(Block& lhs, Block& successor); 135fd4e5da5Sopenharmony_ci}; 136fd4e5da5Sopenharmony_ci 137fd4e5da5Sopenharmony_ci/// Assigns the successors for the Block on the lhs 138fd4e5da5Sopenharmony_ciBlock& operator>>(Block& lhs, std::vector<Block> successors) { 139fd4e5da5Sopenharmony_ci if (lhs.type_ == spv::Op::OpBranchConditional) { 140fd4e5da5Sopenharmony_ci assert(successors.size() == 2); 141fd4e5da5Sopenharmony_ci } else if (lhs.type_ == spv::Op::OpSwitch) { 142fd4e5da5Sopenharmony_ci assert(successors.size() > 1); 143fd4e5da5Sopenharmony_ci } 144fd4e5da5Sopenharmony_ci lhs.successors_ = successors; 145fd4e5da5Sopenharmony_ci return lhs; 146fd4e5da5Sopenharmony_ci} 147fd4e5da5Sopenharmony_ci 148fd4e5da5Sopenharmony_ci/// Assigns the successor for the Block on the lhs 149fd4e5da5Sopenharmony_ciBlock& operator>>(Block& lhs, Block& successor) { 150fd4e5da5Sopenharmony_ci assert(lhs.type_ == spv::Op::OpBranch); 151fd4e5da5Sopenharmony_ci lhs.successors_.push_back(successor); 152fd4e5da5Sopenharmony_ci return lhs; 153fd4e5da5Sopenharmony_ci} 154fd4e5da5Sopenharmony_ci 155fd4e5da5Sopenharmony_ciconst std::string& GetDefaultHeader(spv::Capability cap) { 156fd4e5da5Sopenharmony_ci static const std::string shader_header = 157fd4e5da5Sopenharmony_ci "OpCapability Shader\n" 158fd4e5da5Sopenharmony_ci "OpCapability Linkage\n" 159fd4e5da5Sopenharmony_ci "OpMemoryModel Logical GLSL450\n"; 160fd4e5da5Sopenharmony_ci 161fd4e5da5Sopenharmony_ci static const std::string kernel_header = 162fd4e5da5Sopenharmony_ci "OpCapability Kernel\n" 163fd4e5da5Sopenharmony_ci "OpCapability Linkage\n" 164fd4e5da5Sopenharmony_ci "OpMemoryModel Logical OpenCL\n"; 165fd4e5da5Sopenharmony_ci 166fd4e5da5Sopenharmony_ci return (cap == spv::Capability::Shader) ? shader_header : kernel_header; 167fd4e5da5Sopenharmony_ci} 168fd4e5da5Sopenharmony_ci 169fd4e5da5Sopenharmony_ciconst std::string& types_consts() { 170fd4e5da5Sopenharmony_ci static const std::string types = 171fd4e5da5Sopenharmony_ci "%voidt = OpTypeVoid\n" 172fd4e5da5Sopenharmony_ci "%boolt = OpTypeBool\n" 173fd4e5da5Sopenharmony_ci "%intt = OpTypeInt 32 0\n" 174fd4e5da5Sopenharmony_ci "%one = OpConstant %intt 1\n" 175fd4e5da5Sopenharmony_ci "%two = OpConstant %intt 2\n" 176fd4e5da5Sopenharmony_ci "%ptrt = OpTypePointer Function %intt\n" 177fd4e5da5Sopenharmony_ci "%funct = OpTypeFunction %voidt\n"; 178fd4e5da5Sopenharmony_ci return types; 179fd4e5da5Sopenharmony_ci} 180fd4e5da5Sopenharmony_ci 181fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P(StructuredControlFlow, ValidateCFG, 182fd4e5da5Sopenharmony_ci ::testing::Values(spv::Capability::Shader, 183fd4e5da5Sopenharmony_ci spv::Capability::Kernel)); 184fd4e5da5Sopenharmony_ci 185fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, LoopReachableFromEntryButNeverLeadingToReturn) { 186fd4e5da5Sopenharmony_ci // In this case, the loop is reachable from a node without a predecessor, 187fd4e5da5Sopenharmony_ci // but never reaches a node with a return. 188fd4e5da5Sopenharmony_ci // 189fd4e5da5Sopenharmony_ci // This motivates the need for the pseudo-exit node to have a node 190fd4e5da5Sopenharmony_ci // from a cycle in its predecessors list. Otherwise the validator's 191fd4e5da5Sopenharmony_ci // post-dominance calculation will go into an infinite loop. 192fd4e5da5Sopenharmony_ci // 193fd4e5da5Sopenharmony_ci // For more motivation, see 194fd4e5da5Sopenharmony_ci // https://github.com/KhronosGroup/SPIRV-Tools/issues/279 195fd4e5da5Sopenharmony_ci std::string str = R"( 196fd4e5da5Sopenharmony_ci OpCapability Shader 197fd4e5da5Sopenharmony_ci OpCapability Linkage 198fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 199fd4e5da5Sopenharmony_ci 200fd4e5da5Sopenharmony_ci OpName %entry "entry" 201fd4e5da5Sopenharmony_ci OpName %loop "loop" 202fd4e5da5Sopenharmony_ci OpName %exit "exit" 203fd4e5da5Sopenharmony_ci 204fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid 205fd4e5da5Sopenharmony_ci%funct = OpTypeFunction %voidt 206fd4e5da5Sopenharmony_ci 207fd4e5da5Sopenharmony_ci%main = OpFunction %voidt None %funct 208fd4e5da5Sopenharmony_ci%entry = OpLabel 209fd4e5da5Sopenharmony_ci OpBranch %loop 210fd4e5da5Sopenharmony_ci%loop = OpLabel 211fd4e5da5Sopenharmony_ci OpLoopMerge %exit %loop None 212fd4e5da5Sopenharmony_ci OpBranch %loop 213fd4e5da5Sopenharmony_ci%exit = OpLabel 214fd4e5da5Sopenharmony_ci OpReturn 215fd4e5da5Sopenharmony_ci OpFunctionEnd 216fd4e5da5Sopenharmony_ci )"; 217fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 218fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()) << str; 219fd4e5da5Sopenharmony_ci} 220fd4e5da5Sopenharmony_ci 221fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, LoopUnreachableFromEntryButLeadingToReturn) { 222fd4e5da5Sopenharmony_ci // In this case, the loop is not reachable from a node without a 223fd4e5da5Sopenharmony_ci // predecessor, but eventually reaches a node with a return. 224fd4e5da5Sopenharmony_ci // 225fd4e5da5Sopenharmony_ci // This motivates the need for the pseudo-entry node to have a node 226fd4e5da5Sopenharmony_ci // from a cycle in its successors list. Otherwise the validator's 227fd4e5da5Sopenharmony_ci // dominance calculation will go into an infinite loop. 228fd4e5da5Sopenharmony_ci // 229fd4e5da5Sopenharmony_ci // For more motivation, see 230fd4e5da5Sopenharmony_ci // https://github.com/KhronosGroup/SPIRV-Tools/issues/279 231fd4e5da5Sopenharmony_ci // Before that fix, we'd have an infinite loop when calculating 232fd4e5da5Sopenharmony_ci // post-dominators. 233fd4e5da5Sopenharmony_ci std::string str = R"( 234fd4e5da5Sopenharmony_ci OpCapability Shader 235fd4e5da5Sopenharmony_ci OpCapability Linkage 236fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 237fd4e5da5Sopenharmony_ci 238fd4e5da5Sopenharmony_ci OpName %entry "entry" 239fd4e5da5Sopenharmony_ci OpName %loop "loop" 240fd4e5da5Sopenharmony_ci OpName %cont "cont" 241fd4e5da5Sopenharmony_ci OpName %exit "exit" 242fd4e5da5Sopenharmony_ci 243fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid 244fd4e5da5Sopenharmony_ci%funct = OpTypeFunction %voidt 245fd4e5da5Sopenharmony_ci%boolt = OpTypeBool 246fd4e5da5Sopenharmony_ci%false = OpConstantFalse %boolt 247fd4e5da5Sopenharmony_ci 248fd4e5da5Sopenharmony_ci%main = OpFunction %voidt None %funct 249fd4e5da5Sopenharmony_ci%entry = OpLabel 250fd4e5da5Sopenharmony_ci OpReturn 251fd4e5da5Sopenharmony_ci 252fd4e5da5Sopenharmony_ci%loop = OpLabel 253fd4e5da5Sopenharmony_ci OpLoopMerge %exit %cont None 254fd4e5da5Sopenharmony_ci OpBranch %cont 255fd4e5da5Sopenharmony_ci 256fd4e5da5Sopenharmony_ci%cont = OpLabel 257fd4e5da5Sopenharmony_ci OpBranchConditional %false %loop %exit 258fd4e5da5Sopenharmony_ci 259fd4e5da5Sopenharmony_ci%exit = OpLabel 260fd4e5da5Sopenharmony_ci OpReturn 261fd4e5da5Sopenharmony_ci OpFunctionEnd 262fd4e5da5Sopenharmony_ci )"; 263fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 264fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()) 265fd4e5da5Sopenharmony_ci << str << getDiagnosticString(); 266fd4e5da5Sopenharmony_ci} 267fd4e5da5Sopenharmony_ci 268fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, Simple) { 269fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 270fd4e5da5Sopenharmony_ci Block entry("entry"); 271fd4e5da5Sopenharmony_ci Block loop("loop", spv::Op::OpBranchConditional); 272fd4e5da5Sopenharmony_ci Block cont("cont"); 273fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 274fd4e5da5Sopenharmony_ci 275fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 276fd4e5da5Sopenharmony_ci if (is_shader) { 277fd4e5da5Sopenharmony_ci loop.SetBody("OpLoopMerge %merge %cont None\n"); 278fd4e5da5Sopenharmony_ci } 279fd4e5da5Sopenharmony_ci 280fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 281fd4e5da5Sopenharmony_ci nameOps("loop", "entry", "cont", "merge", 282fd4e5da5Sopenharmony_ci std::make_pair("func", "Main")) + 283fd4e5da5Sopenharmony_ci types_consts() + 284fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 285fd4e5da5Sopenharmony_ci 286fd4e5da5Sopenharmony_ci str += entry >> loop; 287fd4e5da5Sopenharmony_ci str += loop >> std::vector<Block>({cont, merge}); 288fd4e5da5Sopenharmony_ci str += cont >> loop; 289fd4e5da5Sopenharmony_ci str += merge; 290fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 291fd4e5da5Sopenharmony_ci 292fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 293fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 294fd4e5da5Sopenharmony_ci} 295fd4e5da5Sopenharmony_ci 296fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, Variable) { 297fd4e5da5Sopenharmony_ci Block entry("entry"); 298fd4e5da5Sopenharmony_ci Block cont("cont"); 299fd4e5da5Sopenharmony_ci Block exit("exit", spv::Op::OpReturn); 300fd4e5da5Sopenharmony_ci 301fd4e5da5Sopenharmony_ci entry.SetBody("%var = OpVariable %ptrt Function\n"); 302fd4e5da5Sopenharmony_ci 303fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 304fd4e5da5Sopenharmony_ci nameOps(std::make_pair("func", "Main")) + types_consts() + 305fd4e5da5Sopenharmony_ci " %func = OpFunction %voidt None %funct\n"; 306fd4e5da5Sopenharmony_ci str += entry >> cont; 307fd4e5da5Sopenharmony_ci str += cont >> exit; 308fd4e5da5Sopenharmony_ci str += exit; 309fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 310fd4e5da5Sopenharmony_ci 311fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 312fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 313fd4e5da5Sopenharmony_ci} 314fd4e5da5Sopenharmony_ci 315fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, VariableNotInFirstBlockBad) { 316fd4e5da5Sopenharmony_ci Block entry("entry"); 317fd4e5da5Sopenharmony_ci Block cont("cont"); 318fd4e5da5Sopenharmony_ci Block exit("exit", spv::Op::OpReturn); 319fd4e5da5Sopenharmony_ci 320fd4e5da5Sopenharmony_ci // This operation should only be performed in the entry block 321fd4e5da5Sopenharmony_ci cont.SetBody("%var = OpVariable %ptrt Function\n"); 322fd4e5da5Sopenharmony_ci 323fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 324fd4e5da5Sopenharmony_ci nameOps(std::make_pair("func", "Main")) + types_consts() + 325fd4e5da5Sopenharmony_ci " %func = OpFunction %voidt None %funct\n"; 326fd4e5da5Sopenharmony_ci 327fd4e5da5Sopenharmony_ci str += entry >> cont; 328fd4e5da5Sopenharmony_ci str += cont >> exit; 329fd4e5da5Sopenharmony_ci str += exit; 330fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 331fd4e5da5Sopenharmony_ci 332fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 333fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 334fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 335fd4e5da5Sopenharmony_ci HasSubstr("All OpVariable instructions in a function must be the " 336fd4e5da5Sopenharmony_ci "first instructions in the first block")); 337fd4e5da5Sopenharmony_ci} 338fd4e5da5Sopenharmony_ci 339fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, BlockSelfLoopIsOk) { 340fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 341fd4e5da5Sopenharmony_ci Block entry("entry"); 342fd4e5da5Sopenharmony_ci Block loop("loop", spv::Op::OpBranchConditional); 343fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 344fd4e5da5Sopenharmony_ci 345fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 346fd4e5da5Sopenharmony_ci if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n"); 347fd4e5da5Sopenharmony_ci 348fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 349fd4e5da5Sopenharmony_ci nameOps("loop", "merge", std::make_pair("func", "Main")) + 350fd4e5da5Sopenharmony_ci types_consts() + 351fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 352fd4e5da5Sopenharmony_ci 353fd4e5da5Sopenharmony_ci str += entry >> loop; 354fd4e5da5Sopenharmony_ci // loop branches to itself, but does not trigger an error. 355fd4e5da5Sopenharmony_ci str += loop >> std::vector<Block>({merge, loop}); 356fd4e5da5Sopenharmony_ci str += merge; 357fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 358fd4e5da5Sopenharmony_ci 359fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 360fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString(); 361fd4e5da5Sopenharmony_ci} 362fd4e5da5Sopenharmony_ci 363fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, BlockAppearsBeforeDominatorBad) { 364fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 365fd4e5da5Sopenharmony_ci Block entry("entry"); 366fd4e5da5Sopenharmony_ci Block cont("cont"); 367fd4e5da5Sopenharmony_ci Block branch("branch", spv::Op::OpBranchConditional); 368fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 369fd4e5da5Sopenharmony_ci 370fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 371fd4e5da5Sopenharmony_ci if (is_shader) branch.SetBody("OpSelectionMerge %merge None\n"); 372fd4e5da5Sopenharmony_ci 373fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 374fd4e5da5Sopenharmony_ci nameOps("cont", "branch", std::make_pair("func", "Main")) + 375fd4e5da5Sopenharmony_ci types_consts() + 376fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 377fd4e5da5Sopenharmony_ci 378fd4e5da5Sopenharmony_ci str += entry >> branch; 379fd4e5da5Sopenharmony_ci str += cont >> merge; // cont appears before its dominator 380fd4e5da5Sopenharmony_ci str += branch >> std::vector<Block>({cont, merge}); 381fd4e5da5Sopenharmony_ci str += merge; 382fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 383fd4e5da5Sopenharmony_ci 384fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 385fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 386fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 387fd4e5da5Sopenharmony_ci MatchesRegex("Block '.\\[%cont\\]' appears in the binary " 388fd4e5da5Sopenharmony_ci "before its dominator '.\\[%branch\\]'\n" 389fd4e5da5Sopenharmony_ci " %branch = OpLabel\n")); 390fd4e5da5Sopenharmony_ci} 391fd4e5da5Sopenharmony_ci 392fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, MergeBlockTargetedByMultipleHeaderBlocksBad) { 393fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 394fd4e5da5Sopenharmony_ci Block entry("entry"); 395fd4e5da5Sopenharmony_ci Block loop("loop"); 396fd4e5da5Sopenharmony_ci Block selection("selection", spv::Op::OpBranchConditional); 397fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 398fd4e5da5Sopenharmony_ci 399fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 400fd4e5da5Sopenharmony_ci if (is_shader) loop.SetBody(" OpLoopMerge %merge %loop None\n"); 401fd4e5da5Sopenharmony_ci 402fd4e5da5Sopenharmony_ci // cannot share the same merge 403fd4e5da5Sopenharmony_ci if (is_shader) selection.SetBody("OpSelectionMerge %merge None\n"); 404fd4e5da5Sopenharmony_ci 405fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 406fd4e5da5Sopenharmony_ci nameOps("merge", std::make_pair("func", "Main")) + 407fd4e5da5Sopenharmony_ci types_consts() + 408fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 409fd4e5da5Sopenharmony_ci 410fd4e5da5Sopenharmony_ci str += entry >> loop; 411fd4e5da5Sopenharmony_ci str += loop >> selection; 412fd4e5da5Sopenharmony_ci str += selection >> std::vector<Block>({loop, merge}); 413fd4e5da5Sopenharmony_ci str += merge; 414fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 415fd4e5da5Sopenharmony_ci 416fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 417fd4e5da5Sopenharmony_ci if (is_shader) { 418fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 419fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 420fd4e5da5Sopenharmony_ci MatchesRegex("Block '.\\[%merge\\]' is already a merge block " 421fd4e5da5Sopenharmony_ci "for another header\n" 422fd4e5da5Sopenharmony_ci " %Main = OpFunction %void None %9\n")); 423fd4e5da5Sopenharmony_ci } else { 424fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 425fd4e5da5Sopenharmony_ci } 426fd4e5da5Sopenharmony_ci} 427fd4e5da5Sopenharmony_ci 428fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, MergeBlockTargetedByMultipleHeaderBlocksSelectionBad) { 429fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 430fd4e5da5Sopenharmony_ci Block entry("entry"); 431fd4e5da5Sopenharmony_ci Block loop("loop", spv::Op::OpBranchConditional); 432fd4e5da5Sopenharmony_ci Block selection("selection", spv::Op::OpBranchConditional); 433fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 434fd4e5da5Sopenharmony_ci 435fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 436fd4e5da5Sopenharmony_ci if (is_shader) selection.SetBody(" OpSelectionMerge %merge None\n"); 437fd4e5da5Sopenharmony_ci 438fd4e5da5Sopenharmony_ci // cannot share the same merge 439fd4e5da5Sopenharmony_ci if (is_shader) loop.SetBody(" OpLoopMerge %merge %loop None\n"); 440fd4e5da5Sopenharmony_ci 441fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 442fd4e5da5Sopenharmony_ci nameOps("merge", std::make_pair("func", "Main")) + 443fd4e5da5Sopenharmony_ci types_consts() + 444fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 445fd4e5da5Sopenharmony_ci 446fd4e5da5Sopenharmony_ci str += entry >> selection; 447fd4e5da5Sopenharmony_ci str += selection >> std::vector<Block>({merge, loop}); 448fd4e5da5Sopenharmony_ci str += loop >> std::vector<Block>({loop, merge}); 449fd4e5da5Sopenharmony_ci str += merge; 450fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 451fd4e5da5Sopenharmony_ci 452fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 453fd4e5da5Sopenharmony_ci if (is_shader) { 454fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 455fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 456fd4e5da5Sopenharmony_ci MatchesRegex("Block '.\\[%merge\\]' is already a merge block " 457fd4e5da5Sopenharmony_ci "for another header\n" 458fd4e5da5Sopenharmony_ci " %Main = OpFunction %void None %9\n")); 459fd4e5da5Sopenharmony_ci } else { 460fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 461fd4e5da5Sopenharmony_ci } 462fd4e5da5Sopenharmony_ci} 463fd4e5da5Sopenharmony_ci 464fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, BranchTargetFirstBlockBadSinceEntryBlock) { 465fd4e5da5Sopenharmony_ci Block entry("entry"); 466fd4e5da5Sopenharmony_ci Block bad("bad"); 467fd4e5da5Sopenharmony_ci Block end("end", spv::Op::OpReturn); 468fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 469fd4e5da5Sopenharmony_ci nameOps("entry", "bad", std::make_pair("func", "Main")) + 470fd4e5da5Sopenharmony_ci types_consts() + 471fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 472fd4e5da5Sopenharmony_ci 473fd4e5da5Sopenharmony_ci str += entry >> bad; 474fd4e5da5Sopenharmony_ci str += bad >> entry; // Cannot target entry block 475fd4e5da5Sopenharmony_ci str += end; 476fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 477fd4e5da5Sopenharmony_ci 478fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 479fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 480fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 481fd4e5da5Sopenharmony_ci MatchesRegex("First block '.\\[%entry\\]' of function " 482fd4e5da5Sopenharmony_ci "'.\\[%Main\\]' is targeted by block '.\\[%bad\\]'\n" 483fd4e5da5Sopenharmony_ci " %Main = OpFunction %void None %10\n")); 484fd4e5da5Sopenharmony_ci} 485fd4e5da5Sopenharmony_ci 486fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, BranchTargetFirstBlockBadSinceValue) { 487fd4e5da5Sopenharmony_ci Block entry("entry"); 488fd4e5da5Sopenharmony_ci entry.SetBody("%undef = OpUndef %boolt\n"); 489fd4e5da5Sopenharmony_ci Block bad("bad"); 490fd4e5da5Sopenharmony_ci Block end("end", spv::Op::OpReturn); 491fd4e5da5Sopenharmony_ci Block badvalue("undef"); // This references the OpUndef. 492fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 493fd4e5da5Sopenharmony_ci nameOps("entry", "bad", std::make_pair("func", "Main")) + 494fd4e5da5Sopenharmony_ci types_consts() + 495fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 496fd4e5da5Sopenharmony_ci 497fd4e5da5Sopenharmony_ci str += entry >> bad; 498fd4e5da5Sopenharmony_ci str += 499fd4e5da5Sopenharmony_ci bad >> badvalue; // Check branch to a function value (it's not a block!) 500fd4e5da5Sopenharmony_ci str += end; 501fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 502fd4e5da5Sopenharmony_ci 503fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 504fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 505fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 506fd4e5da5Sopenharmony_ci HasSubstr("'Target Label' operands for OpBranch must " 507fd4e5da5Sopenharmony_ci "be the ID of an OpLabel instruction")); 508fd4e5da5Sopenharmony_ci} 509fd4e5da5Sopenharmony_ci 510fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, BranchConditionalTrueTargetFirstBlockBad) { 511fd4e5da5Sopenharmony_ci Block entry("entry"); 512fd4e5da5Sopenharmony_ci Block bad("bad", spv::Op::OpBranchConditional); 513fd4e5da5Sopenharmony_ci Block exit("exit", spv::Op::OpReturn); 514fd4e5da5Sopenharmony_ci 515fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 516fd4e5da5Sopenharmony_ci bad.SetBody(" OpLoopMerge %entry %exit None\n"); 517fd4e5da5Sopenharmony_ci 518fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 519fd4e5da5Sopenharmony_ci nameOps("entry", "bad", std::make_pair("func", "Main")) + 520fd4e5da5Sopenharmony_ci types_consts() + 521fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 522fd4e5da5Sopenharmony_ci 523fd4e5da5Sopenharmony_ci str += entry >> bad; 524fd4e5da5Sopenharmony_ci str += bad >> std::vector<Block>({entry, exit}); // cannot target entry block 525fd4e5da5Sopenharmony_ci str += exit; 526fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 527fd4e5da5Sopenharmony_ci 528fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 529fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 530fd4e5da5Sopenharmony_ci EXPECT_THAT( 531fd4e5da5Sopenharmony_ci getDiagnosticString(), 532fd4e5da5Sopenharmony_ci MatchesRegex("First block '.\\[%entry\\]' of function '.\\[%Main\\]' " 533fd4e5da5Sopenharmony_ci "is targeted by block '.\\[%bad\\]'\n" 534fd4e5da5Sopenharmony_ci " %Main = OpFunction %void None %10\n")); 535fd4e5da5Sopenharmony_ci} 536fd4e5da5Sopenharmony_ci 537fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, BranchConditionalFalseTargetFirstBlockBad) { 538fd4e5da5Sopenharmony_ci Block entry("entry"); 539fd4e5da5Sopenharmony_ci Block bad("bad", spv::Op::OpBranchConditional); 540fd4e5da5Sopenharmony_ci Block t("t"); 541fd4e5da5Sopenharmony_ci Block merge("merge"); 542fd4e5da5Sopenharmony_ci Block end("end", spv::Op::OpReturn); 543fd4e5da5Sopenharmony_ci 544fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 545fd4e5da5Sopenharmony_ci bad.SetBody("OpLoopMerge %merge %cont None\n"); 546fd4e5da5Sopenharmony_ci 547fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 548fd4e5da5Sopenharmony_ci nameOps("entry", "bad", std::make_pair("func", "Main")) + 549fd4e5da5Sopenharmony_ci types_consts() + 550fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 551fd4e5da5Sopenharmony_ci 552fd4e5da5Sopenharmony_ci str += entry >> bad; 553fd4e5da5Sopenharmony_ci str += bad >> std::vector<Block>({t, entry}); 554fd4e5da5Sopenharmony_ci str += merge >> end; 555fd4e5da5Sopenharmony_ci str += end; 556fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 557fd4e5da5Sopenharmony_ci 558fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 559fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 560fd4e5da5Sopenharmony_ci EXPECT_THAT( 561fd4e5da5Sopenharmony_ci getDiagnosticString(), 562fd4e5da5Sopenharmony_ci MatchesRegex("First block '.\\[%entry\\]' of function '.\\[%Main\\]' " 563fd4e5da5Sopenharmony_ci "is targeted by block '.\\[%bad\\]'\n" 564fd4e5da5Sopenharmony_ci " %Main = OpFunction %void None %10\n")); 565fd4e5da5Sopenharmony_ci} 566fd4e5da5Sopenharmony_ci 567fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, SwitchTargetFirstBlockBad) { 568fd4e5da5Sopenharmony_ci Block entry("entry"); 569fd4e5da5Sopenharmony_ci Block bad("bad", spv::Op::OpSwitch); 570fd4e5da5Sopenharmony_ci Block block1("block1"); 571fd4e5da5Sopenharmony_ci Block block2("block2"); 572fd4e5da5Sopenharmony_ci Block block3("block3"); 573fd4e5da5Sopenharmony_ci Block def("def"); // default block 574fd4e5da5Sopenharmony_ci Block merge("merge"); 575fd4e5da5Sopenharmony_ci Block end("end", spv::Op::OpReturn); 576fd4e5da5Sopenharmony_ci 577fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 578fd4e5da5Sopenharmony_ci bad.SetBody("OpSelectionMerge %merge None\n"); 579fd4e5da5Sopenharmony_ci 580fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 581fd4e5da5Sopenharmony_ci nameOps("entry", "bad", std::make_pair("func", "Main")) + 582fd4e5da5Sopenharmony_ci types_consts() + 583fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 584fd4e5da5Sopenharmony_ci 585fd4e5da5Sopenharmony_ci str += entry >> bad; 586fd4e5da5Sopenharmony_ci str += bad >> std::vector<Block>({def, block1, block2, block3, entry}); 587fd4e5da5Sopenharmony_ci str += def >> merge; 588fd4e5da5Sopenharmony_ci str += block1 >> merge; 589fd4e5da5Sopenharmony_ci str += block2 >> merge; 590fd4e5da5Sopenharmony_ci str += block3 >> merge; 591fd4e5da5Sopenharmony_ci str += merge >> end; 592fd4e5da5Sopenharmony_ci str += end; 593fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 594fd4e5da5Sopenharmony_ci 595fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 596fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 597fd4e5da5Sopenharmony_ci EXPECT_THAT( 598fd4e5da5Sopenharmony_ci getDiagnosticString(), 599fd4e5da5Sopenharmony_ci MatchesRegex("First block '.\\[%entry\\]' of function '.\\[%Main\\]' " 600fd4e5da5Sopenharmony_ci "is targeted by block '.\\[%bad\\]'\n" 601fd4e5da5Sopenharmony_ci " %Main = OpFunction %void None %10\n")); 602fd4e5da5Sopenharmony_ci} 603fd4e5da5Sopenharmony_ci 604fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, BranchToBlockInOtherFunctionBad) { 605fd4e5da5Sopenharmony_ci Block entry("entry"); 606fd4e5da5Sopenharmony_ci Block middle("middle", spv::Op::OpBranchConditional); 607fd4e5da5Sopenharmony_ci Block end("end", spv::Op::OpReturn); 608fd4e5da5Sopenharmony_ci 609fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 610fd4e5da5Sopenharmony_ci middle.SetBody("OpSelectionMerge %end None\n"); 611fd4e5da5Sopenharmony_ci 612fd4e5da5Sopenharmony_ci Block entry2("entry2"); 613fd4e5da5Sopenharmony_ci Block middle2("middle2"); 614fd4e5da5Sopenharmony_ci Block end2("end2", spv::Op::OpReturn); 615fd4e5da5Sopenharmony_ci 616fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 617fd4e5da5Sopenharmony_ci nameOps("middle2", std::make_pair("func", "Main")) + 618fd4e5da5Sopenharmony_ci types_consts() + 619fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 620fd4e5da5Sopenharmony_ci 621fd4e5da5Sopenharmony_ci str += entry >> middle; 622fd4e5da5Sopenharmony_ci str += middle >> std::vector<Block>({end, middle2}); 623fd4e5da5Sopenharmony_ci str += end; 624fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 625fd4e5da5Sopenharmony_ci 626fd4e5da5Sopenharmony_ci str += "%func2 = OpFunction %voidt None %funct\n"; 627fd4e5da5Sopenharmony_ci str += entry2 >> middle2; 628fd4e5da5Sopenharmony_ci str += middle2 >> end2; 629fd4e5da5Sopenharmony_ci str += end2; 630fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 631fd4e5da5Sopenharmony_ci 632fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 633fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 634fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 635fd4e5da5Sopenharmony_ci MatchesRegex( 636fd4e5da5Sopenharmony_ci "Block\\(s\\) \\{'.\\[%middle2\\]'\\} are referenced but not " 637fd4e5da5Sopenharmony_ci "defined in function '.\\[%Main\\]'\n" 638fd4e5da5Sopenharmony_ci " %Main = OpFunction %void None %9\n")); 639fd4e5da5Sopenharmony_ci} 640fd4e5da5Sopenharmony_ci 641fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, HeaderDoesntStrictlyDominateMergeBad) { 642fd4e5da5Sopenharmony_ci // If a merge block is reachable, then it must be strictly dominated by 643fd4e5da5Sopenharmony_ci // its header block. 644fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 645fd4e5da5Sopenharmony_ci Block head("head", spv::Op::OpBranchConditional); 646fd4e5da5Sopenharmony_ci Block exit("exit", spv::Op::OpReturn); 647fd4e5da5Sopenharmony_ci 648fd4e5da5Sopenharmony_ci head.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 649fd4e5da5Sopenharmony_ci 650fd4e5da5Sopenharmony_ci if (is_shader) head.AppendBody("OpSelectionMerge %head None\n"); 651fd4e5da5Sopenharmony_ci 652fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 653fd4e5da5Sopenharmony_ci nameOps("head", "exit", std::make_pair("func", "Main")) + 654fd4e5da5Sopenharmony_ci types_consts() + 655fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 656fd4e5da5Sopenharmony_ci 657fd4e5da5Sopenharmony_ci str += head >> std::vector<Block>({exit, exit}); 658fd4e5da5Sopenharmony_ci str += exit; 659fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 660fd4e5da5Sopenharmony_ci 661fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 662fd4e5da5Sopenharmony_ci if (is_shader) { 663fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 664fd4e5da5Sopenharmony_ci EXPECT_THAT( 665fd4e5da5Sopenharmony_ci getDiagnosticString(), 666fd4e5da5Sopenharmony_ci MatchesRegex( 667fd4e5da5Sopenharmony_ci "The selection construct with the selection header " 668fd4e5da5Sopenharmony_ci "'.\\[%head\\]' does not strictly structurally dominate the " 669fd4e5da5Sopenharmony_ci "merge block " 670fd4e5da5Sopenharmony_ci "'.\\[%head\\]'\n %head = OpLabel\n")); 671fd4e5da5Sopenharmony_ci } else { 672fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()) << str; 673fd4e5da5Sopenharmony_ci } 674fd4e5da5Sopenharmony_ci} 675fd4e5da5Sopenharmony_ci 676fd4e5da5Sopenharmony_cistd::string GetUnreachableMergeNoMergeInst(spv::Capability cap) { 677fd4e5da5Sopenharmony_ci std::string header = GetDefaultHeader(cap); 678fd4e5da5Sopenharmony_ci Block entry("entry"); 679fd4e5da5Sopenharmony_ci Block branch("branch", spv::Op::OpBranchConditional); 680fd4e5da5Sopenharmony_ci Block t("t", spv::Op::OpReturn); 681fd4e5da5Sopenharmony_ci Block f("f", spv::Op::OpReturn); 682fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 683fd4e5da5Sopenharmony_ci 684fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 685fd4e5da5Sopenharmony_ci if (cap == spv::Capability::Shader) 686fd4e5da5Sopenharmony_ci branch.AppendBody("OpSelectionMerge %merge None\n"); 687fd4e5da5Sopenharmony_ci 688fd4e5da5Sopenharmony_ci std::string str = header; 689fd4e5da5Sopenharmony_ci str += nameOps("branch", "merge", std::make_pair("func", "Main")); 690fd4e5da5Sopenharmony_ci str += types_consts() + "%func = OpFunction %voidt None %funct\n"; 691fd4e5da5Sopenharmony_ci str += entry >> branch; 692fd4e5da5Sopenharmony_ci str += branch >> std::vector<Block>({t, f}); 693fd4e5da5Sopenharmony_ci str += t; 694fd4e5da5Sopenharmony_ci str += f; 695fd4e5da5Sopenharmony_ci str += merge; 696fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 697fd4e5da5Sopenharmony_ci 698fd4e5da5Sopenharmony_ci return str; 699fd4e5da5Sopenharmony_ci} 700fd4e5da5Sopenharmony_ci 701fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, UnreachableMergeNoMergeInst) { 702fd4e5da5Sopenharmony_ci CompileSuccessfully(GetUnreachableMergeNoMergeInst(GetParam())); 703fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 704fd4e5da5Sopenharmony_ci} 705fd4e5da5Sopenharmony_ci 706fd4e5da5Sopenharmony_cistd::string GetUnreachableMergeTerminatedBy(spv::Capability cap, spv::Op op) { 707fd4e5da5Sopenharmony_ci std::string header = GetDefaultHeader(cap); 708fd4e5da5Sopenharmony_ci 709fd4e5da5Sopenharmony_ci Block entry("entry"); 710fd4e5da5Sopenharmony_ci Block branch("branch", spv::Op::OpBranchConditional); 711fd4e5da5Sopenharmony_ci Block t("t", spv::Op::OpReturn); 712fd4e5da5Sopenharmony_ci Block f("f", spv::Op::OpReturn); 713fd4e5da5Sopenharmony_ci Block merge("merge", op); 714fd4e5da5Sopenharmony_ci 715fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 716fd4e5da5Sopenharmony_ci std::string str = header; 717fd4e5da5Sopenharmony_ci if (cap == spv::Capability::Shader) 718fd4e5da5Sopenharmony_ci branch.AppendBody("OpSelectionMerge %merge None\n"); 719fd4e5da5Sopenharmony_ci 720fd4e5da5Sopenharmony_ci str += nameOps("branch", "merge", std::make_pair("func", "Main")); 721fd4e5da5Sopenharmony_ci str += types_consts(); 722fd4e5da5Sopenharmony_ci str += "%func = OpFunction %voidt None %funct\n"; 723fd4e5da5Sopenharmony_ci str += entry >> branch; 724fd4e5da5Sopenharmony_ci str += branch >> std::vector<Block>({t, f}); 725fd4e5da5Sopenharmony_ci str += t; 726fd4e5da5Sopenharmony_ci str += f; 727fd4e5da5Sopenharmony_ci str += merge; 728fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 729fd4e5da5Sopenharmony_ci 730fd4e5da5Sopenharmony_ci return str; 731fd4e5da5Sopenharmony_ci} 732fd4e5da5Sopenharmony_ci 733fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, UnreachableMergeTerminatedByOpUnreachable) { 734fd4e5da5Sopenharmony_ci CompileSuccessfully( 735fd4e5da5Sopenharmony_ci GetUnreachableMergeTerminatedBy(GetParam(), spv::Op::OpUnreachable)); 736fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 737fd4e5da5Sopenharmony_ci} 738fd4e5da5Sopenharmony_ci 739fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, UnreachableMergeTerminatedByOpKill) { 740fd4e5da5Sopenharmony_ci CompileSuccessfully(GetUnreachableMergeTerminatedBy(spv::Capability::Shader, 741fd4e5da5Sopenharmony_ci spv::Op::OpKill)); 742fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 743fd4e5da5Sopenharmony_ci} 744fd4e5da5Sopenharmony_ci 745fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, UnreachableMergeTerminatedByOpReturn) { 746fd4e5da5Sopenharmony_ci CompileSuccessfully( 747fd4e5da5Sopenharmony_ci GetUnreachableMergeTerminatedBy(GetParam(), spv::Op::OpReturn)); 748fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 749fd4e5da5Sopenharmony_ci} 750fd4e5da5Sopenharmony_ci 751fd4e5da5Sopenharmony_cistd::string GetUnreachableContinueTerminatedBy(spv::Capability cap, 752fd4e5da5Sopenharmony_ci spv::Op op) { 753fd4e5da5Sopenharmony_ci std::string header = GetDefaultHeader(cap); 754fd4e5da5Sopenharmony_ci 755fd4e5da5Sopenharmony_ci Block entry("entry"); 756fd4e5da5Sopenharmony_ci Block branch("branch", spv::Op::OpBranch); 757fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 758fd4e5da5Sopenharmony_ci Block target("target", op); 759fd4e5da5Sopenharmony_ci 760fd4e5da5Sopenharmony_ci if (op == spv::Op::OpBranch) target >> branch; 761fd4e5da5Sopenharmony_ci 762fd4e5da5Sopenharmony_ci std::string str = header; 763fd4e5da5Sopenharmony_ci if (cap == spv::Capability::Shader) 764fd4e5da5Sopenharmony_ci branch.AppendBody("OpLoopMerge %merge %target None\n"); 765fd4e5da5Sopenharmony_ci 766fd4e5da5Sopenharmony_ci str += nameOps("branch", "merge", "target", std::make_pair("func", "Main")); 767fd4e5da5Sopenharmony_ci str += types_consts(); 768fd4e5da5Sopenharmony_ci str += "%func = OpFunction %voidt None %funct\n"; 769fd4e5da5Sopenharmony_ci str += entry >> branch; 770fd4e5da5Sopenharmony_ci str += branch >> std::vector<Block>({merge}); 771fd4e5da5Sopenharmony_ci str += merge; 772fd4e5da5Sopenharmony_ci str += target; 773fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 774fd4e5da5Sopenharmony_ci 775fd4e5da5Sopenharmony_ci return str; 776fd4e5da5Sopenharmony_ci} 777fd4e5da5Sopenharmony_ci 778fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, UnreachableContinueTerminatedByOpUnreachable) { 779fd4e5da5Sopenharmony_ci CompileSuccessfully( 780fd4e5da5Sopenharmony_ci GetUnreachableContinueTerminatedBy(GetParam(), spv::Op::OpUnreachable)); 781fd4e5da5Sopenharmony_ci if (GetParam() == spv::Capability::Shader) { 782fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 783fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 784fd4e5da5Sopenharmony_ci HasSubstr("targeted by 0 back-edge blocks")); 785fd4e5da5Sopenharmony_ci } else { 786fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 787fd4e5da5Sopenharmony_ci } 788fd4e5da5Sopenharmony_ci} 789fd4e5da5Sopenharmony_ci 790fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, UnreachableContinueTerminatedByOpKill) { 791fd4e5da5Sopenharmony_ci CompileSuccessfully(GetUnreachableContinueTerminatedBy( 792fd4e5da5Sopenharmony_ci spv::Capability::Shader, spv::Op::OpKill)); 793fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 794fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 795fd4e5da5Sopenharmony_ci HasSubstr("targeted by 0 back-edge blocks")); 796fd4e5da5Sopenharmony_ci} 797fd4e5da5Sopenharmony_ci 798fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, UnreachableContinueTerminatedByOpReturn) { 799fd4e5da5Sopenharmony_ci CompileSuccessfully( 800fd4e5da5Sopenharmony_ci GetUnreachableContinueTerminatedBy(GetParam(), spv::Op::OpReturn)); 801fd4e5da5Sopenharmony_ci if (GetParam() == spv::Capability::Shader) { 802fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 803fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 804fd4e5da5Sopenharmony_ci HasSubstr("targeted by 0 back-edge blocks")); 805fd4e5da5Sopenharmony_ci } else { 806fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 807fd4e5da5Sopenharmony_ci } 808fd4e5da5Sopenharmony_ci} 809fd4e5da5Sopenharmony_ci 810fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, UnreachableContinueTerminatedByOpBranch) { 811fd4e5da5Sopenharmony_ci CompileSuccessfully( 812fd4e5da5Sopenharmony_ci GetUnreachableContinueTerminatedBy(GetParam(), spv::Op::OpBranch)); 813fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 814fd4e5da5Sopenharmony_ci} 815fd4e5da5Sopenharmony_ci 816fd4e5da5Sopenharmony_cistd::string GetUnreachableMergeUnreachableMergeInst(spv::Capability cap) { 817fd4e5da5Sopenharmony_ci std::string header = GetDefaultHeader(cap); 818fd4e5da5Sopenharmony_ci 819fd4e5da5Sopenharmony_ci Block body("body", spv::Op::OpReturn); 820fd4e5da5Sopenharmony_ci Block entry("entry"); 821fd4e5da5Sopenharmony_ci Block branch("branch", spv::Op::OpBranchConditional); 822fd4e5da5Sopenharmony_ci Block t("t", spv::Op::OpReturn); 823fd4e5da5Sopenharmony_ci Block f("f", spv::Op::OpReturn); 824fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpUnreachable); 825fd4e5da5Sopenharmony_ci 826fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 827fd4e5da5Sopenharmony_ci std::string str = header; 828fd4e5da5Sopenharmony_ci if (cap == spv::Capability::Shader) 829fd4e5da5Sopenharmony_ci branch.AppendBody("OpSelectionMerge %merge None\n"); 830fd4e5da5Sopenharmony_ci 831fd4e5da5Sopenharmony_ci str += nameOps("branch", "merge", std::make_pair("func", "Main")); 832fd4e5da5Sopenharmony_ci str += types_consts(); 833fd4e5da5Sopenharmony_ci str += "%func = OpFunction %voidt None %funct\n"; 834fd4e5da5Sopenharmony_ci str += body; 835fd4e5da5Sopenharmony_ci str += merge; 836fd4e5da5Sopenharmony_ci str += entry >> branch; 837fd4e5da5Sopenharmony_ci str += branch >> std::vector<Block>({t, f}); 838fd4e5da5Sopenharmony_ci str += t; 839fd4e5da5Sopenharmony_ci str += f; 840fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 841fd4e5da5Sopenharmony_ci 842fd4e5da5Sopenharmony_ci return str; 843fd4e5da5Sopenharmony_ci} 844fd4e5da5Sopenharmony_ci 845fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, UnreachableMergeUnreachableMergeInst) { 846fd4e5da5Sopenharmony_ci CompileSuccessfully(GetUnreachableMergeUnreachableMergeInst(GetParam())); 847fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 848fd4e5da5Sopenharmony_ci} 849fd4e5da5Sopenharmony_ci 850fd4e5da5Sopenharmony_cistd::string GetUnreachableContinueUnreachableLoopInst(spv::Capability cap) { 851fd4e5da5Sopenharmony_ci std::string header = GetDefaultHeader(cap); 852fd4e5da5Sopenharmony_ci 853fd4e5da5Sopenharmony_ci Block body("body", spv::Op::OpReturn); 854fd4e5da5Sopenharmony_ci Block entry("entry"); 855fd4e5da5Sopenharmony_ci Block branch("branch", spv::Op::OpBranch); 856fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 857fd4e5da5Sopenharmony_ci Block target("target", spv::Op::OpBranch); 858fd4e5da5Sopenharmony_ci 859fd4e5da5Sopenharmony_ci target >> branch; 860fd4e5da5Sopenharmony_ci 861fd4e5da5Sopenharmony_ci std::string str = header; 862fd4e5da5Sopenharmony_ci if (cap == spv::Capability::Shader) 863fd4e5da5Sopenharmony_ci branch.AppendBody("OpLoopMerge %merge %target None\n"); 864fd4e5da5Sopenharmony_ci 865fd4e5da5Sopenharmony_ci str += nameOps("branch", "merge", "target", std::make_pair("func", "Main")); 866fd4e5da5Sopenharmony_ci str += types_consts(); 867fd4e5da5Sopenharmony_ci str += "%func = OpFunction %voidt None %funct\n"; 868fd4e5da5Sopenharmony_ci str += body; 869fd4e5da5Sopenharmony_ci str += target; 870fd4e5da5Sopenharmony_ci str += merge; 871fd4e5da5Sopenharmony_ci str += entry >> branch; 872fd4e5da5Sopenharmony_ci str += branch >> std::vector<Block>({merge}); 873fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 874fd4e5da5Sopenharmony_ci 875fd4e5da5Sopenharmony_ci return str; 876fd4e5da5Sopenharmony_ci} 877fd4e5da5Sopenharmony_ci 878fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, UnreachableContinueUnreachableLoopInst) { 879fd4e5da5Sopenharmony_ci CompileSuccessfully(GetUnreachableContinueUnreachableLoopInst(GetParam())); 880fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 881fd4e5da5Sopenharmony_ci} 882fd4e5da5Sopenharmony_ci 883fd4e5da5Sopenharmony_cistd::string GetUnreachableMergeWithComplexBody(spv::Capability cap) { 884fd4e5da5Sopenharmony_ci std::string header = GetDefaultHeader(cap); 885fd4e5da5Sopenharmony_ci 886fd4e5da5Sopenharmony_ci Block entry("entry"); 887fd4e5da5Sopenharmony_ci Block branch("branch", spv::Op::OpBranchConditional); 888fd4e5da5Sopenharmony_ci Block t("t", spv::Op::OpReturn); 889fd4e5da5Sopenharmony_ci Block f("f", spv::Op::OpReturn); 890fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpUnreachable); 891fd4e5da5Sopenharmony_ci 892fd4e5da5Sopenharmony_ci entry.AppendBody("%placeholder = OpVariable %intptrt Function\n"); 893fd4e5da5Sopenharmony_ci entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n"); 894fd4e5da5Sopenharmony_ci merge.AppendBody("OpStore %placeholder %one\n"); 895fd4e5da5Sopenharmony_ci 896fd4e5da5Sopenharmony_ci std::string str = header; 897fd4e5da5Sopenharmony_ci if (cap == spv::Capability::Shader) 898fd4e5da5Sopenharmony_ci branch.AppendBody("OpSelectionMerge %merge None\n"); 899fd4e5da5Sopenharmony_ci 900fd4e5da5Sopenharmony_ci str += nameOps("branch", "merge", std::make_pair("func", "Main")); 901fd4e5da5Sopenharmony_ci str += types_consts(); 902fd4e5da5Sopenharmony_ci str += "%intptrt = OpTypePointer Function %intt\n"; 903fd4e5da5Sopenharmony_ci str += "%func = OpFunction %voidt None %funct\n"; 904fd4e5da5Sopenharmony_ci str += entry >> branch; 905fd4e5da5Sopenharmony_ci str += branch >> std::vector<Block>({t, f}); 906fd4e5da5Sopenharmony_ci str += t; 907fd4e5da5Sopenharmony_ci str += f; 908fd4e5da5Sopenharmony_ci str += merge; 909fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 910fd4e5da5Sopenharmony_ci 911fd4e5da5Sopenharmony_ci return str; 912fd4e5da5Sopenharmony_ci} 913fd4e5da5Sopenharmony_ci 914fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, UnreachableMergeWithComplexBody) { 915fd4e5da5Sopenharmony_ci CompileSuccessfully(GetUnreachableMergeWithComplexBody(GetParam())); 916fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 917fd4e5da5Sopenharmony_ci} 918fd4e5da5Sopenharmony_ci 919fd4e5da5Sopenharmony_cistd::string GetUnreachableContinueWithComplexBody(spv::Capability cap) { 920fd4e5da5Sopenharmony_ci std::string header = GetDefaultHeader(cap); 921fd4e5da5Sopenharmony_ci 922fd4e5da5Sopenharmony_ci Block entry("entry"); 923fd4e5da5Sopenharmony_ci Block branch("branch", spv::Op::OpBranch); 924fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 925fd4e5da5Sopenharmony_ci Block target("target", spv::Op::OpBranch); 926fd4e5da5Sopenharmony_ci 927fd4e5da5Sopenharmony_ci target >> branch; 928fd4e5da5Sopenharmony_ci 929fd4e5da5Sopenharmony_ci entry.AppendBody("%placeholder = OpVariable %intptrt Function\n"); 930fd4e5da5Sopenharmony_ci target.AppendBody("OpStore %placeholder %one\n"); 931fd4e5da5Sopenharmony_ci 932fd4e5da5Sopenharmony_ci std::string str = header; 933fd4e5da5Sopenharmony_ci if (cap == spv::Capability::Shader) 934fd4e5da5Sopenharmony_ci branch.AppendBody("OpLoopMerge %merge %target None\n"); 935fd4e5da5Sopenharmony_ci 936fd4e5da5Sopenharmony_ci str += nameOps("branch", "merge", "target", std::make_pair("func", "Main")); 937fd4e5da5Sopenharmony_ci str += types_consts(); 938fd4e5da5Sopenharmony_ci str += "%intptrt = OpTypePointer Function %intt\n"; 939fd4e5da5Sopenharmony_ci str += "%func = OpFunction %voidt None %funct\n"; 940fd4e5da5Sopenharmony_ci str += entry >> branch; 941fd4e5da5Sopenharmony_ci str += branch >> std::vector<Block>({merge}); 942fd4e5da5Sopenharmony_ci str += merge; 943fd4e5da5Sopenharmony_ci str += target; 944fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 945fd4e5da5Sopenharmony_ci 946fd4e5da5Sopenharmony_ci return str; 947fd4e5da5Sopenharmony_ci} 948fd4e5da5Sopenharmony_ci 949fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, UnreachableContinueWithComplexBody) { 950fd4e5da5Sopenharmony_ci CompileSuccessfully(GetUnreachableContinueWithComplexBody(GetParam())); 951fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 952fd4e5da5Sopenharmony_ci} 953fd4e5da5Sopenharmony_ci 954fd4e5da5Sopenharmony_cistd::string GetUnreachableMergeWithBranchUse(spv::Capability cap) { 955fd4e5da5Sopenharmony_ci std::string header = GetDefaultHeader(cap); 956fd4e5da5Sopenharmony_ci 957fd4e5da5Sopenharmony_ci Block entry("entry"); 958fd4e5da5Sopenharmony_ci Block branch("branch", spv::Op::OpBranchConditional); 959fd4e5da5Sopenharmony_ci Block t("t", spv::Op::OpBranch); 960fd4e5da5Sopenharmony_ci Block f("f", spv::Op::OpReturn); 961fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpUnreachable); 962fd4e5da5Sopenharmony_ci 963fd4e5da5Sopenharmony_ci entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n"); 964fd4e5da5Sopenharmony_ci 965fd4e5da5Sopenharmony_ci std::string str = header; 966fd4e5da5Sopenharmony_ci if (cap == spv::Capability::Shader) 967fd4e5da5Sopenharmony_ci branch.AppendBody("OpSelectionMerge %merge None\n"); 968fd4e5da5Sopenharmony_ci 969fd4e5da5Sopenharmony_ci str += nameOps("branch", "merge", std::make_pair("func", "Main")); 970fd4e5da5Sopenharmony_ci str += types_consts(); 971fd4e5da5Sopenharmony_ci str += "%func = OpFunction %voidt None %funct\n"; 972fd4e5da5Sopenharmony_ci str += entry >> branch; 973fd4e5da5Sopenharmony_ci str += branch >> std::vector<Block>({t, f}); 974fd4e5da5Sopenharmony_ci str += t >> merge; 975fd4e5da5Sopenharmony_ci str += f; 976fd4e5da5Sopenharmony_ci str += merge; 977fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 978fd4e5da5Sopenharmony_ci 979fd4e5da5Sopenharmony_ci return str; 980fd4e5da5Sopenharmony_ci} 981fd4e5da5Sopenharmony_ci 982fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, UnreachableMergeWithBranchUse) { 983fd4e5da5Sopenharmony_ci CompileSuccessfully(GetUnreachableMergeWithBranchUse(GetParam())); 984fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 985fd4e5da5Sopenharmony_ci} 986fd4e5da5Sopenharmony_ci 987fd4e5da5Sopenharmony_cistd::string GetUnreachableMergeWithMultipleUses(spv::Capability cap) { 988fd4e5da5Sopenharmony_ci std::string header = GetDefaultHeader(cap); 989fd4e5da5Sopenharmony_ci 990fd4e5da5Sopenharmony_ci Block entry("entry"); 991fd4e5da5Sopenharmony_ci Block branch("branch", spv::Op::OpBranchConditional); 992fd4e5da5Sopenharmony_ci Block t("t", spv::Op::OpReturn); 993fd4e5da5Sopenharmony_ci Block f("f", spv::Op::OpReturn); 994fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpUnreachable); 995fd4e5da5Sopenharmony_ci Block duplicate("duplicate", spv::Op::OpBranchConditional); 996fd4e5da5Sopenharmony_ci 997fd4e5da5Sopenharmony_ci entry.AppendBody("%cond = OpSLessThan %boolt %one %two\n"); 998fd4e5da5Sopenharmony_ci 999fd4e5da5Sopenharmony_ci std::string str = header; 1000fd4e5da5Sopenharmony_ci if (cap == spv::Capability::Shader) { 1001fd4e5da5Sopenharmony_ci branch.AppendBody("OpSelectionMerge %merge None\n"); 1002fd4e5da5Sopenharmony_ci duplicate.AppendBody("OpSelectionMerge %merge None\n"); 1003fd4e5da5Sopenharmony_ci } 1004fd4e5da5Sopenharmony_ci 1005fd4e5da5Sopenharmony_ci str += nameOps("branch", "merge", std::make_pair("func", "Main")); 1006fd4e5da5Sopenharmony_ci str += types_consts(); 1007fd4e5da5Sopenharmony_ci str += "%func = OpFunction %voidt None %funct\n"; 1008fd4e5da5Sopenharmony_ci str += entry >> branch; 1009fd4e5da5Sopenharmony_ci str += branch >> std::vector<Block>({t, f}); 1010fd4e5da5Sopenharmony_ci str += duplicate >> std::vector<Block>({t, f}); 1011fd4e5da5Sopenharmony_ci str += t; 1012fd4e5da5Sopenharmony_ci str += f; 1013fd4e5da5Sopenharmony_ci str += merge; 1014fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 1015fd4e5da5Sopenharmony_ci 1016fd4e5da5Sopenharmony_ci return str; 1017fd4e5da5Sopenharmony_ci} 1018fd4e5da5Sopenharmony_ci 1019fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, UnreachableMergeWithMultipleUses) { 1020fd4e5da5Sopenharmony_ci CompileSuccessfully(GetUnreachableMergeWithMultipleUses(GetParam())); 1021fd4e5da5Sopenharmony_ci if (GetParam() == spv::Capability::Shader) { 1022fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 1023fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 1024fd4e5da5Sopenharmony_ci HasSubstr("is already a merge block for another header")); 1025fd4e5da5Sopenharmony_ci } else { 1026fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1027fd4e5da5Sopenharmony_ci } 1028fd4e5da5Sopenharmony_ci} 1029fd4e5da5Sopenharmony_ci 1030fd4e5da5Sopenharmony_cistd::string GetUnreachableContinueWithBranchUse(spv::Capability cap) { 1031fd4e5da5Sopenharmony_ci std::string header = GetDefaultHeader(cap); 1032fd4e5da5Sopenharmony_ci 1033fd4e5da5Sopenharmony_ci Block entry("entry"); 1034fd4e5da5Sopenharmony_ci Block branch("branch", spv::Op::OpBranch); 1035fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 1036fd4e5da5Sopenharmony_ci Block target("target", spv::Op::OpBranch); 1037fd4e5da5Sopenharmony_ci 1038fd4e5da5Sopenharmony_ci target >> branch; 1039fd4e5da5Sopenharmony_ci 1040fd4e5da5Sopenharmony_ci entry.AppendBody("%placeholder = OpVariable %intptrt Function\n"); 1041fd4e5da5Sopenharmony_ci 1042fd4e5da5Sopenharmony_ci std::string str = header; 1043fd4e5da5Sopenharmony_ci if (cap == spv::Capability::Shader) 1044fd4e5da5Sopenharmony_ci branch.AppendBody("OpLoopMerge %merge %target None\n"); 1045fd4e5da5Sopenharmony_ci 1046fd4e5da5Sopenharmony_ci str += nameOps("branch", "merge", "target", std::make_pair("func", "Main")); 1047fd4e5da5Sopenharmony_ci str += types_consts(); 1048fd4e5da5Sopenharmony_ci str += "%intptrt = OpTypePointer Function %intt\n"; 1049fd4e5da5Sopenharmony_ci str += "%func = OpFunction %voidt None %funct\n"; 1050fd4e5da5Sopenharmony_ci str += entry >> branch; 1051fd4e5da5Sopenharmony_ci str += branch >> std::vector<Block>({merge}); 1052fd4e5da5Sopenharmony_ci str += merge; 1053fd4e5da5Sopenharmony_ci str += target; 1054fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 1055fd4e5da5Sopenharmony_ci 1056fd4e5da5Sopenharmony_ci return str; 1057fd4e5da5Sopenharmony_ci} 1058fd4e5da5Sopenharmony_ci 1059fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, UnreachableContinueWithBranchUse) { 1060fd4e5da5Sopenharmony_ci CompileSuccessfully(GetUnreachableContinueWithBranchUse(GetParam())); 1061fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1062fd4e5da5Sopenharmony_ci} 1063fd4e5da5Sopenharmony_ci 1064fd4e5da5Sopenharmony_cistd::string GetReachableMergeAndContinue(spv::Capability cap) { 1065fd4e5da5Sopenharmony_ci std::string header = GetDefaultHeader(cap); 1066fd4e5da5Sopenharmony_ci 1067fd4e5da5Sopenharmony_ci Block entry("entry"); 1068fd4e5da5Sopenharmony_ci Block branch("branch", spv::Op::OpBranch); 1069fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 1070fd4e5da5Sopenharmony_ci Block target("target", spv::Op::OpBranch); 1071fd4e5da5Sopenharmony_ci Block body("body", spv::Op::OpBranchConditional); 1072fd4e5da5Sopenharmony_ci Block t("t", spv::Op::OpBranch); 1073fd4e5da5Sopenharmony_ci Block f("f", spv::Op::OpBranch); 1074fd4e5da5Sopenharmony_ci 1075fd4e5da5Sopenharmony_ci target >> branch; 1076fd4e5da5Sopenharmony_ci body.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 1077fd4e5da5Sopenharmony_ci t >> merge; 1078fd4e5da5Sopenharmony_ci f >> target; 1079fd4e5da5Sopenharmony_ci 1080fd4e5da5Sopenharmony_ci std::string str = header; 1081fd4e5da5Sopenharmony_ci if (cap == spv::Capability::Shader) { 1082fd4e5da5Sopenharmony_ci branch.AppendBody("OpLoopMerge %merge %target None\n"); 1083fd4e5da5Sopenharmony_ci body.AppendBody("OpSelectionMerge %f None\n"); 1084fd4e5da5Sopenharmony_ci } 1085fd4e5da5Sopenharmony_ci 1086fd4e5da5Sopenharmony_ci str += nameOps("branch", "merge", "target", "body", "t", "f", 1087fd4e5da5Sopenharmony_ci std::make_pair("func", "Main")); 1088fd4e5da5Sopenharmony_ci str += types_consts(); 1089fd4e5da5Sopenharmony_ci str += "%func = OpFunction %voidt None %funct\n"; 1090fd4e5da5Sopenharmony_ci str += entry >> branch; 1091fd4e5da5Sopenharmony_ci str += branch >> std::vector<Block>({body}); 1092fd4e5da5Sopenharmony_ci str += body >> std::vector<Block>({t, f}); 1093fd4e5da5Sopenharmony_ci str += t; 1094fd4e5da5Sopenharmony_ci str += f; 1095fd4e5da5Sopenharmony_ci str += merge; 1096fd4e5da5Sopenharmony_ci str += target; 1097fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 1098fd4e5da5Sopenharmony_ci 1099fd4e5da5Sopenharmony_ci return str; 1100fd4e5da5Sopenharmony_ci} 1101fd4e5da5Sopenharmony_ci 1102fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, ReachableMergeAndContinue) { 1103fd4e5da5Sopenharmony_ci CompileSuccessfully(GetReachableMergeAndContinue(GetParam())); 1104fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1105fd4e5da5Sopenharmony_ci} 1106fd4e5da5Sopenharmony_ci 1107fd4e5da5Sopenharmony_cistd::string GetUnreachableMergeAndContinue(spv::Capability cap) { 1108fd4e5da5Sopenharmony_ci std::string header = GetDefaultHeader(cap); 1109fd4e5da5Sopenharmony_ci 1110fd4e5da5Sopenharmony_ci Block entry("entry"); 1111fd4e5da5Sopenharmony_ci Block branch("branch", spv::Op::OpBranch); 1112fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 1113fd4e5da5Sopenharmony_ci Block target("target", spv::Op::OpBranch); 1114fd4e5da5Sopenharmony_ci Block body("body", spv::Op::OpBranchConditional); 1115fd4e5da5Sopenharmony_ci Block t("t", spv::Op::OpReturn); 1116fd4e5da5Sopenharmony_ci Block f("f", spv::Op::OpReturn); 1117fd4e5da5Sopenharmony_ci Block pre_target("pre_target", spv::Op::OpBranch); 1118fd4e5da5Sopenharmony_ci 1119fd4e5da5Sopenharmony_ci target >> branch; 1120fd4e5da5Sopenharmony_ci body.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 1121fd4e5da5Sopenharmony_ci 1122fd4e5da5Sopenharmony_ci std::string str = header; 1123fd4e5da5Sopenharmony_ci if (cap == spv::Capability::Shader) { 1124fd4e5da5Sopenharmony_ci branch.AppendBody("OpLoopMerge %merge %target None\n"); 1125fd4e5da5Sopenharmony_ci body.AppendBody("OpSelectionMerge %pre_target None\n"); 1126fd4e5da5Sopenharmony_ci } 1127fd4e5da5Sopenharmony_ci 1128fd4e5da5Sopenharmony_ci str += nameOps("branch", "merge", "pre_target", "target", "body", "t", "f", 1129fd4e5da5Sopenharmony_ci std::make_pair("func", "Main")); 1130fd4e5da5Sopenharmony_ci str += types_consts(); 1131fd4e5da5Sopenharmony_ci str += "%func = OpFunction %voidt None %funct\n"; 1132fd4e5da5Sopenharmony_ci str += entry >> branch; 1133fd4e5da5Sopenharmony_ci str += branch >> std::vector<Block>({body}); 1134fd4e5da5Sopenharmony_ci str += body >> std::vector<Block>({t, f}); 1135fd4e5da5Sopenharmony_ci str += t; 1136fd4e5da5Sopenharmony_ci str += f; 1137fd4e5da5Sopenharmony_ci str += merge; 1138fd4e5da5Sopenharmony_ci str += pre_target >> target; 1139fd4e5da5Sopenharmony_ci str += target; 1140fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 1141fd4e5da5Sopenharmony_ci 1142fd4e5da5Sopenharmony_ci return str; 1143fd4e5da5Sopenharmony_ci} 1144fd4e5da5Sopenharmony_ci 1145fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, UnreachableMergeAndContinue) { 1146fd4e5da5Sopenharmony_ci CompileSuccessfully(GetUnreachableMergeAndContinue(GetParam())); 1147fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1148fd4e5da5Sopenharmony_ci} 1149fd4e5da5Sopenharmony_ci 1150fd4e5da5Sopenharmony_cistd::string GetUnreachableBlock(spv::Capability cap) { 1151fd4e5da5Sopenharmony_ci std::string header = GetDefaultHeader(cap); 1152fd4e5da5Sopenharmony_ci 1153fd4e5da5Sopenharmony_ci Block entry("entry"); 1154fd4e5da5Sopenharmony_ci Block unreachable("unreachable"); 1155fd4e5da5Sopenharmony_ci Block exit("exit", spv::Op::OpReturn); 1156fd4e5da5Sopenharmony_ci 1157fd4e5da5Sopenharmony_ci std::string str = header; 1158fd4e5da5Sopenharmony_ci str += nameOps("unreachable", "exit", std::make_pair("func", "Main")); 1159fd4e5da5Sopenharmony_ci str += types_consts(); 1160fd4e5da5Sopenharmony_ci str += "%func = OpFunction %voidt None %funct\n"; 1161fd4e5da5Sopenharmony_ci str += entry >> exit; 1162fd4e5da5Sopenharmony_ci str += unreachable >> exit; 1163fd4e5da5Sopenharmony_ci str += exit; 1164fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 1165fd4e5da5Sopenharmony_ci 1166fd4e5da5Sopenharmony_ci return str; 1167fd4e5da5Sopenharmony_ci} 1168fd4e5da5Sopenharmony_ci 1169fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, UnreachableBlock) { 1170fd4e5da5Sopenharmony_ci CompileSuccessfully(GetUnreachableBlock(GetParam())); 1171fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1172fd4e5da5Sopenharmony_ci} 1173fd4e5da5Sopenharmony_ci 1174fd4e5da5Sopenharmony_cistd::string GetUnreachableBranch(spv::Capability cap) { 1175fd4e5da5Sopenharmony_ci std::string header = GetDefaultHeader(cap); 1176fd4e5da5Sopenharmony_ci 1177fd4e5da5Sopenharmony_ci Block entry("entry"); 1178fd4e5da5Sopenharmony_ci Block unreachable("unreachable", spv::Op::OpBranchConditional); 1179fd4e5da5Sopenharmony_ci Block unreachablechildt("unreachablechildt"); 1180fd4e5da5Sopenharmony_ci Block unreachablechildf("unreachablechildf"); 1181fd4e5da5Sopenharmony_ci Block merge("merge"); 1182fd4e5da5Sopenharmony_ci Block exit("exit", spv::Op::OpReturn); 1183fd4e5da5Sopenharmony_ci 1184fd4e5da5Sopenharmony_ci unreachable.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 1185fd4e5da5Sopenharmony_ci if (cap == spv::Capability::Shader) 1186fd4e5da5Sopenharmony_ci unreachable.AppendBody("OpSelectionMerge %merge None\n"); 1187fd4e5da5Sopenharmony_ci 1188fd4e5da5Sopenharmony_ci std::string str = header; 1189fd4e5da5Sopenharmony_ci str += nameOps("unreachable", "exit", std::make_pair("func", "Main")); 1190fd4e5da5Sopenharmony_ci str += types_consts(); 1191fd4e5da5Sopenharmony_ci str += "%func = OpFunction %voidt None %funct\n"; 1192fd4e5da5Sopenharmony_ci 1193fd4e5da5Sopenharmony_ci str += entry >> exit; 1194fd4e5da5Sopenharmony_ci str += 1195fd4e5da5Sopenharmony_ci unreachable >> std::vector<Block>({unreachablechildt, unreachablechildf}); 1196fd4e5da5Sopenharmony_ci str += unreachablechildt >> merge; 1197fd4e5da5Sopenharmony_ci str += unreachablechildf >> merge; 1198fd4e5da5Sopenharmony_ci str += merge >> exit; 1199fd4e5da5Sopenharmony_ci str += exit; 1200fd4e5da5Sopenharmony_ci str += "OpFunctionEnd\n"; 1201fd4e5da5Sopenharmony_ci 1202fd4e5da5Sopenharmony_ci return str; 1203fd4e5da5Sopenharmony_ci} 1204fd4e5da5Sopenharmony_ci 1205fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, UnreachableBranch) { 1206fd4e5da5Sopenharmony_ci CompileSuccessfully(GetUnreachableBranch(GetParam())); 1207fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1208fd4e5da5Sopenharmony_ci} 1209fd4e5da5Sopenharmony_ci 1210fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, EmptyFunction) { 1211fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + std::string(types_consts()) + 1212fd4e5da5Sopenharmony_ci R"(%func = OpFunction %voidt None %funct 1213fd4e5da5Sopenharmony_ci %l = OpLabel 1214fd4e5da5Sopenharmony_ci OpReturn 1215fd4e5da5Sopenharmony_ci OpFunctionEnd)"; 1216fd4e5da5Sopenharmony_ci 1217fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1218fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1219fd4e5da5Sopenharmony_ci} 1220fd4e5da5Sopenharmony_ci 1221fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, SingleBlockLoop) { 1222fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 1223fd4e5da5Sopenharmony_ci Block entry("entry"); 1224fd4e5da5Sopenharmony_ci Block loop("loop", spv::Op::OpBranchConditional); 1225fd4e5da5Sopenharmony_ci Block exit("exit", spv::Op::OpReturn); 1226fd4e5da5Sopenharmony_ci 1227fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 1228fd4e5da5Sopenharmony_ci if (is_shader) loop.AppendBody("OpLoopMerge %exit %loop None\n"); 1229fd4e5da5Sopenharmony_ci 1230fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + std::string(types_consts()) + 1231fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 1232fd4e5da5Sopenharmony_ci 1233fd4e5da5Sopenharmony_ci str += entry >> loop; 1234fd4e5da5Sopenharmony_ci str += loop >> std::vector<Block>({loop, exit}); 1235fd4e5da5Sopenharmony_ci str += exit; 1236fd4e5da5Sopenharmony_ci str += "OpFunctionEnd"; 1237fd4e5da5Sopenharmony_ci 1238fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1239fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1240fd4e5da5Sopenharmony_ci} 1241fd4e5da5Sopenharmony_ci 1242fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, NestedLoops) { 1243fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 1244fd4e5da5Sopenharmony_ci Block entry("entry"); 1245fd4e5da5Sopenharmony_ci Block loop1("loop1"); 1246fd4e5da5Sopenharmony_ci Block loop1_cont_break_block("loop1_cont_break_block", 1247fd4e5da5Sopenharmony_ci spv::Op::OpBranchConditional); 1248fd4e5da5Sopenharmony_ci Block loop2("loop2", spv::Op::OpBranchConditional); 1249fd4e5da5Sopenharmony_ci Block loop2_merge("loop2_merge"); 1250fd4e5da5Sopenharmony_ci Block loop1_merge("loop1_merge"); 1251fd4e5da5Sopenharmony_ci Block exit("exit", spv::Op::OpReturn); 1252fd4e5da5Sopenharmony_ci 1253fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 1254fd4e5da5Sopenharmony_ci if (is_shader) { 1255fd4e5da5Sopenharmony_ci loop1.SetBody("OpLoopMerge %loop1_merge %loop2 None\n"); 1256fd4e5da5Sopenharmony_ci loop2.SetBody("OpLoopMerge %loop2_merge %loop2 None\n"); 1257fd4e5da5Sopenharmony_ci } 1258fd4e5da5Sopenharmony_ci 1259fd4e5da5Sopenharmony_ci std::string str = 1260fd4e5da5Sopenharmony_ci GetDefaultHeader(GetParam()) + 1261fd4e5da5Sopenharmony_ci nameOps("loop1", "loop1_cont_break_block", "loop2", "loop2_merge") + 1262fd4e5da5Sopenharmony_ci types_consts() + "%func = OpFunction %voidt None %funct\n"; 1263fd4e5da5Sopenharmony_ci 1264fd4e5da5Sopenharmony_ci str += entry >> loop1; 1265fd4e5da5Sopenharmony_ci str += loop1 >> loop1_cont_break_block; 1266fd4e5da5Sopenharmony_ci str += loop1_cont_break_block >> std::vector<Block>({loop1_merge, loop2}); 1267fd4e5da5Sopenharmony_ci str += loop2 >> std::vector<Block>({loop2, loop2_merge}); 1268fd4e5da5Sopenharmony_ci str += loop2_merge >> loop1; 1269fd4e5da5Sopenharmony_ci str += loop1_merge >> exit; 1270fd4e5da5Sopenharmony_ci str += exit; 1271fd4e5da5Sopenharmony_ci str += "OpFunctionEnd"; 1272fd4e5da5Sopenharmony_ci 1273fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1274fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1275fd4e5da5Sopenharmony_ci} 1276fd4e5da5Sopenharmony_ci 1277fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, NestedSelection) { 1278fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 1279fd4e5da5Sopenharmony_ci Block entry("entry"); 1280fd4e5da5Sopenharmony_ci const int N = 256; 1281fd4e5da5Sopenharmony_ci std::vector<Block> if_blocks; 1282fd4e5da5Sopenharmony_ci std::vector<Block> merge_blocks; 1283fd4e5da5Sopenharmony_ci Block inner("inner"); 1284fd4e5da5Sopenharmony_ci 1285fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 1286fd4e5da5Sopenharmony_ci 1287fd4e5da5Sopenharmony_ci if_blocks.emplace_back("if0", spv::Op::OpBranchConditional); 1288fd4e5da5Sopenharmony_ci 1289fd4e5da5Sopenharmony_ci if (is_shader) if_blocks[0].SetBody("OpSelectionMerge %if_merge0 None\n"); 1290fd4e5da5Sopenharmony_ci merge_blocks.emplace_back("if_merge0", spv::Op::OpReturn); 1291fd4e5da5Sopenharmony_ci 1292fd4e5da5Sopenharmony_ci for (int i = 1; i < N; i++) { 1293fd4e5da5Sopenharmony_ci std::stringstream ss; 1294fd4e5da5Sopenharmony_ci ss << i; 1295fd4e5da5Sopenharmony_ci if_blocks.emplace_back("if" + ss.str(), spv::Op::OpBranchConditional); 1296fd4e5da5Sopenharmony_ci if (is_shader) 1297fd4e5da5Sopenharmony_ci if_blocks[i].SetBody("OpSelectionMerge %if_merge" + ss.str() + " None\n"); 1298fd4e5da5Sopenharmony_ci merge_blocks.emplace_back("if_merge" + ss.str(), spv::Op::OpBranch); 1299fd4e5da5Sopenharmony_ci } 1300fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + std::string(types_consts()) + 1301fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 1302fd4e5da5Sopenharmony_ci 1303fd4e5da5Sopenharmony_ci str += entry >> if_blocks[0]; 1304fd4e5da5Sopenharmony_ci for (int i = 0; i < N - 1; i++) { 1305fd4e5da5Sopenharmony_ci str += 1306fd4e5da5Sopenharmony_ci if_blocks[i] >> std::vector<Block>({if_blocks[i + 1], merge_blocks[i]}); 1307fd4e5da5Sopenharmony_ci } 1308fd4e5da5Sopenharmony_ci str += if_blocks.back() >> std::vector<Block>({inner, merge_blocks.back()}); 1309fd4e5da5Sopenharmony_ci str += inner >> merge_blocks.back(); 1310fd4e5da5Sopenharmony_ci for (int i = N - 1; i > 0; i--) { 1311fd4e5da5Sopenharmony_ci str += merge_blocks[i] >> merge_blocks[i - 1]; 1312fd4e5da5Sopenharmony_ci } 1313fd4e5da5Sopenharmony_ci str += merge_blocks[0]; 1314fd4e5da5Sopenharmony_ci str += "OpFunctionEnd"; 1315fd4e5da5Sopenharmony_ci 1316fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1317fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1318fd4e5da5Sopenharmony_ci} 1319fd4e5da5Sopenharmony_ci 1320fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, BackEdgeBlockDoesntPostDominateContinueTargetBad) { 1321fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 1322fd4e5da5Sopenharmony_ci Block entry("entry"); 1323fd4e5da5Sopenharmony_ci Block loop1("loop1", spv::Op::OpBranchConditional); 1324fd4e5da5Sopenharmony_ci Block loop2("loop2", spv::Op::OpBranchConditional); 1325fd4e5da5Sopenharmony_ci Block loop2_merge("loop2_merge"); 1326fd4e5da5Sopenharmony_ci Block loop1_cont("loop1_cont", spv::Op::OpBranchConditional); 1327fd4e5da5Sopenharmony_ci Block be_block("be_block"); 1328fd4e5da5Sopenharmony_ci Block exit("exit", spv::Op::OpReturn); 1329fd4e5da5Sopenharmony_ci 1330fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 1331fd4e5da5Sopenharmony_ci if (is_shader) { 1332fd4e5da5Sopenharmony_ci loop1.SetBody("OpLoopMerge %exit %loop1_cont None\n"); 1333fd4e5da5Sopenharmony_ci loop2.SetBody("OpLoopMerge %loop2_merge %loop2 None\n"); 1334fd4e5da5Sopenharmony_ci } 1335fd4e5da5Sopenharmony_ci 1336fd4e5da5Sopenharmony_ci std::string str = 1337fd4e5da5Sopenharmony_ci GetDefaultHeader(GetParam()) + 1338fd4e5da5Sopenharmony_ci nameOps("loop1", "loop2", "be_block", "loop1_cont", "loop2_merge") + 1339fd4e5da5Sopenharmony_ci types_consts() + "%func = OpFunction %voidt None %funct\n"; 1340fd4e5da5Sopenharmony_ci 1341fd4e5da5Sopenharmony_ci str += entry >> loop1; 1342fd4e5da5Sopenharmony_ci str += loop1 >> std::vector<Block>({loop2, exit}); 1343fd4e5da5Sopenharmony_ci str += loop2 >> std::vector<Block>({loop2, loop2_merge}); 1344fd4e5da5Sopenharmony_ci str += loop2_merge >> loop1_cont; 1345fd4e5da5Sopenharmony_ci str += loop1_cont >> std::vector<Block>({be_block, exit}); 1346fd4e5da5Sopenharmony_ci str += be_block >> loop1; 1347fd4e5da5Sopenharmony_ci str += exit; 1348fd4e5da5Sopenharmony_ci str += "OpFunctionEnd"; 1349fd4e5da5Sopenharmony_ci 1350fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1351fd4e5da5Sopenharmony_ci if (GetParam() == spv::Capability::Shader) { 1352fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 1353fd4e5da5Sopenharmony_ci EXPECT_THAT( 1354fd4e5da5Sopenharmony_ci getDiagnosticString(), 1355fd4e5da5Sopenharmony_ci MatchesRegex( 1356fd4e5da5Sopenharmony_ci "The continue construct with the continue target " 1357fd4e5da5Sopenharmony_ci "'.\\[%loop1_cont\\]' is not structurally post dominated by the " 1358fd4e5da5Sopenharmony_ci "back-edge block '.\\[%be_block\\]'\n" 1359fd4e5da5Sopenharmony_ci " %be_block = OpLabel\n")); 1360fd4e5da5Sopenharmony_ci } else { 1361fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1362fd4e5da5Sopenharmony_ci } 1363fd4e5da5Sopenharmony_ci} 1364fd4e5da5Sopenharmony_ci 1365fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, BranchingToNonLoopHeaderBlockBad) { 1366fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 1367fd4e5da5Sopenharmony_ci Block entry("entry"); 1368fd4e5da5Sopenharmony_ci Block split("split", spv::Op::OpBranchConditional); 1369fd4e5da5Sopenharmony_ci Block t("t"); 1370fd4e5da5Sopenharmony_ci Block f("f"); 1371fd4e5da5Sopenharmony_ci Block exit("exit", spv::Op::OpReturn); 1372fd4e5da5Sopenharmony_ci 1373fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 1374fd4e5da5Sopenharmony_ci if (is_shader) split.SetBody("OpSelectionMerge %exit None\n"); 1375fd4e5da5Sopenharmony_ci 1376fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + nameOps("split", "f") + 1377fd4e5da5Sopenharmony_ci types_consts() + 1378fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 1379fd4e5da5Sopenharmony_ci 1380fd4e5da5Sopenharmony_ci str += entry >> split; 1381fd4e5da5Sopenharmony_ci str += split >> std::vector<Block>({t, f}); 1382fd4e5da5Sopenharmony_ci str += t >> exit; 1383fd4e5da5Sopenharmony_ci str += f >> split; 1384fd4e5da5Sopenharmony_ci str += exit; 1385fd4e5da5Sopenharmony_ci str += "OpFunctionEnd"; 1386fd4e5da5Sopenharmony_ci 1387fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1388fd4e5da5Sopenharmony_ci if (is_shader) { 1389fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 1390fd4e5da5Sopenharmony_ci EXPECT_THAT( 1391fd4e5da5Sopenharmony_ci getDiagnosticString(), 1392fd4e5da5Sopenharmony_ci MatchesRegex("Back-edges \\('.\\[%f\\]' -> '.\\[%split\\]'\\) can only " 1393fd4e5da5Sopenharmony_ci "be formed between a block and a loop header.\n" 1394fd4e5da5Sopenharmony_ci " %f = OpLabel\n")); 1395fd4e5da5Sopenharmony_ci } else { 1396fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1397fd4e5da5Sopenharmony_ci } 1398fd4e5da5Sopenharmony_ci} 1399fd4e5da5Sopenharmony_ci 1400fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, BranchingToSameNonLoopHeaderBlockBad) { 1401fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 1402fd4e5da5Sopenharmony_ci Block entry("entry"); 1403fd4e5da5Sopenharmony_ci Block split("split", spv::Op::OpBranchConditional); 1404fd4e5da5Sopenharmony_ci Block exit("exit", spv::Op::OpReturn); 1405fd4e5da5Sopenharmony_ci 1406fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 1407fd4e5da5Sopenharmony_ci if (is_shader) split.SetBody("OpSelectionMerge %exit None\n"); 1408fd4e5da5Sopenharmony_ci 1409fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + nameOps("split") + 1410fd4e5da5Sopenharmony_ci types_consts() + 1411fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 1412fd4e5da5Sopenharmony_ci 1413fd4e5da5Sopenharmony_ci str += entry >> split; 1414fd4e5da5Sopenharmony_ci str += split >> std::vector<Block>({split, exit}); 1415fd4e5da5Sopenharmony_ci str += exit; 1416fd4e5da5Sopenharmony_ci str += "OpFunctionEnd"; 1417fd4e5da5Sopenharmony_ci 1418fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1419fd4e5da5Sopenharmony_ci if (is_shader) { 1420fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 1421fd4e5da5Sopenharmony_ci EXPECT_THAT( 1422fd4e5da5Sopenharmony_ci getDiagnosticString(), 1423fd4e5da5Sopenharmony_ci MatchesRegex( 1424fd4e5da5Sopenharmony_ci "Back-edges \\('.\\[%split\\]' -> '.\\[%split\\]'\\) can only be " 1425fd4e5da5Sopenharmony_ci "formed between a block and a loop header.\n %split = OpLabel\n")); 1426fd4e5da5Sopenharmony_ci } else { 1427fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1428fd4e5da5Sopenharmony_ci } 1429fd4e5da5Sopenharmony_ci} 1430fd4e5da5Sopenharmony_ci 1431fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, MultipleBackEdgeBlocksToLoopHeaderBad) { 1432fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 1433fd4e5da5Sopenharmony_ci Block entry("entry"); 1434fd4e5da5Sopenharmony_ci Block loop("loop", spv::Op::OpBranchConditional); 1435fd4e5da5Sopenharmony_ci Block back0("back0"); 1436fd4e5da5Sopenharmony_ci Block back1("back1"); 1437fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 1438fd4e5da5Sopenharmony_ci 1439fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 1440fd4e5da5Sopenharmony_ci if (is_shader) loop.SetBody("OpLoopMerge %merge %back0 None\n"); 1441fd4e5da5Sopenharmony_ci 1442fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 1443fd4e5da5Sopenharmony_ci nameOps("loop", "back0", "back1") + types_consts() + 1444fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 1445fd4e5da5Sopenharmony_ci 1446fd4e5da5Sopenharmony_ci str += entry >> loop; 1447fd4e5da5Sopenharmony_ci str += loop >> std::vector<Block>({back0, back1}); 1448fd4e5da5Sopenharmony_ci str += back0 >> loop; 1449fd4e5da5Sopenharmony_ci str += back1 >> loop; 1450fd4e5da5Sopenharmony_ci str += merge; 1451fd4e5da5Sopenharmony_ci str += "OpFunctionEnd"; 1452fd4e5da5Sopenharmony_ci 1453fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1454fd4e5da5Sopenharmony_ci if (is_shader) { 1455fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 1456fd4e5da5Sopenharmony_ci EXPECT_THAT( 1457fd4e5da5Sopenharmony_ci getDiagnosticString(), 1458fd4e5da5Sopenharmony_ci MatchesRegex( 1459fd4e5da5Sopenharmony_ci "Loop header '.\\[%loop\\]' is targeted by 2 back-edge blocks but " 1460fd4e5da5Sopenharmony_ci "the standard requires exactly one\n %loop = OpLabel\n")) 1461fd4e5da5Sopenharmony_ci << str; 1462fd4e5da5Sopenharmony_ci } else { 1463fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1464fd4e5da5Sopenharmony_ci } 1465fd4e5da5Sopenharmony_ci} 1466fd4e5da5Sopenharmony_ci 1467fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, ContinueTargetMustBePostDominatedByBackEdge) { 1468fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 1469fd4e5da5Sopenharmony_ci Block entry("entry"); 1470fd4e5da5Sopenharmony_ci Block loop("loop", spv::Op::OpBranchConditional); 1471fd4e5da5Sopenharmony_ci Block cheader("cheader", spv::Op::OpBranchConditional); 1472fd4e5da5Sopenharmony_ci Block be_block("be_block"); 1473fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 1474fd4e5da5Sopenharmony_ci Block exit("exit", spv::Op::OpReturn); 1475fd4e5da5Sopenharmony_ci 1476fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 1477fd4e5da5Sopenharmony_ci if (is_shader) loop.SetBody("OpLoopMerge %merge %cheader None\n"); 1478fd4e5da5Sopenharmony_ci 1479fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 1480fd4e5da5Sopenharmony_ci nameOps("cheader", "be_block") + types_consts() + 1481fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 1482fd4e5da5Sopenharmony_ci 1483fd4e5da5Sopenharmony_ci str += entry >> loop; 1484fd4e5da5Sopenharmony_ci str += loop >> std::vector<Block>({cheader, merge}); 1485fd4e5da5Sopenharmony_ci str += cheader >> std::vector<Block>({exit, be_block}); 1486fd4e5da5Sopenharmony_ci str += exit; // Branches out of a continue construct 1487fd4e5da5Sopenharmony_ci str += be_block >> loop; 1488fd4e5da5Sopenharmony_ci str += merge; 1489fd4e5da5Sopenharmony_ci str += "OpFunctionEnd"; 1490fd4e5da5Sopenharmony_ci 1491fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1492fd4e5da5Sopenharmony_ci if (is_shader) { 1493fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 1494fd4e5da5Sopenharmony_ci EXPECT_THAT( 1495fd4e5da5Sopenharmony_ci getDiagnosticString(), 1496fd4e5da5Sopenharmony_ci MatchesRegex( 1497fd4e5da5Sopenharmony_ci "The continue construct with the continue target " 1498fd4e5da5Sopenharmony_ci "'.\\[%cheader\\]' is not structurally post dominated by the " 1499fd4e5da5Sopenharmony_ci "back-edge block '.\\[%be_block\\]'\n" 1500fd4e5da5Sopenharmony_ci " %be_block = OpLabel\n")); 1501fd4e5da5Sopenharmony_ci } else { 1502fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1503fd4e5da5Sopenharmony_ci } 1504fd4e5da5Sopenharmony_ci} 1505fd4e5da5Sopenharmony_ci 1506fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, BranchOutOfConstructToMergeBad) { 1507fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 1508fd4e5da5Sopenharmony_ci Block entry("entry"); 1509fd4e5da5Sopenharmony_ci Block loop("loop", spv::Op::OpBranchConditional); 1510fd4e5da5Sopenharmony_ci Block cont("cont", spv::Op::OpBranchConditional); 1511fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 1512fd4e5da5Sopenharmony_ci 1513fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 1514fd4e5da5Sopenharmony_ci if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n"); 1515fd4e5da5Sopenharmony_ci 1516fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + nameOps("cont", "loop") + 1517fd4e5da5Sopenharmony_ci types_consts() + 1518fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 1519fd4e5da5Sopenharmony_ci 1520fd4e5da5Sopenharmony_ci str += entry >> loop; 1521fd4e5da5Sopenharmony_ci str += loop >> std::vector<Block>({cont, merge}); 1522fd4e5da5Sopenharmony_ci str += cont >> std::vector<Block>({loop, merge}); 1523fd4e5da5Sopenharmony_ci str += merge; 1524fd4e5da5Sopenharmony_ci str += "OpFunctionEnd"; 1525fd4e5da5Sopenharmony_ci 1526fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1527fd4e5da5Sopenharmony_ci if (is_shader) { 1528fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 1529fd4e5da5Sopenharmony_ci EXPECT_THAT( 1530fd4e5da5Sopenharmony_ci getDiagnosticString(), 1531fd4e5da5Sopenharmony_ci MatchesRegex("The continue construct with the continue target " 1532fd4e5da5Sopenharmony_ci "'.\\[%loop\\]' is not structurally post dominated by the " 1533fd4e5da5Sopenharmony_ci "back-edge block '.\\[%cont\\]'\n" 1534fd4e5da5Sopenharmony_ci " %cont = OpLabel\n")) 1535fd4e5da5Sopenharmony_ci << str; 1536fd4e5da5Sopenharmony_ci } else { 1537fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1538fd4e5da5Sopenharmony_ci } 1539fd4e5da5Sopenharmony_ci} 1540fd4e5da5Sopenharmony_ci 1541fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, BranchOutOfConstructBad) { 1542fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 1543fd4e5da5Sopenharmony_ci Block entry("entry"); 1544fd4e5da5Sopenharmony_ci Block loop("loop", spv::Op::OpBranchConditional); 1545fd4e5da5Sopenharmony_ci Block cont("cont", spv::Op::OpBranchConditional); 1546fd4e5da5Sopenharmony_ci Block merge("merge"); 1547fd4e5da5Sopenharmony_ci Block exit("exit", spv::Op::OpReturn); 1548fd4e5da5Sopenharmony_ci 1549fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 1550fd4e5da5Sopenharmony_ci if (is_shader) loop.SetBody("OpLoopMerge %merge %loop None\n"); 1551fd4e5da5Sopenharmony_ci 1552fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + nameOps("cont", "loop") + 1553fd4e5da5Sopenharmony_ci types_consts() + 1554fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 1555fd4e5da5Sopenharmony_ci 1556fd4e5da5Sopenharmony_ci str += entry >> loop; 1557fd4e5da5Sopenharmony_ci str += loop >> std::vector<Block>({cont, merge}); 1558fd4e5da5Sopenharmony_ci str += cont >> std::vector<Block>({loop, exit}); 1559fd4e5da5Sopenharmony_ci str += merge >> exit; 1560fd4e5da5Sopenharmony_ci str += exit; 1561fd4e5da5Sopenharmony_ci str += "OpFunctionEnd"; 1562fd4e5da5Sopenharmony_ci 1563fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1564fd4e5da5Sopenharmony_ci if (is_shader) { 1565fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 1566fd4e5da5Sopenharmony_ci EXPECT_THAT( 1567fd4e5da5Sopenharmony_ci getDiagnosticString(), 1568fd4e5da5Sopenharmony_ci MatchesRegex("The continue construct with the continue target " 1569fd4e5da5Sopenharmony_ci "'.\\[%loop\\]' is not structurally post dominated by the " 1570fd4e5da5Sopenharmony_ci "back-edge block '.\\[%cont\\]'\n" 1571fd4e5da5Sopenharmony_ci " %cont = OpLabel\n")); 1572fd4e5da5Sopenharmony_ci } else { 1573fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1574fd4e5da5Sopenharmony_ci } 1575fd4e5da5Sopenharmony_ci} 1576fd4e5da5Sopenharmony_ci 1577fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, OpSwitchToUnreachableBlock) { 1578fd4e5da5Sopenharmony_ci Block entry("entry", spv::Op::OpSwitch); 1579fd4e5da5Sopenharmony_ci Block case0("case0"); 1580fd4e5da5Sopenharmony_ci Block case1("case1"); 1581fd4e5da5Sopenharmony_ci Block case2("case2"); 1582fd4e5da5Sopenharmony_ci Block def("default", spv::Op::OpUnreachable); 1583fd4e5da5Sopenharmony_ci Block phi("phi", spv::Op::OpReturn); 1584fd4e5da5Sopenharmony_ci 1585fd4e5da5Sopenharmony_ci std::string str = R"( 1586fd4e5da5Sopenharmony_ciOpCapability Shader 1587fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 1588fd4e5da5Sopenharmony_ciOpEntryPoint GLCompute %main "main" %id 1589fd4e5da5Sopenharmony_ciOpExecutionMode %main LocalSize 1 1 1 1590fd4e5da5Sopenharmony_ciOpSource GLSL 430 1591fd4e5da5Sopenharmony_ciOpName %main "main" 1592fd4e5da5Sopenharmony_ciOpDecorate %id BuiltIn GlobalInvocationId 1593fd4e5da5Sopenharmony_ci%void = OpTypeVoid 1594fd4e5da5Sopenharmony_ci%voidf = OpTypeFunction %void 1595fd4e5da5Sopenharmony_ci%u32 = OpTypeInt 32 0 1596fd4e5da5Sopenharmony_ci%f32 = OpTypeFloat 32 1597fd4e5da5Sopenharmony_ci%uvec3 = OpTypeVector %u32 3 1598fd4e5da5Sopenharmony_ci%fvec3 = OpTypeVector %f32 3 1599fd4e5da5Sopenharmony_ci%uvec3ptr = OpTypePointer Input %uvec3 1600fd4e5da5Sopenharmony_ci%id = OpVariable %uvec3ptr Input 1601fd4e5da5Sopenharmony_ci%one = OpConstant %u32 1 1602fd4e5da5Sopenharmony_ci%three = OpConstant %u32 3 1603fd4e5da5Sopenharmony_ci%main = OpFunction %void None %voidf 1604fd4e5da5Sopenharmony_ci)"; 1605fd4e5da5Sopenharmony_ci 1606fd4e5da5Sopenharmony_ci entry.SetBody( 1607fd4e5da5Sopenharmony_ci "%idval = OpLoad %uvec3 %id\n" 1608fd4e5da5Sopenharmony_ci "%x = OpCompositeExtract %u32 %idval 0\n" 1609fd4e5da5Sopenharmony_ci "%selector = OpUMod %u32 %x %three\n" 1610fd4e5da5Sopenharmony_ci "OpSelectionMerge %phi None\n"); 1611fd4e5da5Sopenharmony_ci str += entry >> std::vector<Block>({def, case0, case1, case2}); 1612fd4e5da5Sopenharmony_ci str += case1 >> phi; 1613fd4e5da5Sopenharmony_ci str += def; 1614fd4e5da5Sopenharmony_ci str += phi; 1615fd4e5da5Sopenharmony_ci str += case0 >> phi; 1616fd4e5da5Sopenharmony_ci str += case2 >> phi; 1617fd4e5da5Sopenharmony_ci str += "OpFunctionEnd"; 1618fd4e5da5Sopenharmony_ci 1619fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1620fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 1621fd4e5da5Sopenharmony_ci} 1622fd4e5da5Sopenharmony_ci 1623fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, LoopWithZeroBackEdgesBad) { 1624fd4e5da5Sopenharmony_ci std::string str = R"( 1625fd4e5da5Sopenharmony_ci OpCapability Shader 1626fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 1627fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %main "main" 1628fd4e5da5Sopenharmony_ci OpExecutionMode %main OriginUpperLeft 1629fd4e5da5Sopenharmony_ci OpName %loop "loop" 1630fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid 1631fd4e5da5Sopenharmony_ci%funct = OpTypeFunction %voidt 1632fd4e5da5Sopenharmony_ci%main = OpFunction %voidt None %funct 1633fd4e5da5Sopenharmony_ci%loop = OpLabel 1634fd4e5da5Sopenharmony_ci OpLoopMerge %exit %loop None 1635fd4e5da5Sopenharmony_ci OpBranch %exit 1636fd4e5da5Sopenharmony_ci%exit = OpLabel 1637fd4e5da5Sopenharmony_ci OpReturn 1638fd4e5da5Sopenharmony_ci OpFunctionEnd 1639fd4e5da5Sopenharmony_ci)"; 1640fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1641fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 1642fd4e5da5Sopenharmony_ci EXPECT_THAT( 1643fd4e5da5Sopenharmony_ci getDiagnosticString(), 1644fd4e5da5Sopenharmony_ci MatchesRegex("Loop header '.\\[%loop\\]' is targeted by " 1645fd4e5da5Sopenharmony_ci "0 back-edge blocks but the standard requires exactly " 1646fd4e5da5Sopenharmony_ci "one\n %loop = OpLabel\n")); 1647fd4e5da5Sopenharmony_ci} 1648fd4e5da5Sopenharmony_ci 1649fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, LoopWithBackEdgeFromUnreachableContinueConstructGood) { 1650fd4e5da5Sopenharmony_ci std::string str = R"( 1651fd4e5da5Sopenharmony_ci OpCapability Shader 1652fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 1653fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %main "main" 1654fd4e5da5Sopenharmony_ci OpExecutionMode %main OriginUpperLeft 1655fd4e5da5Sopenharmony_ci OpName %loop "loop" 1656fd4e5da5Sopenharmony_ci%voidt = OpTypeVoid 1657fd4e5da5Sopenharmony_ci%funct = OpTypeFunction %voidt 1658fd4e5da5Sopenharmony_ci%floatt = OpTypeFloat 32 1659fd4e5da5Sopenharmony_ci%boolt = OpTypeBool 1660fd4e5da5Sopenharmony_ci%one = OpConstant %floatt 1 1661fd4e5da5Sopenharmony_ci%two = OpConstant %floatt 2 1662fd4e5da5Sopenharmony_ci%main = OpFunction %voidt None %funct 1663fd4e5da5Sopenharmony_ci%entry = OpLabel 1664fd4e5da5Sopenharmony_ci OpBranch %loop 1665fd4e5da5Sopenharmony_ci%loop = OpLabel 1666fd4e5da5Sopenharmony_ci OpLoopMerge %exit %cont None 1667fd4e5da5Sopenharmony_ci OpBranch %16 1668fd4e5da5Sopenharmony_ci%16 = OpLabel 1669fd4e5da5Sopenharmony_ci%cond = OpFOrdLessThan %boolt %one %two 1670fd4e5da5Sopenharmony_ci OpBranchConditional %cond %body %exit 1671fd4e5da5Sopenharmony_ci%body = OpLabel 1672fd4e5da5Sopenharmony_ci OpReturn 1673fd4e5da5Sopenharmony_ci%cont = OpLabel ; Reachable only from OpLoopMerge ContinueTarget parameter 1674fd4e5da5Sopenharmony_ci OpBranch %loop ; Should be considered a back-edge 1675fd4e5da5Sopenharmony_ci%exit = OpLabel 1676fd4e5da5Sopenharmony_ci OpReturn 1677fd4e5da5Sopenharmony_ci OpFunctionEnd 1678fd4e5da5Sopenharmony_ci)"; 1679fd4e5da5Sopenharmony_ci 1680fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1681fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString(); 1682fd4e5da5Sopenharmony_ci} 1683fd4e5da5Sopenharmony_ci 1684fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, 1685fd4e5da5Sopenharmony_ci NestedConstructWithUnreachableMergeBlockBranchingToOuterMergeBlock) { 1686fd4e5da5Sopenharmony_ci // Test for https://github.com/KhronosGroup/SPIRV-Tools/issues/297 1687fd4e5da5Sopenharmony_ci // The nested construct has an unreachable merge block. In the 1688fd4e5da5Sopenharmony_ci // augmented CFG that merge block 1689fd4e5da5Sopenharmony_ci // we still determine that the 1690fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 1691fd4e5da5Sopenharmony_ci Block entry("entry", spv::Op::OpBranchConditional); 1692fd4e5da5Sopenharmony_ci Block inner_head("inner_head", spv::Op::OpBranchConditional); 1693fd4e5da5Sopenharmony_ci Block inner_true("inner_true", spv::Op::OpReturn); 1694fd4e5da5Sopenharmony_ci Block inner_false("inner_false", spv::Op::OpReturn); 1695fd4e5da5Sopenharmony_ci Block inner_merge("inner_merge"); 1696fd4e5da5Sopenharmony_ci Block exit("exit", spv::Op::OpReturn); 1697fd4e5da5Sopenharmony_ci 1698fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 1699fd4e5da5Sopenharmony_ci if (is_shader) { 1700fd4e5da5Sopenharmony_ci entry.AppendBody("OpSelectionMerge %exit None\n"); 1701fd4e5da5Sopenharmony_ci inner_head.SetBody("OpSelectionMerge %inner_merge None\n"); 1702fd4e5da5Sopenharmony_ci } 1703fd4e5da5Sopenharmony_ci 1704fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 1705fd4e5da5Sopenharmony_ci nameOps("entry", "inner_merge", "exit") + types_consts() + 1706fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 1707fd4e5da5Sopenharmony_ci 1708fd4e5da5Sopenharmony_ci str += entry >> std::vector<Block>({inner_head, exit}); 1709fd4e5da5Sopenharmony_ci str += inner_head >> std::vector<Block>({inner_true, inner_false}); 1710fd4e5da5Sopenharmony_ci str += inner_true; 1711fd4e5da5Sopenharmony_ci str += inner_false; 1712fd4e5da5Sopenharmony_ci str += inner_merge >> exit; 1713fd4e5da5Sopenharmony_ci str += exit; 1714fd4e5da5Sopenharmony_ci str += "OpFunctionEnd"; 1715fd4e5da5Sopenharmony_ci 1716fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1717fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) << getDiagnosticString(); 1718fd4e5da5Sopenharmony_ci} 1719fd4e5da5Sopenharmony_ci 1720fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, ContinueTargetCanBeMergeBlockForNestedStructure) { 1721fd4e5da5Sopenharmony_ci // The continue construct cannot be the merge target of a nested selection 1722fd4e5da5Sopenharmony_ci // because the loop construct must contain "if_merge" because it contains 1723fd4e5da5Sopenharmony_ci // "if_head". 1724fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 1725fd4e5da5Sopenharmony_ci Block entry("entry"); 1726fd4e5da5Sopenharmony_ci Block loop("loop"); 1727fd4e5da5Sopenharmony_ci Block if_head("if_head", spv::Op::OpBranchConditional); 1728fd4e5da5Sopenharmony_ci Block if_true("if_true"); 1729fd4e5da5Sopenharmony_ci Block if_merge("if_merge", spv::Op::OpBranchConditional); 1730fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 1731fd4e5da5Sopenharmony_ci 1732fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 1733fd4e5da5Sopenharmony_ci if (is_shader) { 1734fd4e5da5Sopenharmony_ci loop.SetBody("OpLoopMerge %merge %if_merge None\n"); 1735fd4e5da5Sopenharmony_ci if_head.SetBody("OpSelectionMerge %if_merge None\n"); 1736fd4e5da5Sopenharmony_ci } 1737fd4e5da5Sopenharmony_ci 1738fd4e5da5Sopenharmony_ci std::string str = 1739fd4e5da5Sopenharmony_ci GetDefaultHeader(GetParam()) + 1740fd4e5da5Sopenharmony_ci nameOps("entry", "loop", "if_head", "if_true", "if_merge", "merge") + 1741fd4e5da5Sopenharmony_ci types_consts() + "%func = OpFunction %voidt None %funct\n"; 1742fd4e5da5Sopenharmony_ci 1743fd4e5da5Sopenharmony_ci str += entry >> loop; 1744fd4e5da5Sopenharmony_ci str += loop >> if_head; 1745fd4e5da5Sopenharmony_ci str += if_head >> std::vector<Block>({if_true, if_merge}); 1746fd4e5da5Sopenharmony_ci str += if_true >> if_merge; 1747fd4e5da5Sopenharmony_ci str += if_merge >> std::vector<Block>({loop, merge}); 1748fd4e5da5Sopenharmony_ci str += merge; 1749fd4e5da5Sopenharmony_ci str += "OpFunctionEnd"; 1750fd4e5da5Sopenharmony_ci 1751fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1752fd4e5da5Sopenharmony_ci if (is_shader) { 1753fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 1754fd4e5da5Sopenharmony_ci EXPECT_THAT( 1755fd4e5da5Sopenharmony_ci getDiagnosticString(), 1756fd4e5da5Sopenharmony_ci HasSubstr( 1757fd4e5da5Sopenharmony_ci "Header block '3[%if_head]' is contained in the loop construct " 1758fd4e5da5Sopenharmony_ci "headed " 1759fd4e5da5Sopenharmony_ci "by '2[%loop]', but its merge block '5[%if_merge]' is not")); 1760fd4e5da5Sopenharmony_ci } else { 1761fd4e5da5Sopenharmony_ci EXPECT_THAT(SPV_SUCCESS, ValidateInstructions()); 1762fd4e5da5Sopenharmony_ci } 1763fd4e5da5Sopenharmony_ci} 1764fd4e5da5Sopenharmony_ci 1765fd4e5da5Sopenharmony_ciTEST_P(ValidateCFG, SingleLatchBlockMultipleBranchesToLoopHeader) { 1766fd4e5da5Sopenharmony_ci // This test case ensures we allow both branches of a loop latch block 1767fd4e5da5Sopenharmony_ci // to go back to the loop header. It still counts as a single back edge. 1768fd4e5da5Sopenharmony_ci bool is_shader = GetParam() == spv::Capability::Shader; 1769fd4e5da5Sopenharmony_ci Block entry("entry"); 1770fd4e5da5Sopenharmony_ci Block loop("loop", spv::Op::OpBranchConditional); 1771fd4e5da5Sopenharmony_ci Block latch("latch", spv::Op::OpBranchConditional); 1772fd4e5da5Sopenharmony_ci Block merge("merge", spv::Op::OpReturn); 1773fd4e5da5Sopenharmony_ci 1774fd4e5da5Sopenharmony_ci entry.SetBody("%cond = OpSLessThan %boolt %one %two\n"); 1775fd4e5da5Sopenharmony_ci if (is_shader) { 1776fd4e5da5Sopenharmony_ci loop.SetBody("OpLoopMerge %merge %latch None\n"); 1777fd4e5da5Sopenharmony_ci } 1778fd4e5da5Sopenharmony_ci 1779fd4e5da5Sopenharmony_ci std::string str = GetDefaultHeader(GetParam()) + 1780fd4e5da5Sopenharmony_ci nameOps("entry", "loop", "latch", "merge") + 1781fd4e5da5Sopenharmony_ci types_consts() + 1782fd4e5da5Sopenharmony_ci "%func = OpFunction %voidt None %funct\n"; 1783fd4e5da5Sopenharmony_ci 1784fd4e5da5Sopenharmony_ci str += entry >> loop; 1785fd4e5da5Sopenharmony_ci str += loop >> std::vector<Block>({latch, merge}); 1786fd4e5da5Sopenharmony_ci str += latch >> std::vector<Block>({loop, loop}); // This is the key 1787fd4e5da5Sopenharmony_ci str += merge; 1788fd4e5da5Sopenharmony_ci str += "OpFunctionEnd"; 1789fd4e5da5Sopenharmony_ci 1790fd4e5da5Sopenharmony_ci CompileSuccessfully(str); 1791fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()) 1792fd4e5da5Sopenharmony_ci << str << getDiagnosticString(); 1793fd4e5da5Sopenharmony_ci} 1794fd4e5da5Sopenharmony_ci 1795fd4e5da5Sopenharmony_ci// Unit test to check the case where a basic block is the entry block of 2 1796fd4e5da5Sopenharmony_ci// different constructs. In this case, the basic block is the entry block of a 1797fd4e5da5Sopenharmony_ci// continue construct as well as a selection construct. See issue# 517 for more 1798fd4e5da5Sopenharmony_ci// details. 1799fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, BasicBlockIsEntryBlockOfTwoConstructsGood) { 1800fd4e5da5Sopenharmony_ci std::string spirv = R"( 1801fd4e5da5Sopenharmony_ci OpCapability Shader 1802fd4e5da5Sopenharmony_ci OpCapability Linkage 1803fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 1804fd4e5da5Sopenharmony_ci %void = OpTypeVoid 1805fd4e5da5Sopenharmony_ci %bool = OpTypeBool 1806fd4e5da5Sopenharmony_ci %int = OpTypeInt 32 1 1807fd4e5da5Sopenharmony_ci %void_func = OpTypeFunction %void 1808fd4e5da5Sopenharmony_ci %int_0 = OpConstant %int 0 1809fd4e5da5Sopenharmony_ci %testfun = OpFunction %void None %void_func 1810fd4e5da5Sopenharmony_ci %label_1 = OpLabel 1811fd4e5da5Sopenharmony_ci OpBranch %start 1812fd4e5da5Sopenharmony_ci %start = OpLabel 1813fd4e5da5Sopenharmony_ci %cond = OpSLessThan %bool %int_0 %int_0 1814fd4e5da5Sopenharmony_ci ; 1815fd4e5da5Sopenharmony_ci ; Note: In this case, the "target" block is both the entry block of 1816fd4e5da5Sopenharmony_ci ; the continue construct of the loop as well as the entry block of 1817fd4e5da5Sopenharmony_ci ; the selection construct. 1818fd4e5da5Sopenharmony_ci ; 1819fd4e5da5Sopenharmony_ci OpLoopMerge %loop_merge %target None 1820fd4e5da5Sopenharmony_ci OpBranchConditional %cond %target %loop_merge 1821fd4e5da5Sopenharmony_ci %loop_merge = OpLabel 1822fd4e5da5Sopenharmony_ci OpReturn 1823fd4e5da5Sopenharmony_ci %target = OpLabel 1824fd4e5da5Sopenharmony_ci OpSelectionMerge %selection_merge None 1825fd4e5da5Sopenharmony_ci OpBranchConditional %cond %do_stuff %do_other_stuff 1826fd4e5da5Sopenharmony_ci %do_other_stuff = OpLabel 1827fd4e5da5Sopenharmony_ci OpBranch %selection_merge 1828fd4e5da5Sopenharmony_ci %selection_merge = OpLabel 1829fd4e5da5Sopenharmony_ci OpBranch %start 1830fd4e5da5Sopenharmony_ci %do_stuff = OpLabel 1831fd4e5da5Sopenharmony_ci OpBranch %selection_merge 1832fd4e5da5Sopenharmony_ci OpFunctionEnd 1833fd4e5da5Sopenharmony_ci )"; 1834fd4e5da5Sopenharmony_ci CompileSuccessfully(spirv); 1835fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 1836fd4e5da5Sopenharmony_ci} 1837fd4e5da5Sopenharmony_ci 1838fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, OpReturnInNonVoidFunc) { 1839fd4e5da5Sopenharmony_ci std::string spirv = R"( 1840fd4e5da5Sopenharmony_ci OpCapability Shader 1841fd4e5da5Sopenharmony_ci OpCapability Linkage 1842fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 1843fd4e5da5Sopenharmony_ci %int = OpTypeInt 32 1 1844fd4e5da5Sopenharmony_ci %int_func = OpTypeFunction %int 1845fd4e5da5Sopenharmony_ci %testfun = OpFunction %int None %int_func 1846fd4e5da5Sopenharmony_ci %label_1 = OpLabel 1847fd4e5da5Sopenharmony_ci OpReturn 1848fd4e5da5Sopenharmony_ci OpFunctionEnd 1849fd4e5da5Sopenharmony_ci )"; 1850fd4e5da5Sopenharmony_ci CompileSuccessfully(spirv); 1851fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 1852fd4e5da5Sopenharmony_ci EXPECT_THAT( 1853fd4e5da5Sopenharmony_ci getDiagnosticString(), 1854fd4e5da5Sopenharmony_ci HasSubstr( 1855fd4e5da5Sopenharmony_ci "OpReturn can only be called from a function with void return type.\n" 1856fd4e5da5Sopenharmony_ci " OpReturn")); 1857fd4e5da5Sopenharmony_ci} 1858fd4e5da5Sopenharmony_ci 1859fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, StructuredCFGBranchIntoSelectionBody) { 1860fd4e5da5Sopenharmony_ci std::string spirv = R"( 1861fd4e5da5Sopenharmony_ciOpCapability Shader 1862fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 1863fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %func "func" 1864fd4e5da5Sopenharmony_ciOpExecutionMode %func OriginUpperLeft 1865fd4e5da5Sopenharmony_ci%void = OpTypeVoid 1866fd4e5da5Sopenharmony_ci%bool = OpTypeBool 1867fd4e5da5Sopenharmony_ci%true = OpConstantTrue %bool 1868fd4e5da5Sopenharmony_ci%functy = OpTypeFunction %void 1869fd4e5da5Sopenharmony_ci%func = OpFunction %void None %functy 1870fd4e5da5Sopenharmony_ci%entry = OpLabel 1871fd4e5da5Sopenharmony_ciOpSelectionMerge %merge None 1872fd4e5da5Sopenharmony_ciOpBranchConditional %true %then %merge 1873fd4e5da5Sopenharmony_ci%merge = OpLabel 1874fd4e5da5Sopenharmony_ciOpBranch %then 1875fd4e5da5Sopenharmony_ci%then = OpLabel 1876fd4e5da5Sopenharmony_ciOpReturn 1877fd4e5da5Sopenharmony_ciOpFunctionEnd 1878fd4e5da5Sopenharmony_ci)"; 1879fd4e5da5Sopenharmony_ci 1880fd4e5da5Sopenharmony_ci CompileSuccessfully(spirv); 1881fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 1882fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 1883fd4e5da5Sopenharmony_ci HasSubstr("branches to the selection construct, but not to the " 1884fd4e5da5Sopenharmony_ci "selection header <ID> 6\n %7 = OpLabel")); 1885fd4e5da5Sopenharmony_ci} 1886fd4e5da5Sopenharmony_ci 1887fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, SwitchDefaultOnly) { 1888fd4e5da5Sopenharmony_ci std::string text = R"( 1889fd4e5da5Sopenharmony_ciOpCapability Shader 1890fd4e5da5Sopenharmony_ciOpCapability Linkage 1891fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 1892fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 1893fd4e5da5Sopenharmony_ci%2 = OpTypeInt 32 0 1894fd4e5da5Sopenharmony_ci%3 = OpConstant %2 0 1895fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %1 1896fd4e5da5Sopenharmony_ci%5 = OpFunction %1 None %4 1897fd4e5da5Sopenharmony_ci%6 = OpLabel 1898fd4e5da5Sopenharmony_ciOpSelectionMerge %7 None 1899fd4e5da5Sopenharmony_ciOpSwitch %3 %7 1900fd4e5da5Sopenharmony_ci%7 = OpLabel 1901fd4e5da5Sopenharmony_ciOpReturn 1902fd4e5da5Sopenharmony_ciOpFunctionEnd 1903fd4e5da5Sopenharmony_ci)"; 1904fd4e5da5Sopenharmony_ci 1905fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 1906fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1907fd4e5da5Sopenharmony_ci} 1908fd4e5da5Sopenharmony_ci 1909fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, SwitchSingleCase) { 1910fd4e5da5Sopenharmony_ci std::string text = R"( 1911fd4e5da5Sopenharmony_ciOpCapability Shader 1912fd4e5da5Sopenharmony_ciOpCapability Linkage 1913fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 1914fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 1915fd4e5da5Sopenharmony_ci%2 = OpTypeInt 32 0 1916fd4e5da5Sopenharmony_ci%3 = OpConstant %2 0 1917fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %1 1918fd4e5da5Sopenharmony_ci%5 = OpFunction %1 None %4 1919fd4e5da5Sopenharmony_ci%6 = OpLabel 1920fd4e5da5Sopenharmony_ciOpSelectionMerge %7 None 1921fd4e5da5Sopenharmony_ciOpSwitch %3 %7 0 %8 1922fd4e5da5Sopenharmony_ci%8 = OpLabel 1923fd4e5da5Sopenharmony_ciOpBranch %7 1924fd4e5da5Sopenharmony_ci%7 = OpLabel 1925fd4e5da5Sopenharmony_ciOpReturn 1926fd4e5da5Sopenharmony_ciOpFunctionEnd 1927fd4e5da5Sopenharmony_ci)"; 1928fd4e5da5Sopenharmony_ci 1929fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 1930fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 1931fd4e5da5Sopenharmony_ci} 1932fd4e5da5Sopenharmony_ci 1933fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, MultipleFallThroughBlocks) { 1934fd4e5da5Sopenharmony_ci std::string text = R"( 1935fd4e5da5Sopenharmony_ciOpCapability Shader 1936fd4e5da5Sopenharmony_ciOpCapability Linkage 1937fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 1938fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 1939fd4e5da5Sopenharmony_ci%2 = OpTypeInt 32 0 1940fd4e5da5Sopenharmony_ci%3 = OpConstant %2 0 1941fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %1 1942fd4e5da5Sopenharmony_ci%5 = OpTypeBool 1943fd4e5da5Sopenharmony_ci%6 = OpConstantTrue %5 1944fd4e5da5Sopenharmony_ci%7 = OpFunction %1 None %4 1945fd4e5da5Sopenharmony_ci%8 = OpLabel 1946fd4e5da5Sopenharmony_ciOpSelectionMerge %9 None 1947fd4e5da5Sopenharmony_ciOpSwitch %3 %10 0 %11 1 %12 1948fd4e5da5Sopenharmony_ci%10 = OpLabel 1949fd4e5da5Sopenharmony_ciOpBranchConditional %6 %11 %12 1950fd4e5da5Sopenharmony_ci%11 = OpLabel 1951fd4e5da5Sopenharmony_ciOpBranch %9 1952fd4e5da5Sopenharmony_ci%12 = OpLabel 1953fd4e5da5Sopenharmony_ciOpBranch %9 1954fd4e5da5Sopenharmony_ci%9 = OpLabel 1955fd4e5da5Sopenharmony_ciOpReturn 1956fd4e5da5Sopenharmony_ciOpFunctionEnd 1957fd4e5da5Sopenharmony_ci)"; 1958fd4e5da5Sopenharmony_ci 1959fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 1960fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 1961fd4e5da5Sopenharmony_ci EXPECT_THAT( 1962fd4e5da5Sopenharmony_ci getDiagnosticString(), 1963fd4e5da5Sopenharmony_ci HasSubstr( 1964fd4e5da5Sopenharmony_ci "Case construct that targets '10[%10]' has branches to multiple " 1965fd4e5da5Sopenharmony_ci "other " 1966fd4e5da5Sopenharmony_ci "case construct targets '12[%12]' and '11[%11]'\n %10 = OpLabel")); 1967fd4e5da5Sopenharmony_ci} 1968fd4e5da5Sopenharmony_ci 1969fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, MultipleFallThroughToDefault) { 1970fd4e5da5Sopenharmony_ci std::string text = R"( 1971fd4e5da5Sopenharmony_ciOpCapability Shader 1972fd4e5da5Sopenharmony_ciOpCapability Linkage 1973fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 1974fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 1975fd4e5da5Sopenharmony_ci%2 = OpTypeInt 32 0 1976fd4e5da5Sopenharmony_ci%3 = OpConstant %2 0 1977fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %1 1978fd4e5da5Sopenharmony_ci%5 = OpTypeBool 1979fd4e5da5Sopenharmony_ci%6 = OpConstantTrue %5 1980fd4e5da5Sopenharmony_ci%7 = OpFunction %1 None %4 1981fd4e5da5Sopenharmony_ci%8 = OpLabel 1982fd4e5da5Sopenharmony_ciOpSelectionMerge %9 None 1983fd4e5da5Sopenharmony_ciOpSwitch %3 %10 0 %11 1 %12 1984fd4e5da5Sopenharmony_ci%10 = OpLabel 1985fd4e5da5Sopenharmony_ciOpBranch %9 1986fd4e5da5Sopenharmony_ci%11 = OpLabel 1987fd4e5da5Sopenharmony_ciOpBranch %10 1988fd4e5da5Sopenharmony_ci%12 = OpLabel 1989fd4e5da5Sopenharmony_ciOpBranch %10 1990fd4e5da5Sopenharmony_ci%9 = OpLabel 1991fd4e5da5Sopenharmony_ciOpReturn 1992fd4e5da5Sopenharmony_ciOpFunctionEnd 1993fd4e5da5Sopenharmony_ci)"; 1994fd4e5da5Sopenharmony_ci 1995fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 1996fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 1997fd4e5da5Sopenharmony_ci EXPECT_THAT( 1998fd4e5da5Sopenharmony_ci getDiagnosticString(), 1999fd4e5da5Sopenharmony_ci HasSubstr("Multiple case constructs have branches to the case construct " 2000fd4e5da5Sopenharmony_ci "that targets '10[%10]'\n %10 = OpLabel")); 2001fd4e5da5Sopenharmony_ci} 2002fd4e5da5Sopenharmony_ci 2003fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, MultipleFallThroughToNonDefault) { 2004fd4e5da5Sopenharmony_ci std::string text = R"( 2005fd4e5da5Sopenharmony_ciOpCapability Shader 2006fd4e5da5Sopenharmony_ciOpCapability Linkage 2007fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2008fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 2009fd4e5da5Sopenharmony_ci%2 = OpTypeInt 32 0 2010fd4e5da5Sopenharmony_ci%3 = OpConstant %2 0 2011fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %1 2012fd4e5da5Sopenharmony_ci%5 = OpTypeBool 2013fd4e5da5Sopenharmony_ci%6 = OpConstantTrue %5 2014fd4e5da5Sopenharmony_ci%7 = OpFunction %1 None %4 2015fd4e5da5Sopenharmony_ci%8 = OpLabel 2016fd4e5da5Sopenharmony_ciOpSelectionMerge %9 None 2017fd4e5da5Sopenharmony_ciOpSwitch %3 %10 0 %11 1 %12 2018fd4e5da5Sopenharmony_ci%10 = OpLabel 2019fd4e5da5Sopenharmony_ciOpBranch %12 2020fd4e5da5Sopenharmony_ci%11 = OpLabel 2021fd4e5da5Sopenharmony_ciOpBranch %12 2022fd4e5da5Sopenharmony_ci%12 = OpLabel 2023fd4e5da5Sopenharmony_ciOpBranch %9 2024fd4e5da5Sopenharmony_ci%9 = OpLabel 2025fd4e5da5Sopenharmony_ciOpReturn 2026fd4e5da5Sopenharmony_ciOpFunctionEnd 2027fd4e5da5Sopenharmony_ci)"; 2028fd4e5da5Sopenharmony_ci 2029fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2030fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 2031fd4e5da5Sopenharmony_ci EXPECT_THAT( 2032fd4e5da5Sopenharmony_ci getDiagnosticString(), 2033fd4e5da5Sopenharmony_ci HasSubstr("Multiple case constructs have branches to the case construct " 2034fd4e5da5Sopenharmony_ci "that targets '12[%12]'\n %12 = OpLabel")); 2035fd4e5da5Sopenharmony_ci} 2036fd4e5da5Sopenharmony_ci 2037fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, DuplicateTargetWithFallThrough) { 2038fd4e5da5Sopenharmony_ci std::string text = R"( 2039fd4e5da5Sopenharmony_ciOpCapability Shader 2040fd4e5da5Sopenharmony_ciOpCapability Linkage 2041fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2042fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 2043fd4e5da5Sopenharmony_ci%2 = OpTypeInt 32 0 2044fd4e5da5Sopenharmony_ci%3 = OpConstant %2 0 2045fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %1 2046fd4e5da5Sopenharmony_ci%5 = OpTypeBool 2047fd4e5da5Sopenharmony_ci%6 = OpConstantTrue %5 2048fd4e5da5Sopenharmony_ci%7 = OpFunction %1 None %4 2049fd4e5da5Sopenharmony_ci%8 = OpLabel 2050fd4e5da5Sopenharmony_ciOpSelectionMerge %9 None 2051fd4e5da5Sopenharmony_ciOpSwitch %3 %10 0 %10 1 %11 2052fd4e5da5Sopenharmony_ci%10 = OpLabel 2053fd4e5da5Sopenharmony_ciOpBranch %11 2054fd4e5da5Sopenharmony_ci%11 = OpLabel 2055fd4e5da5Sopenharmony_ciOpBranch %9 2056fd4e5da5Sopenharmony_ci%9 = OpLabel 2057fd4e5da5Sopenharmony_ciOpReturn 2058fd4e5da5Sopenharmony_ciOpFunctionEnd 2059fd4e5da5Sopenharmony_ci)"; 2060fd4e5da5Sopenharmony_ci 2061fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2062fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 2063fd4e5da5Sopenharmony_ci} 2064fd4e5da5Sopenharmony_ci 2065fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, OpSwitchTargetCannotBeOuterLoopMergeBlock) { 2066fd4e5da5Sopenharmony_ci std::string text = R"( 2067fd4e5da5Sopenharmony_ciOpCapability Shader 2068fd4e5da5Sopenharmony_ciOpCapability Linkage 2069fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2070fd4e5da5Sopenharmony_ci 2071fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 2072fd4e5da5Sopenharmony_ci%2 = OpTypeFunction %1 2073fd4e5da5Sopenharmony_ci%3 = OpTypeBool 2074fd4e5da5Sopenharmony_ci%4 = OpUndef %3 2075fd4e5da5Sopenharmony_ci%5 = OpTypeInt 32 0 2076fd4e5da5Sopenharmony_ci%6 = OpConstant %5 0 2077fd4e5da5Sopenharmony_ci 2078fd4e5da5Sopenharmony_ci%7 = OpFunction %1 None %2 2079fd4e5da5Sopenharmony_ci 2080fd4e5da5Sopenharmony_ci%8 = OpLabel 2081fd4e5da5Sopenharmony_ciOpBranch %9 2082fd4e5da5Sopenharmony_ci 2083fd4e5da5Sopenharmony_ci%9 = OpLabel 2084fd4e5da5Sopenharmony_ciOpLoopMerge %10 %11 None 2085fd4e5da5Sopenharmony_ciOpBranch %12 2086fd4e5da5Sopenharmony_ci 2087fd4e5da5Sopenharmony_ci%12 = OpLabel 2088fd4e5da5Sopenharmony_ciOpSelectionMerge %13 None 2089fd4e5da5Sopenharmony_ciOpSwitch %6 %13 0 %10 1 %14 2090fd4e5da5Sopenharmony_ci 2091fd4e5da5Sopenharmony_ci%14 = OpLabel 2092fd4e5da5Sopenharmony_ciOpBranch %13 2093fd4e5da5Sopenharmony_ci 2094fd4e5da5Sopenharmony_ci%13 = OpLabel 2095fd4e5da5Sopenharmony_ciOpBranch %11 2096fd4e5da5Sopenharmony_ci 2097fd4e5da5Sopenharmony_ci%11 = OpLabel 2098fd4e5da5Sopenharmony_ciOpBranch %9 2099fd4e5da5Sopenharmony_ci 2100fd4e5da5Sopenharmony_ci%10 = OpLabel 2101fd4e5da5Sopenharmony_ciOpReturn 2102fd4e5da5Sopenharmony_ci 2103fd4e5da5Sopenharmony_ciOpFunctionEnd 2104fd4e5da5Sopenharmony_ci)"; 2105fd4e5da5Sopenharmony_ci 2106fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2107fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 2108fd4e5da5Sopenharmony_ci EXPECT_THAT( 2109fd4e5da5Sopenharmony_ci getDiagnosticString(), 2110fd4e5da5Sopenharmony_ci HasSubstr( 2111fd4e5da5Sopenharmony_ci "Switch header '12[%12]' does not structurally dominate its case construct '10[%10]'\n" 2112fd4e5da5Sopenharmony_ci " %12 = OpLabel")); 2113fd4e5da5Sopenharmony_ci} 2114fd4e5da5Sopenharmony_ci 2115fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, OpSwitchTargetCannotBeOuterLoopContinueBlock) { 2116fd4e5da5Sopenharmony_ci std::string text = R"( 2117fd4e5da5Sopenharmony_ciOpCapability Shader 2118fd4e5da5Sopenharmony_ciOpCapability Linkage 2119fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2120fd4e5da5Sopenharmony_ci 2121fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 2122fd4e5da5Sopenharmony_ci%2 = OpTypeFunction %1 2123fd4e5da5Sopenharmony_ci%3 = OpTypeBool 2124fd4e5da5Sopenharmony_ci%4 = OpUndef %3 2125fd4e5da5Sopenharmony_ci%5 = OpTypeInt 32 0 2126fd4e5da5Sopenharmony_ci%6 = OpConstant %5 0 2127fd4e5da5Sopenharmony_ci 2128fd4e5da5Sopenharmony_ci%7 = OpFunction %1 None %2 2129fd4e5da5Sopenharmony_ci 2130fd4e5da5Sopenharmony_ci%8 = OpLabel 2131fd4e5da5Sopenharmony_ciOpBranch %9 2132fd4e5da5Sopenharmony_ci 2133fd4e5da5Sopenharmony_ci%9 = OpLabel 2134fd4e5da5Sopenharmony_ciOpLoopMerge %10 %11 None 2135fd4e5da5Sopenharmony_ciOpBranch %12 2136fd4e5da5Sopenharmony_ci 2137fd4e5da5Sopenharmony_ci%12 = OpLabel 2138fd4e5da5Sopenharmony_ciOpSelectionMerge %13 None 2139fd4e5da5Sopenharmony_ciOpSwitch %6 %13 0 %11 1 %14 2140fd4e5da5Sopenharmony_ci 2141fd4e5da5Sopenharmony_ci%14 = OpLabel 2142fd4e5da5Sopenharmony_ciOpBranch %13 2143fd4e5da5Sopenharmony_ci 2144fd4e5da5Sopenharmony_ci%13 = OpLabel 2145fd4e5da5Sopenharmony_ciOpBranch %11 2146fd4e5da5Sopenharmony_ci 2147fd4e5da5Sopenharmony_ci%11 = OpLabel 2148fd4e5da5Sopenharmony_ciOpBranch %9 2149fd4e5da5Sopenharmony_ci 2150fd4e5da5Sopenharmony_ci%10 = OpLabel 2151fd4e5da5Sopenharmony_ciOpReturn 2152fd4e5da5Sopenharmony_ci 2153fd4e5da5Sopenharmony_ciOpFunctionEnd 2154fd4e5da5Sopenharmony_ci)"; 2155fd4e5da5Sopenharmony_ci 2156fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2157fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 2158fd4e5da5Sopenharmony_ci EXPECT_THAT( 2159fd4e5da5Sopenharmony_ci getDiagnosticString(), 2160fd4e5da5Sopenharmony_ci HasSubstr( 2161fd4e5da5Sopenharmony_ci "Switch header '12[%12]' does not structurally dominate its case construct '11[%11]'\n" 2162fd4e5da5Sopenharmony_ci " %12 = OpLabel")); 2163fd4e5da5Sopenharmony_ci} 2164fd4e5da5Sopenharmony_ci 2165fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, WrongOperandList) { 2166fd4e5da5Sopenharmony_ci std::string text = R"( 2167fd4e5da5Sopenharmony_ciOpCapability Shader 2168fd4e5da5Sopenharmony_ciOpCapability Linkage 2169fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2170fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 2171fd4e5da5Sopenharmony_ci%2 = OpTypeInt 32 0 2172fd4e5da5Sopenharmony_ci%3 = OpConstant %2 0 2173fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %1 2174fd4e5da5Sopenharmony_ci%5 = OpTypeBool 2175fd4e5da5Sopenharmony_ci%6 = OpConstantTrue %5 2176fd4e5da5Sopenharmony_ci%7 = OpFunction %1 None %4 2177fd4e5da5Sopenharmony_ci%8 = OpLabel 2178fd4e5da5Sopenharmony_ciOpSelectionMerge %9 None 2179fd4e5da5Sopenharmony_ciOpSwitch %3 %10 0 %11 1 %12 2180fd4e5da5Sopenharmony_ci%10 = OpLabel 2181fd4e5da5Sopenharmony_ciOpBranch %9 2182fd4e5da5Sopenharmony_ci%12 = OpLabel 2183fd4e5da5Sopenharmony_ciOpBranch %11 2184fd4e5da5Sopenharmony_ci%11 = OpLabel 2185fd4e5da5Sopenharmony_ciOpBranch %9 2186fd4e5da5Sopenharmony_ci%9 = OpLabel 2187fd4e5da5Sopenharmony_ciOpReturn 2188fd4e5da5Sopenharmony_ciOpFunctionEnd 2189fd4e5da5Sopenharmony_ci)"; 2190fd4e5da5Sopenharmony_ci 2191fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2192fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 2193fd4e5da5Sopenharmony_ci EXPECT_THAT( 2194fd4e5da5Sopenharmony_ci getDiagnosticString(), 2195fd4e5da5Sopenharmony_ci HasSubstr( 2196fd4e5da5Sopenharmony_ci "Case construct that targets '12[%12]' has branches to the case " 2197fd4e5da5Sopenharmony_ci "construct that targets '11[%11]', but does not immediately " 2198fd4e5da5Sopenharmony_ci "precede it in the OpSwitch's target list\n" 2199fd4e5da5Sopenharmony_ci " OpSwitch %uint_0 %10 0 %11 1 %12")); 2200fd4e5da5Sopenharmony_ci} 2201fd4e5da5Sopenharmony_ci 2202fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, WrongOperandListThroughDefault) { 2203fd4e5da5Sopenharmony_ci std::string text = R"( 2204fd4e5da5Sopenharmony_ciOpCapability Shader 2205fd4e5da5Sopenharmony_ciOpCapability Linkage 2206fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2207fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 2208fd4e5da5Sopenharmony_ci%2 = OpTypeInt 32 0 2209fd4e5da5Sopenharmony_ci%3 = OpConstant %2 0 2210fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %1 2211fd4e5da5Sopenharmony_ci%5 = OpTypeBool 2212fd4e5da5Sopenharmony_ci%6 = OpConstantTrue %5 2213fd4e5da5Sopenharmony_ci%7 = OpFunction %1 None %4 2214fd4e5da5Sopenharmony_ci%8 = OpLabel 2215fd4e5da5Sopenharmony_ciOpSelectionMerge %9 None 2216fd4e5da5Sopenharmony_ciOpSwitch %3 %10 0 %11 1 %12 2217fd4e5da5Sopenharmony_ci%10 = OpLabel 2218fd4e5da5Sopenharmony_ciOpBranch %11 2219fd4e5da5Sopenharmony_ci%12 = OpLabel 2220fd4e5da5Sopenharmony_ciOpBranch %10 2221fd4e5da5Sopenharmony_ci%11 = OpLabel 2222fd4e5da5Sopenharmony_ciOpBranch %9 2223fd4e5da5Sopenharmony_ci%9 = OpLabel 2224fd4e5da5Sopenharmony_ciOpReturn 2225fd4e5da5Sopenharmony_ciOpFunctionEnd 2226fd4e5da5Sopenharmony_ci)"; 2227fd4e5da5Sopenharmony_ci 2228fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2229fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 2230fd4e5da5Sopenharmony_ci EXPECT_THAT( 2231fd4e5da5Sopenharmony_ci getDiagnosticString(), 2232fd4e5da5Sopenharmony_ci HasSubstr( 2233fd4e5da5Sopenharmony_ci "Case construct that targets '12[%12]' has branches to the case " 2234fd4e5da5Sopenharmony_ci "construct that targets '11[%11]', but does not immediately " 2235fd4e5da5Sopenharmony_ci "precede it in the OpSwitch's target list\n" 2236fd4e5da5Sopenharmony_ci " OpSwitch %uint_0 %10 0 %11 1 %12")); 2237fd4e5da5Sopenharmony_ci} 2238fd4e5da5Sopenharmony_ci 2239fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, WrongOperandListNotLast) { 2240fd4e5da5Sopenharmony_ci std::string text = R"( 2241fd4e5da5Sopenharmony_ciOpCapability Shader 2242fd4e5da5Sopenharmony_ciOpCapability Linkage 2243fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2244fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 2245fd4e5da5Sopenharmony_ci%2 = OpTypeInt 32 0 2246fd4e5da5Sopenharmony_ci%3 = OpConstant %2 0 2247fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %1 2248fd4e5da5Sopenharmony_ci%5 = OpTypeBool 2249fd4e5da5Sopenharmony_ci%6 = OpConstantTrue %5 2250fd4e5da5Sopenharmony_ci%7 = OpFunction %1 None %4 2251fd4e5da5Sopenharmony_ci%8 = OpLabel 2252fd4e5da5Sopenharmony_ciOpSelectionMerge %9 None 2253fd4e5da5Sopenharmony_ciOpSwitch %3 %10 0 %11 1 %12 2 %13 2254fd4e5da5Sopenharmony_ci%10 = OpLabel 2255fd4e5da5Sopenharmony_ciOpBranch %9 2256fd4e5da5Sopenharmony_ci%12 = OpLabel 2257fd4e5da5Sopenharmony_ciOpBranch %11 2258fd4e5da5Sopenharmony_ci%11 = OpLabel 2259fd4e5da5Sopenharmony_ciOpBranch %9 2260fd4e5da5Sopenharmony_ci%13 = OpLabel 2261fd4e5da5Sopenharmony_ciOpBranch %9 2262fd4e5da5Sopenharmony_ci%9 = OpLabel 2263fd4e5da5Sopenharmony_ciOpReturn 2264fd4e5da5Sopenharmony_ciOpFunctionEnd 2265fd4e5da5Sopenharmony_ci)"; 2266fd4e5da5Sopenharmony_ci 2267fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2268fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 2269fd4e5da5Sopenharmony_ci EXPECT_THAT( 2270fd4e5da5Sopenharmony_ci getDiagnosticString(), 2271fd4e5da5Sopenharmony_ci HasSubstr( 2272fd4e5da5Sopenharmony_ci "Case construct that targets '12[%12]' has branches to the case " 2273fd4e5da5Sopenharmony_ci "construct that targets '11[%11]', but does not immediately " 2274fd4e5da5Sopenharmony_ci "precede it in the OpSwitch's target list\n" 2275fd4e5da5Sopenharmony_ci " OpSwitch %uint_0 %10 0 %11 1 %12 2 %13")); 2276fd4e5da5Sopenharmony_ci} 2277fd4e5da5Sopenharmony_ci 2278fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, GoodUnreachableSwitch) { 2279fd4e5da5Sopenharmony_ci const std::string text = R"( 2280fd4e5da5Sopenharmony_ciOpCapability Shader 2281fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2282fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %2 "main" 2283fd4e5da5Sopenharmony_ciOpExecutionMode %2 OriginUpperLeft 2284fd4e5da5Sopenharmony_ci%3 = OpTypeVoid 2285fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %3 2286fd4e5da5Sopenharmony_ci%5 = OpTypeBool 2287fd4e5da5Sopenharmony_ci%6 = OpConstantTrue %5 2288fd4e5da5Sopenharmony_ci%7 = OpTypeInt 32 1 2289fd4e5da5Sopenharmony_ci%9 = OpConstant %7 0 2290fd4e5da5Sopenharmony_ci%2 = OpFunction %3 None %4 2291fd4e5da5Sopenharmony_ci%10 = OpLabel 2292fd4e5da5Sopenharmony_ciOpSelectionMerge %11 None 2293fd4e5da5Sopenharmony_ciOpBranchConditional %6 %12 %13 2294fd4e5da5Sopenharmony_ci%12 = OpLabel 2295fd4e5da5Sopenharmony_ciOpReturn 2296fd4e5da5Sopenharmony_ci%13 = OpLabel 2297fd4e5da5Sopenharmony_ciOpReturn 2298fd4e5da5Sopenharmony_ci%11 = OpLabel 2299fd4e5da5Sopenharmony_ciOpSelectionMerge %14 None 2300fd4e5da5Sopenharmony_ciOpSwitch %9 %14 0 %15 2301fd4e5da5Sopenharmony_ci%15 = OpLabel 2302fd4e5da5Sopenharmony_ciOpBranch %14 2303fd4e5da5Sopenharmony_ci%14 = OpLabel 2304fd4e5da5Sopenharmony_ciOpReturn 2305fd4e5da5Sopenharmony_ciOpFunctionEnd 2306fd4e5da5Sopenharmony_ci)"; 2307fd4e5da5Sopenharmony_ci 2308fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2309fd4e5da5Sopenharmony_ci EXPECT_THAT(SPV_SUCCESS, ValidateInstructions()); 2310fd4e5da5Sopenharmony_ci} 2311fd4e5da5Sopenharmony_ci 2312fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, InvalidCaseExit) { 2313fd4e5da5Sopenharmony_ci const std::string text = R"( 2314fd4e5da5Sopenharmony_ciOpCapability Shader 2315fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2316fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %1 "func" 2317fd4e5da5Sopenharmony_ciOpExecutionMode %1 OriginUpperLeft 2318fd4e5da5Sopenharmony_ci%2 = OpTypeVoid 2319fd4e5da5Sopenharmony_ci%3 = OpTypeInt 32 0 2320fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %2 2321fd4e5da5Sopenharmony_ci%5 = OpConstant %3 0 2322fd4e5da5Sopenharmony_ci%1 = OpFunction %2 None %4 2323fd4e5da5Sopenharmony_ci%6 = OpLabel 2324fd4e5da5Sopenharmony_ciOpSelectionMerge %7 None 2325fd4e5da5Sopenharmony_ciOpSwitch %5 %7 0 %8 1 %9 2326fd4e5da5Sopenharmony_ci%8 = OpLabel 2327fd4e5da5Sopenharmony_ciOpBranch %10 2328fd4e5da5Sopenharmony_ci%9 = OpLabel 2329fd4e5da5Sopenharmony_ciOpBranch %10 2330fd4e5da5Sopenharmony_ci%10 = OpLabel 2331fd4e5da5Sopenharmony_ciOpReturn 2332fd4e5da5Sopenharmony_ci%7 = OpLabel 2333fd4e5da5Sopenharmony_ciOpReturn 2334fd4e5da5Sopenharmony_ciOpFunctionEnd 2335fd4e5da5Sopenharmony_ci)"; 2336fd4e5da5Sopenharmony_ci 2337fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2338fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 2339fd4e5da5Sopenharmony_ci EXPECT_THAT( 2340fd4e5da5Sopenharmony_ci getDiagnosticString(), 2341fd4e5da5Sopenharmony_ci HasSubstr("Case construct that targets '8[%8]' has invalid branch " 2342fd4e5da5Sopenharmony_ci "to block '10[%10]' (not another case construct, " 2343fd4e5da5Sopenharmony_ci "corresponding merge, outer loop merge or outer loop " 2344fd4e5da5Sopenharmony_ci "continue)")); 2345fd4e5da5Sopenharmony_ci} 2346fd4e5da5Sopenharmony_ci 2347fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, GoodCaseExitsToOuterConstructs) { 2348fd4e5da5Sopenharmony_ci const std::string text = R"( 2349fd4e5da5Sopenharmony_ciOpCapability Shader 2350fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2351fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %func "func" 2352fd4e5da5Sopenharmony_ciOpExecutionMode %func OriginUpperLeft 2353fd4e5da5Sopenharmony_ci%void = OpTypeVoid 2354fd4e5da5Sopenharmony_ci%bool = OpTypeBool 2355fd4e5da5Sopenharmony_ci%true = OpConstantTrue %bool 2356fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 2357fd4e5da5Sopenharmony_ci%int0 = OpConstant %int 0 2358fd4e5da5Sopenharmony_ci%func_ty = OpTypeFunction %void 2359fd4e5da5Sopenharmony_ci%func = OpFunction %void None %func_ty 2360fd4e5da5Sopenharmony_ci%1 = OpLabel 2361fd4e5da5Sopenharmony_ciOpBranch %2 2362fd4e5da5Sopenharmony_ci%2 = OpLabel 2363fd4e5da5Sopenharmony_ciOpLoopMerge %7 %6 None 2364fd4e5da5Sopenharmony_ciOpBranch %3 2365fd4e5da5Sopenharmony_ci%3 = OpLabel 2366fd4e5da5Sopenharmony_ciOpSelectionMerge %5 None 2367fd4e5da5Sopenharmony_ciOpSwitch %int0 %5 0 %4 2368fd4e5da5Sopenharmony_ci%4 = OpLabel 2369fd4e5da5Sopenharmony_ciOpBranchConditional %true %6 %7 2370fd4e5da5Sopenharmony_ci%5 = OpLabel 2371fd4e5da5Sopenharmony_ciOpBranchConditional %true %6 %7 2372fd4e5da5Sopenharmony_ci%6 = OpLabel 2373fd4e5da5Sopenharmony_ciOpBranch %2 2374fd4e5da5Sopenharmony_ci%7 = OpLabel 2375fd4e5da5Sopenharmony_ciOpReturn 2376fd4e5da5Sopenharmony_ciOpFunctionEnd 2377fd4e5da5Sopenharmony_ci)"; 2378fd4e5da5Sopenharmony_ci 2379fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2380fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 2381fd4e5da5Sopenharmony_ci} 2382fd4e5da5Sopenharmony_ci 2383fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, SwitchCaseOrderingBad1) { 2384fd4e5da5Sopenharmony_ci const std::string text = R"( 2385fd4e5da5Sopenharmony_ciOpCapability Shader 2386fd4e5da5Sopenharmony_ciOpCapability Linkage 2387fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2388fd4e5da5Sopenharmony_ciOpName %default "default" 2389fd4e5da5Sopenharmony_ciOpName %other "other" 2390fd4e5da5Sopenharmony_ci%void = OpTypeVoid 2391fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 2392fd4e5da5Sopenharmony_ci%undef = OpUndef %int 2393fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 2394fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 2395fd4e5da5Sopenharmony_ci%entry = OpLabel 2396fd4e5da5Sopenharmony_ciOpSelectionMerge %merge None 2397fd4e5da5Sopenharmony_ciOpSwitch %undef %default 0 %other 1 %default 2398fd4e5da5Sopenharmony_ci%default = OpLabel 2399fd4e5da5Sopenharmony_ciOpBranch %other 2400fd4e5da5Sopenharmony_ci%other = OpLabel 2401fd4e5da5Sopenharmony_ciOpBranch %merge 2402fd4e5da5Sopenharmony_ci%merge = OpLabel 2403fd4e5da5Sopenharmony_ciOpReturn 2404fd4e5da5Sopenharmony_ciOpFunctionEnd 2405fd4e5da5Sopenharmony_ci)"; 2406fd4e5da5Sopenharmony_ci 2407fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2408fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 2409fd4e5da5Sopenharmony_ci EXPECT_THAT( 2410fd4e5da5Sopenharmony_ci getDiagnosticString(), 2411fd4e5da5Sopenharmony_ci HasSubstr("Case construct that targets '1[%default]' has branches to the " 2412fd4e5da5Sopenharmony_ci "case construct that targets '2[%other]', but does not " 2413fd4e5da5Sopenharmony_ci "immediately precede it in the OpSwitch's target list")); 2414fd4e5da5Sopenharmony_ci} 2415fd4e5da5Sopenharmony_ci 2416fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, SwitchCaseOrderingBad2) { 2417fd4e5da5Sopenharmony_ci const std::string text = R"( 2418fd4e5da5Sopenharmony_ciOpCapability Shader 2419fd4e5da5Sopenharmony_ciOpCapability Linkage 2420fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2421fd4e5da5Sopenharmony_ciOpName %default "default" 2422fd4e5da5Sopenharmony_ciOpName %other "other" 2423fd4e5da5Sopenharmony_ci%void = OpTypeVoid 2424fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 2425fd4e5da5Sopenharmony_ci%undef = OpUndef %int 2426fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 2427fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 2428fd4e5da5Sopenharmony_ci%entry = OpLabel 2429fd4e5da5Sopenharmony_ciOpSelectionMerge %merge None 2430fd4e5da5Sopenharmony_ciOpSwitch %undef %default 0 %default 1 %other 2431fd4e5da5Sopenharmony_ci%other = OpLabel 2432fd4e5da5Sopenharmony_ciOpBranch %default 2433fd4e5da5Sopenharmony_ci%default = OpLabel 2434fd4e5da5Sopenharmony_ciOpBranch %merge 2435fd4e5da5Sopenharmony_ci%merge = OpLabel 2436fd4e5da5Sopenharmony_ciOpReturn 2437fd4e5da5Sopenharmony_ciOpFunctionEnd 2438fd4e5da5Sopenharmony_ci)"; 2439fd4e5da5Sopenharmony_ci 2440fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2441fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 2442fd4e5da5Sopenharmony_ci EXPECT_THAT( 2443fd4e5da5Sopenharmony_ci getDiagnosticString(), 2444fd4e5da5Sopenharmony_ci HasSubstr("Case construct that targets '2[%other]' has branches to the " 2445fd4e5da5Sopenharmony_ci "case construct that targets '1[%default]', but does not " 2446fd4e5da5Sopenharmony_ci "immediately precede it in the OpSwitch's target list")); 2447fd4e5da5Sopenharmony_ci} 2448fd4e5da5Sopenharmony_ci 2449fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, SwitchMultipleDefaultWithFallThroughGood) { 2450fd4e5da5Sopenharmony_ci const std::string text = R"( 2451fd4e5da5Sopenharmony_ciOpCapability Shader 2452fd4e5da5Sopenharmony_ciOpCapability Linkage 2453fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2454fd4e5da5Sopenharmony_ciOpName %first "first" 2455fd4e5da5Sopenharmony_ciOpName %second "second" 2456fd4e5da5Sopenharmony_ciOpName %third "third" 2457fd4e5da5Sopenharmony_ci%void = OpTypeVoid 2458fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 2459fd4e5da5Sopenharmony_ci%undef = OpUndef %int 2460fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 2461fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 2462fd4e5da5Sopenharmony_ci%entry = OpLabel 2463fd4e5da5Sopenharmony_ciOpSelectionMerge %merge None 2464fd4e5da5Sopenharmony_ciOpSwitch %undef %second 0 %first 1 %second 2 %third 2465fd4e5da5Sopenharmony_ci%first = OpLabel 2466fd4e5da5Sopenharmony_ciOpBranch %second 2467fd4e5da5Sopenharmony_ci%second = OpLabel 2468fd4e5da5Sopenharmony_ciOpBranch %third 2469fd4e5da5Sopenharmony_ci%third = OpLabel 2470fd4e5da5Sopenharmony_ciOpBranch %merge 2471fd4e5da5Sopenharmony_ci%merge = OpLabel 2472fd4e5da5Sopenharmony_ciOpReturn 2473fd4e5da5Sopenharmony_ciOpFunctionEnd 2474fd4e5da5Sopenharmony_ci)"; 2475fd4e5da5Sopenharmony_ci 2476fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2477fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 2478fd4e5da5Sopenharmony_ci} 2479fd4e5da5Sopenharmony_ci 2480fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, SwitchMultipleDefaultWithFallThroughBad) { 2481fd4e5da5Sopenharmony_ci const std::string text = R"( 2482fd4e5da5Sopenharmony_ciOpCapability Shader 2483fd4e5da5Sopenharmony_ciOpCapability Linkage 2484fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2485fd4e5da5Sopenharmony_ciOpName %first "first" 2486fd4e5da5Sopenharmony_ciOpName %second "second" 2487fd4e5da5Sopenharmony_ciOpName %third "third" 2488fd4e5da5Sopenharmony_ci%void = OpTypeVoid 2489fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 2490fd4e5da5Sopenharmony_ci%undef = OpUndef %int 2491fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 2492fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 2493fd4e5da5Sopenharmony_ci%entry = OpLabel 2494fd4e5da5Sopenharmony_ciOpSelectionMerge %merge None 2495fd4e5da5Sopenharmony_ciOpSwitch %undef %second 0 %second 1 %first 2 %third 2496fd4e5da5Sopenharmony_ci%first = OpLabel 2497fd4e5da5Sopenharmony_ciOpBranch %second 2498fd4e5da5Sopenharmony_ci%second = OpLabel 2499fd4e5da5Sopenharmony_ciOpBranch %third 2500fd4e5da5Sopenharmony_ci%third = OpLabel 2501fd4e5da5Sopenharmony_ciOpBranch %merge 2502fd4e5da5Sopenharmony_ci%merge = OpLabel 2503fd4e5da5Sopenharmony_ciOpReturn 2504fd4e5da5Sopenharmony_ciOpFunctionEnd 2505fd4e5da5Sopenharmony_ci)"; 2506fd4e5da5Sopenharmony_ci 2507fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2508fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 2509fd4e5da5Sopenharmony_ci} 2510fd4e5da5Sopenharmony_ci 2511fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, GoodUnreachableSelection) { 2512fd4e5da5Sopenharmony_ci const std::string text = R"( 2513fd4e5da5Sopenharmony_ciOpCapability Shader 2514fd4e5da5Sopenharmony_ci%1 = OpExtInstImport "GLSL.std.450" 2515fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2516fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %main "main" 2517fd4e5da5Sopenharmony_ciOpExecutionMode %main OriginUpperLeft 2518fd4e5da5Sopenharmony_ci%void = OpTypeVoid 2519fd4e5da5Sopenharmony_ci%8 = OpTypeFunction %void 2520fd4e5da5Sopenharmony_ci%bool = OpTypeBool 2521fd4e5da5Sopenharmony_ci%false = OpConstantFalse %bool 2522fd4e5da5Sopenharmony_ci%main = OpFunction %void None %8 2523fd4e5da5Sopenharmony_ci%15 = OpLabel 2524fd4e5da5Sopenharmony_ciOpBranch %16 2525fd4e5da5Sopenharmony_ci%16 = OpLabel 2526fd4e5da5Sopenharmony_ciOpLoopMerge %17 %18 None 2527fd4e5da5Sopenharmony_ciOpBranch %19 2528fd4e5da5Sopenharmony_ci%19 = OpLabel 2529fd4e5da5Sopenharmony_ciOpBranchConditional %false %21 %17 2530fd4e5da5Sopenharmony_ci%21 = OpLabel 2531fd4e5da5Sopenharmony_ciOpSelectionMerge %22 None 2532fd4e5da5Sopenharmony_ciOpBranchConditional %false %23 %22 2533fd4e5da5Sopenharmony_ci%23 = OpLabel 2534fd4e5da5Sopenharmony_ciOpBranch %24 2535fd4e5da5Sopenharmony_ci%24 = OpLabel 2536fd4e5da5Sopenharmony_ciOpLoopMerge %25 %26 None 2537fd4e5da5Sopenharmony_ciOpBranch %27 2538fd4e5da5Sopenharmony_ci%27 = OpLabel 2539fd4e5da5Sopenharmony_ciOpReturn 2540fd4e5da5Sopenharmony_ci%26 = OpLabel 2541fd4e5da5Sopenharmony_ciOpBranchConditional %false %24 %25 2542fd4e5da5Sopenharmony_ci%25 = OpLabel 2543fd4e5da5Sopenharmony_ciOpSelectionMerge %28 None 2544fd4e5da5Sopenharmony_ciOpBranchConditional %false %18 %28 2545fd4e5da5Sopenharmony_ci%28 = OpLabel 2546fd4e5da5Sopenharmony_ciOpBranch %22 2547fd4e5da5Sopenharmony_ci%22 = OpLabel 2548fd4e5da5Sopenharmony_ciOpBranch %18 2549fd4e5da5Sopenharmony_ci%18 = OpLabel 2550fd4e5da5Sopenharmony_ciOpBranch %16 2551fd4e5da5Sopenharmony_ci%17 = OpLabel 2552fd4e5da5Sopenharmony_ciOpReturn 2553fd4e5da5Sopenharmony_ciOpFunctionEnd 2554fd4e5da5Sopenharmony_ci)"; 2555fd4e5da5Sopenharmony_ci 2556fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2557fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 2558fd4e5da5Sopenharmony_ci} 2559fd4e5da5Sopenharmony_ci 2560fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, ShaderWithPhiPtr) { 2561fd4e5da5Sopenharmony_ci const std::string text = R"( 2562fd4e5da5Sopenharmony_ci OpCapability Shader 2563fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 2564fd4e5da5Sopenharmony_ci OpEntryPoint GLCompute %1 "main" 2565fd4e5da5Sopenharmony_ci OpExecutionMode %1 LocalSize 1 1 1 2566fd4e5da5Sopenharmony_ci OpSource HLSL 600 2567fd4e5da5Sopenharmony_ci %bool = OpTypeBool 2568fd4e5da5Sopenharmony_ci%_ptr_Function_bool = OpTypePointer Function %bool 2569fd4e5da5Sopenharmony_ci %void = OpTypeVoid 2570fd4e5da5Sopenharmony_ci %5 = OpTypeFunction %void 2571fd4e5da5Sopenharmony_ci %1 = OpFunction %void None %5 2572fd4e5da5Sopenharmony_ci %6 = OpLabel 2573fd4e5da5Sopenharmony_ci %7 = OpVariable %_ptr_Function_bool Function 2574fd4e5da5Sopenharmony_ci %8 = OpVariable %_ptr_Function_bool Function 2575fd4e5da5Sopenharmony_ci %9 = OpUndef %bool 2576fd4e5da5Sopenharmony_ci OpSelectionMerge %10 None 2577fd4e5da5Sopenharmony_ci OpBranchConditional %9 %11 %10 2578fd4e5da5Sopenharmony_ci %11 = OpLabel 2579fd4e5da5Sopenharmony_ci OpBranch %10 2580fd4e5da5Sopenharmony_ci %10 = OpLabel 2581fd4e5da5Sopenharmony_ci %12 = OpPhi %_ptr_Function_bool %7 %6 %8 %11 2582fd4e5da5Sopenharmony_ci OpReturn 2583fd4e5da5Sopenharmony_ci OpFunctionEnd 2584fd4e5da5Sopenharmony_ci)"; 2585fd4e5da5Sopenharmony_ci 2586fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2587fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 2588fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 2589fd4e5da5Sopenharmony_ci HasSubstr("Using pointers with OpPhi requires capability " 2590fd4e5da5Sopenharmony_ci "VariablePointers or VariablePointersStorageBuffer")); 2591fd4e5da5Sopenharmony_ci} 2592fd4e5da5Sopenharmony_ci 2593fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, VarPtrShaderWithPhiPtr) { 2594fd4e5da5Sopenharmony_ci const std::string text = R"( 2595fd4e5da5Sopenharmony_ci OpCapability Shader 2596fd4e5da5Sopenharmony_ci OpCapability VariablePointers 2597fd4e5da5Sopenharmony_ci OpExtension "SPV_KHR_variable_pointers" 2598fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 2599fd4e5da5Sopenharmony_ci OpEntryPoint GLCompute %1 "main" 2600fd4e5da5Sopenharmony_ci OpExecutionMode %1 LocalSize 1 1 1 2601fd4e5da5Sopenharmony_ci OpSource HLSL 600 2602fd4e5da5Sopenharmony_ci %bool = OpTypeBool 2603fd4e5da5Sopenharmony_ci%_ptr_Function_bool = OpTypePointer Function %bool 2604fd4e5da5Sopenharmony_ci %void = OpTypeVoid 2605fd4e5da5Sopenharmony_ci %5 = OpTypeFunction %void 2606fd4e5da5Sopenharmony_ci %1 = OpFunction %void None %5 2607fd4e5da5Sopenharmony_ci %6 = OpLabel 2608fd4e5da5Sopenharmony_ci %7 = OpVariable %_ptr_Function_bool Function 2609fd4e5da5Sopenharmony_ci %8 = OpVariable %_ptr_Function_bool Function 2610fd4e5da5Sopenharmony_ci %9 = OpUndef %bool 2611fd4e5da5Sopenharmony_ci OpSelectionMerge %10 None 2612fd4e5da5Sopenharmony_ci OpBranchConditional %9 %11 %10 2613fd4e5da5Sopenharmony_ci %11 = OpLabel 2614fd4e5da5Sopenharmony_ci OpBranch %10 2615fd4e5da5Sopenharmony_ci %10 = OpLabel 2616fd4e5da5Sopenharmony_ci %12 = OpPhi %_ptr_Function_bool %7 %6 %8 %11 2617fd4e5da5Sopenharmony_ci OpReturn 2618fd4e5da5Sopenharmony_ci OpFunctionEnd 2619fd4e5da5Sopenharmony_ci)"; 2620fd4e5da5Sopenharmony_ci 2621fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2622fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 2623fd4e5da5Sopenharmony_ci} 2624fd4e5da5Sopenharmony_ci 2625fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, VarPtrStgBufShaderWithPhiStgBufPtr) { 2626fd4e5da5Sopenharmony_ci const std::string text = R"( 2627fd4e5da5Sopenharmony_ci OpCapability Shader 2628fd4e5da5Sopenharmony_ci OpCapability VariablePointersStorageBuffer 2629fd4e5da5Sopenharmony_ci OpExtension "SPV_KHR_variable_pointers" 2630fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 2631fd4e5da5Sopenharmony_ci OpEntryPoint GLCompute %1 "main" 2632fd4e5da5Sopenharmony_ci OpExecutionMode %1 LocalSize 1 1 1 2633fd4e5da5Sopenharmony_ci OpSource HLSL 600 2634fd4e5da5Sopenharmony_ci %bool = OpTypeBool 2635fd4e5da5Sopenharmony_ci %float = OpTypeFloat 32 2636fd4e5da5Sopenharmony_ci%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float 2637fd4e5da5Sopenharmony_ci %7 = OpVariable %_ptr_StorageBuffer_float StorageBuffer 2638fd4e5da5Sopenharmony_ci %8 = OpVariable %_ptr_StorageBuffer_float StorageBuffer 2639fd4e5da5Sopenharmony_ci %void = OpTypeVoid 2640fd4e5da5Sopenharmony_ci %5 = OpTypeFunction %void 2641fd4e5da5Sopenharmony_ci %1 = OpFunction %void None %5 2642fd4e5da5Sopenharmony_ci %6 = OpLabel 2643fd4e5da5Sopenharmony_ci %9 = OpUndef %bool 2644fd4e5da5Sopenharmony_ci OpSelectionMerge %10 None 2645fd4e5da5Sopenharmony_ci OpBranchConditional %9 %11 %10 2646fd4e5da5Sopenharmony_ci %11 = OpLabel 2647fd4e5da5Sopenharmony_ci OpBranch %10 2648fd4e5da5Sopenharmony_ci %10 = OpLabel 2649fd4e5da5Sopenharmony_ci %12 = OpPhi %_ptr_StorageBuffer_float %7 %6 %8 %11 2650fd4e5da5Sopenharmony_ci OpReturn 2651fd4e5da5Sopenharmony_ci OpFunctionEnd 2652fd4e5da5Sopenharmony_ci)"; 2653fd4e5da5Sopenharmony_ci 2654fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2655fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 2656fd4e5da5Sopenharmony_ci} 2657fd4e5da5Sopenharmony_ci 2658fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, KernelWithPhiPtr) { 2659fd4e5da5Sopenharmony_ci const std::string text = R"( 2660fd4e5da5Sopenharmony_ci OpCapability Kernel 2661fd4e5da5Sopenharmony_ci OpCapability Addresses 2662fd4e5da5Sopenharmony_ci OpMemoryModel Physical32 OpenCL 2663fd4e5da5Sopenharmony_ci OpEntryPoint Kernel %1 "main" 2664fd4e5da5Sopenharmony_ci OpExecutionMode %1 LocalSize 1 1 1 2665fd4e5da5Sopenharmony_ci OpSource HLSL 600 2666fd4e5da5Sopenharmony_ci %bool = OpTypeBool 2667fd4e5da5Sopenharmony_ci%_ptr_Function_bool = OpTypePointer Function %bool 2668fd4e5da5Sopenharmony_ci %void = OpTypeVoid 2669fd4e5da5Sopenharmony_ci %5 = OpTypeFunction %void 2670fd4e5da5Sopenharmony_ci %1 = OpFunction %void None %5 2671fd4e5da5Sopenharmony_ci %6 = OpLabel 2672fd4e5da5Sopenharmony_ci %7 = OpVariable %_ptr_Function_bool Function 2673fd4e5da5Sopenharmony_ci %8 = OpVariable %_ptr_Function_bool Function 2674fd4e5da5Sopenharmony_ci %9 = OpUndef %bool 2675fd4e5da5Sopenharmony_ci OpSelectionMerge %10 None 2676fd4e5da5Sopenharmony_ci OpBranchConditional %9 %11 %10 2677fd4e5da5Sopenharmony_ci %11 = OpLabel 2678fd4e5da5Sopenharmony_ci OpBranch %10 2679fd4e5da5Sopenharmony_ci %10 = OpLabel 2680fd4e5da5Sopenharmony_ci %12 = OpPhi %_ptr_Function_bool %7 %6 %8 %11 2681fd4e5da5Sopenharmony_ci OpReturn 2682fd4e5da5Sopenharmony_ci OpFunctionEnd 2683fd4e5da5Sopenharmony_ci)"; 2684fd4e5da5Sopenharmony_ci 2685fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2686fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 2687fd4e5da5Sopenharmony_ci} 2688fd4e5da5Sopenharmony_ci 2689fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, SwitchTargetMustBeLabel) { 2690fd4e5da5Sopenharmony_ci const std::string text = R"( 2691fd4e5da5Sopenharmony_ci OpCapability Shader 2692fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 2693fd4e5da5Sopenharmony_ci OpEntryPoint GLCompute %1 "foo" 2694fd4e5da5Sopenharmony_ci %uint = OpTypeInt 32 0 2695fd4e5da5Sopenharmony_ci %uint_0 = OpConstant %uint 0 2696fd4e5da5Sopenharmony_ci %void = OpTypeVoid 2697fd4e5da5Sopenharmony_ci %5 = OpTypeFunction %void 2698fd4e5da5Sopenharmony_ci %1 = OpFunction %void None %5 2699fd4e5da5Sopenharmony_ci %6 = OpLabel 2700fd4e5da5Sopenharmony_ci %7 = OpCopyObject %uint %uint_0 2701fd4e5da5Sopenharmony_ci OpSelectionMerge %8 None 2702fd4e5da5Sopenharmony_ci OpSwitch %uint_0 %8 0 %7 2703fd4e5da5Sopenharmony_ci %8 = OpLabel 2704fd4e5da5Sopenharmony_ci OpReturn 2705fd4e5da5Sopenharmony_ci OpFunctionEnd 2706fd4e5da5Sopenharmony_ci)"; 2707fd4e5da5Sopenharmony_ci 2708fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2709fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 2710fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 2711fd4e5da5Sopenharmony_ci HasSubstr("'Target Label' operands for OpSwitch must " 2712fd4e5da5Sopenharmony_ci "be IDs of an OpLabel instruction")); 2713fd4e5da5Sopenharmony_ci} 2714fd4e5da5Sopenharmony_ci 2715fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, BranchTargetMustBeLabel) { 2716fd4e5da5Sopenharmony_ci const std::string text = R"( 2717fd4e5da5Sopenharmony_ci OpCapability Shader 2718fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 2719fd4e5da5Sopenharmony_ci OpEntryPoint GLCompute %1 "foo" 2720fd4e5da5Sopenharmony_ci %uint = OpTypeInt 32 0 2721fd4e5da5Sopenharmony_ci %uint_0 = OpConstant %uint 0 2722fd4e5da5Sopenharmony_ci %void = OpTypeVoid 2723fd4e5da5Sopenharmony_ci %5 = OpTypeFunction %void 2724fd4e5da5Sopenharmony_ci %1 = OpFunction %void None %5 2725fd4e5da5Sopenharmony_ci %2 = OpLabel 2726fd4e5da5Sopenharmony_ci %7 = OpCopyObject %uint %uint_0 2727fd4e5da5Sopenharmony_ci OpBranch %7 2728fd4e5da5Sopenharmony_ci %8 = OpLabel 2729fd4e5da5Sopenharmony_ci OpReturn 2730fd4e5da5Sopenharmony_ci OpFunctionEnd 2731fd4e5da5Sopenharmony_ci)"; 2732fd4e5da5Sopenharmony_ci 2733fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2734fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 2735fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 2736fd4e5da5Sopenharmony_ci HasSubstr("'Target Label' operands for OpBranch must " 2737fd4e5da5Sopenharmony_ci "be the ID of an OpLabel instruction")); 2738fd4e5da5Sopenharmony_ci} 2739fd4e5da5Sopenharmony_ci 2740fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, ReachableOpUnreachableOneBlock) { 2741fd4e5da5Sopenharmony_ci const std::string text = R"( 2742fd4e5da5Sopenharmony_ciOpCapability Shader 2743fd4e5da5Sopenharmony_ciOpCapability Linkage 2744fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2745fd4e5da5Sopenharmony_ci%void = OpTypeVoid 2746fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 2747fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 2748fd4e5da5Sopenharmony_ci%entry = OpLabel 2749fd4e5da5Sopenharmony_ciOpUnreachable 2750fd4e5da5Sopenharmony_ciOpFunctionEnd 2751fd4e5da5Sopenharmony_ci)"; 2752fd4e5da5Sopenharmony_ci 2753fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2754fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 2755fd4e5da5Sopenharmony_ci} 2756fd4e5da5Sopenharmony_ci 2757fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, ReachableOpUnreachableOpBranch) { 2758fd4e5da5Sopenharmony_ci const std::string text = R"( 2759fd4e5da5Sopenharmony_ciOpCapability Shader 2760fd4e5da5Sopenharmony_ciOpCapability Linkage 2761fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2762fd4e5da5Sopenharmony_ci%void = OpTypeVoid 2763fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 2764fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 2765fd4e5da5Sopenharmony_ci%entry = OpLabel 2766fd4e5da5Sopenharmony_ciOpBranch %block 2767fd4e5da5Sopenharmony_ci%block = OpLabel 2768fd4e5da5Sopenharmony_ciOpUnreachable 2769fd4e5da5Sopenharmony_ciOpFunctionEnd 2770fd4e5da5Sopenharmony_ci)"; 2771fd4e5da5Sopenharmony_ci 2772fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2773fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 2774fd4e5da5Sopenharmony_ci} 2775fd4e5da5Sopenharmony_ci 2776fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, ReachableOpUnreachableOpBranchConditional) { 2777fd4e5da5Sopenharmony_ci const std::string text = R"( 2778fd4e5da5Sopenharmony_ciOpCapability Shader 2779fd4e5da5Sopenharmony_ciOpCapability Linkage 2780fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2781fd4e5da5Sopenharmony_ci%void = OpTypeVoid 2782fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 2783fd4e5da5Sopenharmony_ci%bool = OpTypeBool 2784fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 2785fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 2786fd4e5da5Sopenharmony_ci%entry = OpLabel 2787fd4e5da5Sopenharmony_ciOpSelectionMerge %block None 2788fd4e5da5Sopenharmony_ciOpBranchConditional %undef %block %unreachable 2789fd4e5da5Sopenharmony_ci%block = OpLabel 2790fd4e5da5Sopenharmony_ciOpReturn 2791fd4e5da5Sopenharmony_ci%unreachable = OpLabel 2792fd4e5da5Sopenharmony_ciOpUnreachable 2793fd4e5da5Sopenharmony_ciOpFunctionEnd 2794fd4e5da5Sopenharmony_ci)"; 2795fd4e5da5Sopenharmony_ci 2796fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2797fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 2798fd4e5da5Sopenharmony_ci} 2799fd4e5da5Sopenharmony_ci 2800fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, ReachableOpUnreachableOpSwitch) { 2801fd4e5da5Sopenharmony_ci const std::string text = R"( 2802fd4e5da5Sopenharmony_ciOpCapability Shader 2803fd4e5da5Sopenharmony_ciOpCapability Linkage 2804fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2805fd4e5da5Sopenharmony_ci%void = OpTypeVoid 2806fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 2807fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 2808fd4e5da5Sopenharmony_ci%undef = OpUndef %int 2809fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 2810fd4e5da5Sopenharmony_ci%entry = OpLabel 2811fd4e5da5Sopenharmony_ciOpSelectionMerge %block1 None 2812fd4e5da5Sopenharmony_ciOpSwitch %undef %block1 0 %unreachable 1 %block2 2813fd4e5da5Sopenharmony_ci%block1 = OpLabel 2814fd4e5da5Sopenharmony_ciOpReturn 2815fd4e5da5Sopenharmony_ci%unreachable = OpLabel 2816fd4e5da5Sopenharmony_ciOpUnreachable 2817fd4e5da5Sopenharmony_ci%block2 = OpLabel 2818fd4e5da5Sopenharmony_ciOpReturn 2819fd4e5da5Sopenharmony_ciOpFunctionEnd 2820fd4e5da5Sopenharmony_ci)"; 2821fd4e5da5Sopenharmony_ci 2822fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2823fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 2824fd4e5da5Sopenharmony_ci} 2825fd4e5da5Sopenharmony_ci 2826fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, ReachableOpUnreachableLoop) { 2827fd4e5da5Sopenharmony_ci const std::string text = R"( 2828fd4e5da5Sopenharmony_ciOpCapability Shader 2829fd4e5da5Sopenharmony_ciOpCapability Linkage 2830fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2831fd4e5da5Sopenharmony_ci%void = OpTypeVoid 2832fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 2833fd4e5da5Sopenharmony_ci%bool = OpTypeBool 2834fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 2835fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 2836fd4e5da5Sopenharmony_ci%entry = OpLabel 2837fd4e5da5Sopenharmony_ciOpBranch %loop 2838fd4e5da5Sopenharmony_ci%loop = OpLabel 2839fd4e5da5Sopenharmony_ciOpLoopMerge %unreachable %loop None 2840fd4e5da5Sopenharmony_ciOpBranchConditional %undef %loop %unreachable 2841fd4e5da5Sopenharmony_ci%unreachable = OpLabel 2842fd4e5da5Sopenharmony_ciOpUnreachable 2843fd4e5da5Sopenharmony_ciOpFunctionEnd 2844fd4e5da5Sopenharmony_ci)"; 2845fd4e5da5Sopenharmony_ci 2846fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2847fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 2848fd4e5da5Sopenharmony_ci} 2849fd4e5da5Sopenharmony_ci 2850fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, UnreachableLoopBadBackedge) { 2851fd4e5da5Sopenharmony_ci const std::string text = R"( 2852fd4e5da5Sopenharmony_ciOpCapability Shader 2853fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2854fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %2 "main" 2855fd4e5da5Sopenharmony_ciOpExecutionMode %2 OriginUpperLeft 2856fd4e5da5Sopenharmony_ci%4 = OpTypeVoid 2857fd4e5da5Sopenharmony_ci%5 = OpTypeFunction %4 2858fd4e5da5Sopenharmony_ci%8 = OpTypeBool 2859fd4e5da5Sopenharmony_ci%13 = OpConstantTrue %8 2860fd4e5da5Sopenharmony_ci%2 = OpFunction %4 None %5 2861fd4e5da5Sopenharmony_ci%14 = OpLabel 2862fd4e5da5Sopenharmony_ciOpSelectionMerge %15 None 2863fd4e5da5Sopenharmony_ciOpBranchConditional %13 %15 %15 2864fd4e5da5Sopenharmony_ci%16 = OpLabel 2865fd4e5da5Sopenharmony_ciOpLoopMerge %17 %18 None 2866fd4e5da5Sopenharmony_ciOpBranch %17 2867fd4e5da5Sopenharmony_ci%18 = OpLabel 2868fd4e5da5Sopenharmony_ciOpBranch %17 2869fd4e5da5Sopenharmony_ci%17 = OpLabel 2870fd4e5da5Sopenharmony_ciOpBranch %15 2871fd4e5da5Sopenharmony_ci%15 = OpLabel 2872fd4e5da5Sopenharmony_ciOpReturn 2873fd4e5da5Sopenharmony_ciOpFunctionEnd 2874fd4e5da5Sopenharmony_ci)"; 2875fd4e5da5Sopenharmony_ci 2876fd4e5da5Sopenharmony_ci // The back-edge in this test is bad, but the validator fails to identify it 2877fd4e5da5Sopenharmony_ci // because it is in an entirely unreachable section of code. Prior to #2488 2878fd4e5da5Sopenharmony_ci // this code failed an assert in Construct::blocks(). 2879fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2880fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 2881fd4e5da5Sopenharmony_ci} 2882fd4e5da5Sopenharmony_ci 2883fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, OneContinueTwoBackedges) { 2884fd4e5da5Sopenharmony_ci const std::string text = R"( 2885fd4e5da5Sopenharmony_ciOpCapability Shader 2886fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2887fd4e5da5Sopenharmony_ciOpEntryPoint GLCompute %1 "main" 2888fd4e5da5Sopenharmony_ciOpExecutionMode %1 LocalSize 1 1 1 2889fd4e5da5Sopenharmony_ci%void = OpTypeVoid 2890fd4e5da5Sopenharmony_ci%bool = OpTypeBool 2891fd4e5da5Sopenharmony_ci%true = OpConstantTrue %bool 2892fd4e5da5Sopenharmony_ci%5 = OpTypeFunction %void 2893fd4e5da5Sopenharmony_ci%1 = OpFunction %void None %5 2894fd4e5da5Sopenharmony_ci%6 = OpLabel 2895fd4e5da5Sopenharmony_ciOpBranch %7 2896fd4e5da5Sopenharmony_ci%7 = OpLabel 2897fd4e5da5Sopenharmony_ciOpLoopMerge %8 %9 None 2898fd4e5da5Sopenharmony_ciOpBranch %10 2899fd4e5da5Sopenharmony_ci%10 = OpLabel 2900fd4e5da5Sopenharmony_ciOpLoopMerge %11 %9 None 2901fd4e5da5Sopenharmony_ciOpBranchConditional %true %11 %9 2902fd4e5da5Sopenharmony_ci%9 = OpLabel 2903fd4e5da5Sopenharmony_ciOpBranchConditional %true %10 %7 2904fd4e5da5Sopenharmony_ci%11 = OpLabel 2905fd4e5da5Sopenharmony_ciOpBranch %8 2906fd4e5da5Sopenharmony_ci%8 = OpLabel 2907fd4e5da5Sopenharmony_ciOpReturn 2908fd4e5da5Sopenharmony_ciOpFunctionEnd 2909fd4e5da5Sopenharmony_ci)"; 2910fd4e5da5Sopenharmony_ci 2911fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2912fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 2913fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 2914fd4e5da5Sopenharmony_ci HasSubstr("Back-edges ('10[%10]' -> '9[%9]') can only be formed " 2915fd4e5da5Sopenharmony_ci "between a block and a loop header")); 2916fd4e5da5Sopenharmony_ci} 2917fd4e5da5Sopenharmony_ci 2918fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, LoopMergeMergeBlockNotLabel) { 2919fd4e5da5Sopenharmony_ci const std::string text = R"( 2920fd4e5da5Sopenharmony_ciOpCapability Shader 2921fd4e5da5Sopenharmony_ciOpCapability Linkage 2922fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2923fd4e5da5Sopenharmony_ciOpName %undef "undef" 2924fd4e5da5Sopenharmony_ci%void = OpTypeVoid 2925fd4e5da5Sopenharmony_ci%bool = OpTypeBool 2926fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 2927fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 2928fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 2929fd4e5da5Sopenharmony_ci%1 = OpLabel 2930fd4e5da5Sopenharmony_ciOpLoopMerge %undef %2 None 2931fd4e5da5Sopenharmony_ciOpBranchConditional %undef %2 %2 2932fd4e5da5Sopenharmony_ci%2 = OpLabel 2933fd4e5da5Sopenharmony_ciOpReturn 2934fd4e5da5Sopenharmony_ciOpFunctionEnd 2935fd4e5da5Sopenharmony_ci)"; 2936fd4e5da5Sopenharmony_ci 2937fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2938fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 2939fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 2940fd4e5da5Sopenharmony_ci HasSubstr("Merge Block '1[%undef]' must be an OpLabel")); 2941fd4e5da5Sopenharmony_ci} 2942fd4e5da5Sopenharmony_ci 2943fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, LoopMergeContinueTargetNotLabel) { 2944fd4e5da5Sopenharmony_ci const std::string text = R"( 2945fd4e5da5Sopenharmony_ciOpCapability Shader 2946fd4e5da5Sopenharmony_ciOpCapability Linkage 2947fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2948fd4e5da5Sopenharmony_ciOpName %undef "undef" 2949fd4e5da5Sopenharmony_ci%void = OpTypeVoid 2950fd4e5da5Sopenharmony_ci%bool = OpTypeBool 2951fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 2952fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 2953fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 2954fd4e5da5Sopenharmony_ci%1 = OpLabel 2955fd4e5da5Sopenharmony_ciOpLoopMerge %2 %undef None 2956fd4e5da5Sopenharmony_ciOpBranchConditional %undef %2 %2 2957fd4e5da5Sopenharmony_ci%2 = OpLabel 2958fd4e5da5Sopenharmony_ciOpReturn 2959fd4e5da5Sopenharmony_ciOpFunctionEnd 2960fd4e5da5Sopenharmony_ci)"; 2961fd4e5da5Sopenharmony_ci 2962fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2963fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 2964fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 2965fd4e5da5Sopenharmony_ci HasSubstr("Continue Target '1[%undef]' must be an OpLabel")); 2966fd4e5da5Sopenharmony_ci} 2967fd4e5da5Sopenharmony_ci 2968fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, LoopMergeMergeBlockContinueTargetSameLabel) { 2969fd4e5da5Sopenharmony_ci const std::string text = R"( 2970fd4e5da5Sopenharmony_ciOpCapability Shader 2971fd4e5da5Sopenharmony_ciOpCapability Linkage 2972fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2973fd4e5da5Sopenharmony_ciOpName %undef "undef" 2974fd4e5da5Sopenharmony_ci%void = OpTypeVoid 2975fd4e5da5Sopenharmony_ci%bool = OpTypeBool 2976fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 2977fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 2978fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 2979fd4e5da5Sopenharmony_ci%1 = OpLabel 2980fd4e5da5Sopenharmony_ciOpLoopMerge %2 %2 None 2981fd4e5da5Sopenharmony_ciOpBranchConditional %undef %2 %2 2982fd4e5da5Sopenharmony_ci%2 = OpLabel 2983fd4e5da5Sopenharmony_ciOpReturn 2984fd4e5da5Sopenharmony_ciOpFunctionEnd 2985fd4e5da5Sopenharmony_ci)"; 2986fd4e5da5Sopenharmony_ci 2987fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 2988fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 2989fd4e5da5Sopenharmony_ci EXPECT_THAT( 2990fd4e5da5Sopenharmony_ci getDiagnosticString(), 2991fd4e5da5Sopenharmony_ci HasSubstr("Merge Block and Continue Target must be different ids")); 2992fd4e5da5Sopenharmony_ci} 2993fd4e5da5Sopenharmony_ci 2994fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, LoopMergeUnrollAndDontUnroll) { 2995fd4e5da5Sopenharmony_ci const std::string text = R"( 2996fd4e5da5Sopenharmony_ciOpCapability Shader 2997fd4e5da5Sopenharmony_ciOpCapability Linkage 2998fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 2999fd4e5da5Sopenharmony_ciOpName %undef "undef" 3000fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3001fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3002fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3003fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3004fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3005fd4e5da5Sopenharmony_ci%5 = OpLabel 3006fd4e5da5Sopenharmony_ciOpBranch %1 3007fd4e5da5Sopenharmony_ci%1 = OpLabel 3008fd4e5da5Sopenharmony_ciOpLoopMerge %2 %3 Unroll|DontUnroll 3009fd4e5da5Sopenharmony_ciOpBranchConditional %undef %2 %3 3010fd4e5da5Sopenharmony_ci%3 = OpLabel 3011fd4e5da5Sopenharmony_ciOpBranch %1 3012fd4e5da5Sopenharmony_ci%2 = OpLabel 3013fd4e5da5Sopenharmony_ciOpReturn 3014fd4e5da5Sopenharmony_ciOpFunctionEnd 3015fd4e5da5Sopenharmony_ci)"; 3016fd4e5da5Sopenharmony_ci 3017fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3018fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 3019fd4e5da5Sopenharmony_ci EXPECT_THAT( 3020fd4e5da5Sopenharmony_ci getDiagnosticString(), 3021fd4e5da5Sopenharmony_ci HasSubstr( 3022fd4e5da5Sopenharmony_ci "Unroll and DontUnroll loop controls must not both be specified")); 3023fd4e5da5Sopenharmony_ci} 3024fd4e5da5Sopenharmony_ci 3025fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, LoopMergePeelCountAndDontUnroll) { 3026fd4e5da5Sopenharmony_ci const std::string text = R"( 3027fd4e5da5Sopenharmony_ciOpCapability Shader 3028fd4e5da5Sopenharmony_ciOpCapability Linkage 3029fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3030fd4e5da5Sopenharmony_ciOpName %undef "undef" 3031fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3032fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3033fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3034fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3035fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3036fd4e5da5Sopenharmony_ci%5 = OpLabel 3037fd4e5da5Sopenharmony_ciOpBranch %1 3038fd4e5da5Sopenharmony_ci%1 = OpLabel 3039fd4e5da5Sopenharmony_ciOpLoopMerge %2 %3 DontUnroll|PeelCount 1 3040fd4e5da5Sopenharmony_ciOpBranchConditional %undef %2 %3 3041fd4e5da5Sopenharmony_ci%3 = OpLabel 3042fd4e5da5Sopenharmony_ciOpBranch %1 3043fd4e5da5Sopenharmony_ci%2 = OpLabel 3044fd4e5da5Sopenharmony_ciOpReturn 3045fd4e5da5Sopenharmony_ciOpFunctionEnd 3046fd4e5da5Sopenharmony_ci)"; 3047fd4e5da5Sopenharmony_ci 3048fd4e5da5Sopenharmony_ci CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); 3049fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, 3050fd4e5da5Sopenharmony_ci ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); 3051fd4e5da5Sopenharmony_ci EXPECT_THAT( 3052fd4e5da5Sopenharmony_ci getDiagnosticString(), 3053fd4e5da5Sopenharmony_ci HasSubstr( 3054fd4e5da5Sopenharmony_ci "PeelCount and DontUnroll loop controls must not both be specified")); 3055fd4e5da5Sopenharmony_ci} 3056fd4e5da5Sopenharmony_ci 3057fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, LoopMergePartialCountAndDontUnroll) { 3058fd4e5da5Sopenharmony_ci const std::string text = R"( 3059fd4e5da5Sopenharmony_ciOpCapability Shader 3060fd4e5da5Sopenharmony_ciOpCapability Linkage 3061fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3062fd4e5da5Sopenharmony_ciOpName %undef "undef" 3063fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3064fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3065fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3066fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3067fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3068fd4e5da5Sopenharmony_ci%5 = OpLabel 3069fd4e5da5Sopenharmony_ciOpBranch %1 3070fd4e5da5Sopenharmony_ci%1 = OpLabel 3071fd4e5da5Sopenharmony_ciOpLoopMerge %2 %3 DontUnroll|PartialCount 1 3072fd4e5da5Sopenharmony_ciOpBranchConditional %undef %2 %3 3073fd4e5da5Sopenharmony_ci%3 = OpLabel 3074fd4e5da5Sopenharmony_ciOpBranch %1 3075fd4e5da5Sopenharmony_ci%2 = OpLabel 3076fd4e5da5Sopenharmony_ciOpReturn 3077fd4e5da5Sopenharmony_ciOpFunctionEnd 3078fd4e5da5Sopenharmony_ci)"; 3079fd4e5da5Sopenharmony_ci 3080fd4e5da5Sopenharmony_ci CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); 3081fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, 3082fd4e5da5Sopenharmony_ci ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); 3083fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 3084fd4e5da5Sopenharmony_ci HasSubstr("PartialCount and DontUnroll loop controls must not " 3085fd4e5da5Sopenharmony_ci "both be specified")); 3086fd4e5da5Sopenharmony_ci} 3087fd4e5da5Sopenharmony_ci 3088fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, LoopMergeIterationMultipleZero) { 3089fd4e5da5Sopenharmony_ci const std::string text = R"( 3090fd4e5da5Sopenharmony_ciOpCapability Shader 3091fd4e5da5Sopenharmony_ciOpCapability Linkage 3092fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3093fd4e5da5Sopenharmony_ciOpName %undef "undef" 3094fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3095fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3096fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3097fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3098fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3099fd4e5da5Sopenharmony_ci%5 = OpLabel 3100fd4e5da5Sopenharmony_ciOpBranch %1 3101fd4e5da5Sopenharmony_ci%1 = OpLabel 3102fd4e5da5Sopenharmony_ciOpLoopMerge %2 %3 IterationMultiple 0 3103fd4e5da5Sopenharmony_ciOpBranchConditional %undef %2 %3 3104fd4e5da5Sopenharmony_ci%3 = OpLabel 3105fd4e5da5Sopenharmony_ciOpBranch %1 3106fd4e5da5Sopenharmony_ci%2 = OpLabel 3107fd4e5da5Sopenharmony_ciOpReturn 3108fd4e5da5Sopenharmony_ciOpFunctionEnd 3109fd4e5da5Sopenharmony_ci)"; 3110fd4e5da5Sopenharmony_ci 3111fd4e5da5Sopenharmony_ci CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); 3112fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, 3113fd4e5da5Sopenharmony_ci ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); 3114fd4e5da5Sopenharmony_ci EXPECT_THAT( 3115fd4e5da5Sopenharmony_ci getDiagnosticString(), 3116fd4e5da5Sopenharmony_ci HasSubstr( 3117fd4e5da5Sopenharmony_ci "IterationMultiple loop control operand must be greater than zero")); 3118fd4e5da5Sopenharmony_ci} 3119fd4e5da5Sopenharmony_ci 3120fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, LoopMergeIterationMultipleZeroMoreOperands) { 3121fd4e5da5Sopenharmony_ci const std::string text = R"( 3122fd4e5da5Sopenharmony_ciOpCapability Shader 3123fd4e5da5Sopenharmony_ciOpCapability Linkage 3124fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3125fd4e5da5Sopenharmony_ciOpName %undef "undef" 3126fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3127fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3128fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3129fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3130fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3131fd4e5da5Sopenharmony_ci%5 = OpLabel 3132fd4e5da5Sopenharmony_ciOpBranch %1 3133fd4e5da5Sopenharmony_ci%1 = OpLabel 3134fd4e5da5Sopenharmony_ciOpLoopMerge %2 %3 MaxIterations|IterationMultiple 4 0 3135fd4e5da5Sopenharmony_ciOpBranchConditional %undef %2 %3 3136fd4e5da5Sopenharmony_ci%3 = OpLabel 3137fd4e5da5Sopenharmony_ciOpBranch %1 3138fd4e5da5Sopenharmony_ci%2 = OpLabel 3139fd4e5da5Sopenharmony_ciOpReturn 3140fd4e5da5Sopenharmony_ciOpFunctionEnd 3141fd4e5da5Sopenharmony_ci)"; 3142fd4e5da5Sopenharmony_ci 3143fd4e5da5Sopenharmony_ci CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_4); 3144fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, 3145fd4e5da5Sopenharmony_ci ValidateInstructions(SPV_ENV_UNIVERSAL_1_4)); 3146fd4e5da5Sopenharmony_ci EXPECT_THAT( 3147fd4e5da5Sopenharmony_ci getDiagnosticString(), 3148fd4e5da5Sopenharmony_ci HasSubstr( 3149fd4e5da5Sopenharmony_ci "IterationMultiple loop control operand must be greater than zero")); 3150fd4e5da5Sopenharmony_ci} 3151fd4e5da5Sopenharmony_ci 3152fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, LoopMergeTargetsHeader) { 3153fd4e5da5Sopenharmony_ci const std::string text = R"( 3154fd4e5da5Sopenharmony_ciOpCapability Shader 3155fd4e5da5Sopenharmony_ciOpCapability Linkage 3156fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3157fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3158fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3159fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3160fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3161fd4e5da5Sopenharmony_ci%fn = OpFunction %void None %void_fn 3162fd4e5da5Sopenharmony_ci%entry = OpLabel 3163fd4e5da5Sopenharmony_ciOpBranch %loop 3164fd4e5da5Sopenharmony_ci%loop = OpLabel 3165fd4e5da5Sopenharmony_ciOpLoopMerge %loop %continue None 3166fd4e5da5Sopenharmony_ciOpBranch %body 3167fd4e5da5Sopenharmony_ci%continue = OpLabel 3168fd4e5da5Sopenharmony_ciOpBranch %loop 3169fd4e5da5Sopenharmony_ci%body = OpLabel 3170fd4e5da5Sopenharmony_ciOpReturn 3171fd4e5da5Sopenharmony_ciOpFunctionEnd 3172fd4e5da5Sopenharmony_ci)"; 3173fd4e5da5Sopenharmony_ci 3174fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3175fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 3176fd4e5da5Sopenharmony_ci EXPECT_THAT( 3177fd4e5da5Sopenharmony_ci getDiagnosticString(), 3178fd4e5da5Sopenharmony_ci HasSubstr("Merge Block may not be the block containing the OpLoopMerge")); 3179fd4e5da5Sopenharmony_ci} 3180fd4e5da5Sopenharmony_ci 3181fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, InvalidSelectionExit) { 3182fd4e5da5Sopenharmony_ci const std::string text = R"( 3183fd4e5da5Sopenharmony_ciOpCapability Shader 3184fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3185fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %1 "main" 3186fd4e5da5Sopenharmony_ciOpExecutionMode %1 OriginUpperLeft 3187fd4e5da5Sopenharmony_ci%2 = OpTypeVoid 3188fd4e5da5Sopenharmony_ci%3 = OpTypeBool 3189fd4e5da5Sopenharmony_ci%4 = OpConstantTrue %3 3190fd4e5da5Sopenharmony_ci%5 = OpTypeFunction %2 3191fd4e5da5Sopenharmony_ci%1 = OpFunction %2 None %5 3192fd4e5da5Sopenharmony_ci%6 = OpLabel 3193fd4e5da5Sopenharmony_ciOpSelectionMerge %7 None 3194fd4e5da5Sopenharmony_ciOpBranchConditional %4 %7 %8 3195fd4e5da5Sopenharmony_ci%8 = OpLabel 3196fd4e5da5Sopenharmony_ciOpSelectionMerge %9 None 3197fd4e5da5Sopenharmony_ciOpBranchConditional %4 %10 %9 3198fd4e5da5Sopenharmony_ci%10 = OpLabel 3199fd4e5da5Sopenharmony_ciOpBranch %7 3200fd4e5da5Sopenharmony_ci%9 = OpLabel 3201fd4e5da5Sopenharmony_ciOpBranch %7 3202fd4e5da5Sopenharmony_ci%7 = OpLabel 3203fd4e5da5Sopenharmony_ciOpReturn 3204fd4e5da5Sopenharmony_ciOpFunctionEnd 3205fd4e5da5Sopenharmony_ci)"; 3206fd4e5da5Sopenharmony_ci 3207fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3208fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3209fd4e5da5Sopenharmony_ci EXPECT_THAT( 3210fd4e5da5Sopenharmony_ci getDiagnosticString(), 3211fd4e5da5Sopenharmony_ci HasSubstr("block <ID> '10[%10]' exits the selection headed by <ID> " 3212fd4e5da5Sopenharmony_ci "'8[%8]', but not via a structured exit")); 3213fd4e5da5Sopenharmony_ci} 3214fd4e5da5Sopenharmony_ci 3215fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, InvalidLoopExit) { 3216fd4e5da5Sopenharmony_ci const std::string text = R"( 3217fd4e5da5Sopenharmony_ciOpCapability Shader 3218fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3219fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %1 "main" 3220fd4e5da5Sopenharmony_ciOpExecutionMode %1 OriginUpperLeft 3221fd4e5da5Sopenharmony_ci%2 = OpTypeVoid 3222fd4e5da5Sopenharmony_ci%3 = OpTypeBool 3223fd4e5da5Sopenharmony_ci%4 = OpConstantTrue %3 3224fd4e5da5Sopenharmony_ci%5 = OpTypeFunction %2 3225fd4e5da5Sopenharmony_ci%1 = OpFunction %2 None %5 3226fd4e5da5Sopenharmony_ci%6 = OpLabel 3227fd4e5da5Sopenharmony_ciOpSelectionMerge %7 None 3228fd4e5da5Sopenharmony_ciOpBranchConditional %4 %7 %8 3229fd4e5da5Sopenharmony_ci%8 = OpLabel 3230fd4e5da5Sopenharmony_ciOpLoopMerge %9 %10 None 3231fd4e5da5Sopenharmony_ciOpBranchConditional %4 %9 %11 3232fd4e5da5Sopenharmony_ci%11 = OpLabel 3233fd4e5da5Sopenharmony_ciOpBranchConditional %4 %7 %10 3234fd4e5da5Sopenharmony_ci%10 = OpLabel 3235fd4e5da5Sopenharmony_ciOpBranch %8 3236fd4e5da5Sopenharmony_ci%9 = OpLabel 3237fd4e5da5Sopenharmony_ciOpBranch %7 3238fd4e5da5Sopenharmony_ci%7 = OpLabel 3239fd4e5da5Sopenharmony_ciOpReturn 3240fd4e5da5Sopenharmony_ciOpFunctionEnd 3241fd4e5da5Sopenharmony_ci)"; 3242fd4e5da5Sopenharmony_ci 3243fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3244fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3245fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 3246fd4e5da5Sopenharmony_ci HasSubstr("block <ID> '11[%11]' exits the loop headed by <ID> " 3247fd4e5da5Sopenharmony_ci "'8[%8]', but not via a structured exit")); 3248fd4e5da5Sopenharmony_ci} 3249fd4e5da5Sopenharmony_ci 3250fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, InvalidContinueExit) { 3251fd4e5da5Sopenharmony_ci const std::string text = R"( 3252fd4e5da5Sopenharmony_ciOpCapability Shader 3253fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3254fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %1 "main" 3255fd4e5da5Sopenharmony_ciOpExecutionMode %1 OriginUpperLeft 3256fd4e5da5Sopenharmony_ci%2 = OpTypeVoid 3257fd4e5da5Sopenharmony_ci%3 = OpTypeBool 3258fd4e5da5Sopenharmony_ci%4 = OpConstantTrue %3 3259fd4e5da5Sopenharmony_ci%5 = OpTypeFunction %2 3260fd4e5da5Sopenharmony_ci%1 = OpFunction %2 None %5 3261fd4e5da5Sopenharmony_ci%6 = OpLabel 3262fd4e5da5Sopenharmony_ciOpSelectionMerge %7 None 3263fd4e5da5Sopenharmony_ciOpBranchConditional %4 %7 %8 3264fd4e5da5Sopenharmony_ci%8 = OpLabel 3265fd4e5da5Sopenharmony_ciOpLoopMerge %9 %10 None 3266fd4e5da5Sopenharmony_ciOpBranchConditional %4 %9 %10 3267fd4e5da5Sopenharmony_ci%10 = OpLabel 3268fd4e5da5Sopenharmony_ciOpBranch %11 3269fd4e5da5Sopenharmony_ci%11 = OpLabel 3270fd4e5da5Sopenharmony_ciOpBranchConditional %4 %8 %7 3271fd4e5da5Sopenharmony_ci%9 = OpLabel 3272fd4e5da5Sopenharmony_ciOpBranch %7 3273fd4e5da5Sopenharmony_ci%7 = OpLabel 3274fd4e5da5Sopenharmony_ciOpReturn 3275fd4e5da5Sopenharmony_ciOpFunctionEnd 3276fd4e5da5Sopenharmony_ci)"; 3277fd4e5da5Sopenharmony_ci 3278fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3279fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3280fd4e5da5Sopenharmony_ci EXPECT_THAT( 3281fd4e5da5Sopenharmony_ci getDiagnosticString(), 3282fd4e5da5Sopenharmony_ci HasSubstr("block <ID> '11[%11]' exits the continue headed by <ID> " 3283fd4e5da5Sopenharmony_ci "'10[%10]', but not via a structured exit")); 3284fd4e5da5Sopenharmony_ci} 3285fd4e5da5Sopenharmony_ci 3286fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, InvalidSelectionExitBackedge) { 3287fd4e5da5Sopenharmony_ci const std::string text = R"( 3288fd4e5da5Sopenharmony_ciOpCapability Shader 3289fd4e5da5Sopenharmony_ciOpCapability Linkage 3290fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3291fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 3292fd4e5da5Sopenharmony_ci%2 = OpTypeBool 3293fd4e5da5Sopenharmony_ci%3 = OpUndef %2 3294fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %1 3295fd4e5da5Sopenharmony_ci%5 = OpFunction %1 None %4 3296fd4e5da5Sopenharmony_ci%6 = OpLabel 3297fd4e5da5Sopenharmony_ciOpBranch %7 3298fd4e5da5Sopenharmony_ci%7 = OpLabel 3299fd4e5da5Sopenharmony_ciOpLoopMerge %8 %9 None 3300fd4e5da5Sopenharmony_ciOpBranchConditional %3 %8 %9 3301fd4e5da5Sopenharmony_ci%9 = OpLabel 3302fd4e5da5Sopenharmony_ciOpSelectionMerge %10 None 3303fd4e5da5Sopenharmony_ciOpBranchConditional %3 %11 %12 3304fd4e5da5Sopenharmony_ci%11 = OpLabel 3305fd4e5da5Sopenharmony_ciOpBranch %13 3306fd4e5da5Sopenharmony_ci%12 = OpLabel 3307fd4e5da5Sopenharmony_ciOpBranch %13 3308fd4e5da5Sopenharmony_ci%13 = OpLabel 3309fd4e5da5Sopenharmony_ciOpBranch %7 3310fd4e5da5Sopenharmony_ci%10 = OpLabel 3311fd4e5da5Sopenharmony_ciOpUnreachable 3312fd4e5da5Sopenharmony_ci%8 = OpLabel 3313fd4e5da5Sopenharmony_ciOpReturn 3314fd4e5da5Sopenharmony_ciOpFunctionEnd 3315fd4e5da5Sopenharmony_ci)"; 3316fd4e5da5Sopenharmony_ci 3317fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3318fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3319fd4e5da5Sopenharmony_ci EXPECT_THAT( 3320fd4e5da5Sopenharmony_ci getDiagnosticString(), 3321fd4e5da5Sopenharmony_ci HasSubstr( 3322fd4e5da5Sopenharmony_ci "The continue construct with the continue target '9[%9]' is not " 3323fd4e5da5Sopenharmony_ci "structurally post dominated by the back-edge block '13[%13]'")); 3324fd4e5da5Sopenharmony_ci} 3325fd4e5da5Sopenharmony_ci 3326fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, BreakFromSwitch) { 3327fd4e5da5Sopenharmony_ci const std::string text = R"( 3328fd4e5da5Sopenharmony_ciOpCapability Shader 3329fd4e5da5Sopenharmony_ciOpCapability Linkage 3330fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3331fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 3332fd4e5da5Sopenharmony_ci%2 = OpTypeBool 3333fd4e5da5Sopenharmony_ci%3 = OpTypeInt 32 0 3334fd4e5da5Sopenharmony_ci%4 = OpUndef %2 3335fd4e5da5Sopenharmony_ci%5 = OpUndef %3 3336fd4e5da5Sopenharmony_ci%6 = OpTypeFunction %1 3337fd4e5da5Sopenharmony_ci%7 = OpFunction %1 None %6 3338fd4e5da5Sopenharmony_ci%8 = OpLabel 3339fd4e5da5Sopenharmony_ciOpSelectionMerge %9 None 3340fd4e5da5Sopenharmony_ciOpSwitch %5 %9 0 %10 3341fd4e5da5Sopenharmony_ci%10 = OpLabel 3342fd4e5da5Sopenharmony_ciOpSelectionMerge %11 None 3343fd4e5da5Sopenharmony_ciOpBranchConditional %4 %11 %12 3344fd4e5da5Sopenharmony_ci%12 = OpLabel 3345fd4e5da5Sopenharmony_ciOpBranch %9 3346fd4e5da5Sopenharmony_ci%11 = OpLabel 3347fd4e5da5Sopenharmony_ciOpBranch %9 3348fd4e5da5Sopenharmony_ci%9 = OpLabel 3349fd4e5da5Sopenharmony_ciOpReturn 3350fd4e5da5Sopenharmony_ciOpFunctionEnd 3351fd4e5da5Sopenharmony_ci)"; 3352fd4e5da5Sopenharmony_ci 3353fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3354fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 3355fd4e5da5Sopenharmony_ci} 3356fd4e5da5Sopenharmony_ci 3357fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, InvalidBreakFromSwitch) { 3358fd4e5da5Sopenharmony_ci const std::string text = R"( 3359fd4e5da5Sopenharmony_ciOpCapability Shader 3360fd4e5da5Sopenharmony_ciOpCapability Linkage 3361fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3362fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 3363fd4e5da5Sopenharmony_ci%2 = OpTypeBool 3364fd4e5da5Sopenharmony_ci%3 = OpTypeInt 32 0 3365fd4e5da5Sopenharmony_ci%4 = OpUndef %2 3366fd4e5da5Sopenharmony_ci%5 = OpUndef %3 3367fd4e5da5Sopenharmony_ci%6 = OpTypeFunction %1 3368fd4e5da5Sopenharmony_ci%7 = OpFunction %1 None %6 3369fd4e5da5Sopenharmony_ci%8 = OpLabel 3370fd4e5da5Sopenharmony_ciOpSelectionMerge %9 None 3371fd4e5da5Sopenharmony_ciOpSwitch %5 %9 0 %10 3372fd4e5da5Sopenharmony_ci%10 = OpLabel 3373fd4e5da5Sopenharmony_ciOpSelectionMerge %11 None 3374fd4e5da5Sopenharmony_ciOpSwitch %5 %11 0 %12 3375fd4e5da5Sopenharmony_ci%12 = OpLabel 3376fd4e5da5Sopenharmony_ciOpBranch %9 3377fd4e5da5Sopenharmony_ci%11 = OpLabel 3378fd4e5da5Sopenharmony_ciOpBranch %9 3379fd4e5da5Sopenharmony_ci%9 = OpLabel 3380fd4e5da5Sopenharmony_ciOpReturn 3381fd4e5da5Sopenharmony_ciOpFunctionEnd 3382fd4e5da5Sopenharmony_ci)"; 3383fd4e5da5Sopenharmony_ci 3384fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3385fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3386fd4e5da5Sopenharmony_ci EXPECT_THAT( 3387fd4e5da5Sopenharmony_ci getDiagnosticString(), 3388fd4e5da5Sopenharmony_ci HasSubstr("block <ID> '12[%12]' exits the selection headed by <ID> " 3389fd4e5da5Sopenharmony_ci "'10[%10]', but not via a structured exit")); 3390fd4e5da5Sopenharmony_ci} 3391fd4e5da5Sopenharmony_ci 3392fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, BreakToOuterSwitch) { 3393fd4e5da5Sopenharmony_ci const std::string text = R"( 3394fd4e5da5Sopenharmony_ciOpCapability Shader 3395fd4e5da5Sopenharmony_ciOpCapability Linkage 3396fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3397fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 3398fd4e5da5Sopenharmony_ci%2 = OpTypeBool 3399fd4e5da5Sopenharmony_ci%3 = OpTypeInt 32 0 3400fd4e5da5Sopenharmony_ci%4 = OpUndef %2 3401fd4e5da5Sopenharmony_ci%5 = OpUndef %3 3402fd4e5da5Sopenharmony_ci%6 = OpTypeFunction %1 3403fd4e5da5Sopenharmony_ci%7 = OpFunction %1 None %6 3404fd4e5da5Sopenharmony_ci%8 = OpLabel 3405fd4e5da5Sopenharmony_ciOpSelectionMerge %9 None 3406fd4e5da5Sopenharmony_ciOpSwitch %5 %9 0 %10 3407fd4e5da5Sopenharmony_ci%10 = OpLabel 3408fd4e5da5Sopenharmony_ciOpSelectionMerge %11 None 3409fd4e5da5Sopenharmony_ciOpSwitch %5 %11 0 %12 3410fd4e5da5Sopenharmony_ci%12 = OpLabel 3411fd4e5da5Sopenharmony_ciOpSelectionMerge %13 None 3412fd4e5da5Sopenharmony_ciOpBranchConditional %4 %13 %14 3413fd4e5da5Sopenharmony_ci%14 = OpLabel 3414fd4e5da5Sopenharmony_ciOpBranch %9 3415fd4e5da5Sopenharmony_ci%13 = OpLabel 3416fd4e5da5Sopenharmony_ciOpBranch %11 3417fd4e5da5Sopenharmony_ci%11 = OpLabel 3418fd4e5da5Sopenharmony_ciOpBranch %9 3419fd4e5da5Sopenharmony_ci%9 = OpLabel 3420fd4e5da5Sopenharmony_ciOpReturn 3421fd4e5da5Sopenharmony_ciOpFunctionEnd 3422fd4e5da5Sopenharmony_ci)"; 3423fd4e5da5Sopenharmony_ci 3424fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3425fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3426fd4e5da5Sopenharmony_ci EXPECT_THAT( 3427fd4e5da5Sopenharmony_ci getDiagnosticString(), 3428fd4e5da5Sopenharmony_ci HasSubstr("block <ID> '14[%14]' exits the selection headed by <ID> " 3429fd4e5da5Sopenharmony_ci "'10[%10]', but not via a structured exit")); 3430fd4e5da5Sopenharmony_ci} 3431fd4e5da5Sopenharmony_ci 3432fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, BreakToOuterLoop) { 3433fd4e5da5Sopenharmony_ci const std::string text = R"( 3434fd4e5da5Sopenharmony_ciOpCapability Shader 3435fd4e5da5Sopenharmony_ciOpCapability Linkage 3436fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3437fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 3438fd4e5da5Sopenharmony_ci%2 = OpTypeBool 3439fd4e5da5Sopenharmony_ci%3 = OpUndef %2 3440fd4e5da5Sopenharmony_ci%4 = OpTypeFunction %1 3441fd4e5da5Sopenharmony_ci%5 = OpFunction %1 None %4 3442fd4e5da5Sopenharmony_ci%6 = OpLabel 3443fd4e5da5Sopenharmony_ciOpBranch %7 3444fd4e5da5Sopenharmony_ci%7 = OpLabel 3445fd4e5da5Sopenharmony_ciOpLoopMerge %8 %9 None 3446fd4e5da5Sopenharmony_ciOpBranch %10 3447fd4e5da5Sopenharmony_ci%10 = OpLabel 3448fd4e5da5Sopenharmony_ciOpLoopMerge %11 %12 None 3449fd4e5da5Sopenharmony_ciOpBranch %13 3450fd4e5da5Sopenharmony_ci%13 = OpLabel 3451fd4e5da5Sopenharmony_ciOpSelectionMerge %14 None 3452fd4e5da5Sopenharmony_ciOpBranchConditional %3 %14 %15 3453fd4e5da5Sopenharmony_ci%15 = OpLabel 3454fd4e5da5Sopenharmony_ciOpBranch %8 3455fd4e5da5Sopenharmony_ci%14 = OpLabel 3456fd4e5da5Sopenharmony_ciOpBranch %12 3457fd4e5da5Sopenharmony_ci%12 = OpLabel 3458fd4e5da5Sopenharmony_ciOpBranchConditional %3 %10 %11 3459fd4e5da5Sopenharmony_ci%11 = OpLabel 3460fd4e5da5Sopenharmony_ciOpBranch %9 3461fd4e5da5Sopenharmony_ci%9 = OpLabel 3462fd4e5da5Sopenharmony_ciOpBranchConditional %3 %7 %8 3463fd4e5da5Sopenharmony_ci%8 = OpLabel 3464fd4e5da5Sopenharmony_ciOpReturn 3465fd4e5da5Sopenharmony_ciOpFunctionEnd 3466fd4e5da5Sopenharmony_ci)"; 3467fd4e5da5Sopenharmony_ci 3468fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3469fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3470fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 3471fd4e5da5Sopenharmony_ci HasSubstr("block <ID> '15[%15]' exits the loop headed by <ID> " 3472fd4e5da5Sopenharmony_ci "'10[%10]', but not via a structured exit")); 3473fd4e5da5Sopenharmony_ci} 3474fd4e5da5Sopenharmony_ci 3475fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, ContinueFromNestedSelection) { 3476fd4e5da5Sopenharmony_ci const std::string text = R"( 3477fd4e5da5Sopenharmony_ciOpCapability Shader 3478fd4e5da5Sopenharmony_ciOpCapability Linkage 3479fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3480fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3481fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3482fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3483fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3484fd4e5da5Sopenharmony_ci%4 = OpFunction %void None %void_fn 3485fd4e5da5Sopenharmony_ci%5 = OpLabel 3486fd4e5da5Sopenharmony_ciOpBranch %48 3487fd4e5da5Sopenharmony_ci%48 = OpLabel 3488fd4e5da5Sopenharmony_ciOpLoopMerge %47 %50 None 3489fd4e5da5Sopenharmony_ciOpBranch %10 3490fd4e5da5Sopenharmony_ci%10 = OpLabel 3491fd4e5da5Sopenharmony_ciOpLoopMerge %12 %37 None 3492fd4e5da5Sopenharmony_ciOpBranchConditional %undef %11 %12 3493fd4e5da5Sopenharmony_ci%11 = OpLabel 3494fd4e5da5Sopenharmony_ciOpSelectionMerge %31 None 3495fd4e5da5Sopenharmony_ciOpBranchConditional %undef %30 %31 3496fd4e5da5Sopenharmony_ci%30 = OpLabel 3497fd4e5da5Sopenharmony_ciOpSelectionMerge %38 None 3498fd4e5da5Sopenharmony_ciOpBranchConditional %undef %36 %38 3499fd4e5da5Sopenharmony_ci%36 = OpLabel 3500fd4e5da5Sopenharmony_ciOpBranch %38 3501fd4e5da5Sopenharmony_ci%38 = OpLabel 3502fd4e5da5Sopenharmony_ciOpBranch %37 3503fd4e5da5Sopenharmony_ci%37 = OpLabel 3504fd4e5da5Sopenharmony_ciOpBranch %10 3505fd4e5da5Sopenharmony_ci%31 = OpLabel 3506fd4e5da5Sopenharmony_ciOpBranch %12 3507fd4e5da5Sopenharmony_ci%12 = OpLabel 3508fd4e5da5Sopenharmony_ciOpSelectionMerge %55 None 3509fd4e5da5Sopenharmony_ciOpBranchConditional %undef %47 %55 3510fd4e5da5Sopenharmony_ci%55 = OpLabel 3511fd4e5da5Sopenharmony_ciOpBranch %47 3512fd4e5da5Sopenharmony_ci%50 = OpLabel 3513fd4e5da5Sopenharmony_ciOpBranch %48 3514fd4e5da5Sopenharmony_ci%47 = OpLabel 3515fd4e5da5Sopenharmony_ciOpReturn 3516fd4e5da5Sopenharmony_ciOpFunctionEnd 3517fd4e5da5Sopenharmony_ci)"; 3518fd4e5da5Sopenharmony_ci 3519fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3520fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 3521fd4e5da5Sopenharmony_ci} 3522fd4e5da5Sopenharmony_ci 3523fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, MissingMergeConditionalBranchBad) { 3524fd4e5da5Sopenharmony_ci const std::string text = R"( 3525fd4e5da5Sopenharmony_ciOpCapability Shader 3526fd4e5da5Sopenharmony_ciOpCapability Linkage 3527fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3528fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3529fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3530fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3531fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3532fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3533fd4e5da5Sopenharmony_ci%entry = OpLabel 3534fd4e5da5Sopenharmony_ciOpBranchConditional %undef %then %else 3535fd4e5da5Sopenharmony_ci%then = OpLabel 3536fd4e5da5Sopenharmony_ciOpReturn 3537fd4e5da5Sopenharmony_ci%else = OpLabel 3538fd4e5da5Sopenharmony_ciOpReturn 3539fd4e5da5Sopenharmony_ciOpFunctionEnd 3540fd4e5da5Sopenharmony_ci)"; 3541fd4e5da5Sopenharmony_ci 3542fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3543fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3544fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured")); 3545fd4e5da5Sopenharmony_ci} 3546fd4e5da5Sopenharmony_ci 3547fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, LoopConditionalBranchWithoutExitBad) { 3548fd4e5da5Sopenharmony_ci const std::string text = R"( 3549fd4e5da5Sopenharmony_ciOpCapability Shader 3550fd4e5da5Sopenharmony_ciOpCapability Linkage 3551fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3552fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3553fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3554fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3555fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3556fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3557fd4e5da5Sopenharmony_ci%entry = OpLabel 3558fd4e5da5Sopenharmony_ciOpBranch %loop 3559fd4e5da5Sopenharmony_ci%loop = OpLabel 3560fd4e5da5Sopenharmony_ciOpLoopMerge %exit %continue None 3561fd4e5da5Sopenharmony_ciOpBranchConditional %undef %then %else 3562fd4e5da5Sopenharmony_ci%then = OpLabel 3563fd4e5da5Sopenharmony_ciOpBranch %continue 3564fd4e5da5Sopenharmony_ci%else = OpLabel 3565fd4e5da5Sopenharmony_ciOpBranch %exit 3566fd4e5da5Sopenharmony_ci%continue = OpLabel 3567fd4e5da5Sopenharmony_ciOpBranch %loop 3568fd4e5da5Sopenharmony_ci%exit = OpLabel 3569fd4e5da5Sopenharmony_ciOpReturn 3570fd4e5da5Sopenharmony_ciOpFunctionEnd 3571fd4e5da5Sopenharmony_ci)"; 3572fd4e5da5Sopenharmony_ci 3573fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3574fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3575fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured")); 3576fd4e5da5Sopenharmony_ci} 3577fd4e5da5Sopenharmony_ci 3578fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, MissingMergeSwitchBad) { 3579fd4e5da5Sopenharmony_ci const std::string text = R"( 3580fd4e5da5Sopenharmony_ciOpCapability Shader 3581fd4e5da5Sopenharmony_ciOpCapability Linkage 3582fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3583fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3584fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3585fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 3586fd4e5da5Sopenharmony_ci%undef = OpUndef %int 3587fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3588fd4e5da5Sopenharmony_ci%entry = OpLabel 3589fd4e5da5Sopenharmony_ciOpSwitch %undef %then 0 %else 3590fd4e5da5Sopenharmony_ci%then = OpLabel 3591fd4e5da5Sopenharmony_ciOpReturn 3592fd4e5da5Sopenharmony_ci%else = OpLabel 3593fd4e5da5Sopenharmony_ciOpReturn 3594fd4e5da5Sopenharmony_ciOpFunctionEnd 3595fd4e5da5Sopenharmony_ci)"; 3596fd4e5da5Sopenharmony_ci 3597fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3598fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3599fd4e5da5Sopenharmony_ci EXPECT_THAT( 3600fd4e5da5Sopenharmony_ci getDiagnosticString(), 3601fd4e5da5Sopenharmony_ci HasSubstr( 3602fd4e5da5Sopenharmony_ci "OpSwitch must be preceded by an OpSelectionMerge instruction")); 3603fd4e5da5Sopenharmony_ci} 3604fd4e5da5Sopenharmony_ci 3605fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, MissingMergeSwitchBad2) { 3606fd4e5da5Sopenharmony_ci const std::string text = R"( 3607fd4e5da5Sopenharmony_ciOpCapability Shader 3608fd4e5da5Sopenharmony_ciOpCapability Linkage 3609fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3610fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3611fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3612fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 3613fd4e5da5Sopenharmony_ci%undef = OpUndef %int 3614fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3615fd4e5da5Sopenharmony_ci%entry = OpLabel 3616fd4e5da5Sopenharmony_ciOpSwitch %undef %then 0 %then 1 %then 2 %else 3617fd4e5da5Sopenharmony_ci%then = OpLabel 3618fd4e5da5Sopenharmony_ciOpReturn 3619fd4e5da5Sopenharmony_ci%else = OpLabel 3620fd4e5da5Sopenharmony_ciOpReturn 3621fd4e5da5Sopenharmony_ciOpFunctionEnd 3622fd4e5da5Sopenharmony_ci)"; 3623fd4e5da5Sopenharmony_ci 3624fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3625fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3626fd4e5da5Sopenharmony_ci EXPECT_THAT( 3627fd4e5da5Sopenharmony_ci getDiagnosticString(), 3628fd4e5da5Sopenharmony_ci HasSubstr( 3629fd4e5da5Sopenharmony_ci "OpSwitch must be preceded by an OpSelectionMerge instruction")); 3630fd4e5da5Sopenharmony_ci} 3631fd4e5da5Sopenharmony_ci 3632fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, MissingMergeOneBranchToMergeGood) { 3633fd4e5da5Sopenharmony_ci const std::string text = R"( 3634fd4e5da5Sopenharmony_ciOpCapability Shader 3635fd4e5da5Sopenharmony_ciOpCapability Linkage 3636fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3637fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3638fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3639fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3640fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3641fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3642fd4e5da5Sopenharmony_ci%entry = OpLabel 3643fd4e5da5Sopenharmony_ciOpSelectionMerge %b3 None 3644fd4e5da5Sopenharmony_ciOpBranchConditional %undef %b1 %b2 3645fd4e5da5Sopenharmony_ci%b1 = OpLabel 3646fd4e5da5Sopenharmony_ciOpBranchConditional %undef %b2 %b3 3647fd4e5da5Sopenharmony_ci%b2 = OpLabel 3648fd4e5da5Sopenharmony_ciOpBranch %b3 3649fd4e5da5Sopenharmony_ci%b3 = OpLabel 3650fd4e5da5Sopenharmony_ciOpReturn 3651fd4e5da5Sopenharmony_ciOpFunctionEnd 3652fd4e5da5Sopenharmony_ci)"; 3653fd4e5da5Sopenharmony_ci 3654fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3655fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 3656fd4e5da5Sopenharmony_ci} 3657fd4e5da5Sopenharmony_ci 3658fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, MissingMergeSameTargetConditionalBranchGood) { 3659fd4e5da5Sopenharmony_ci const std::string text = R"( 3660fd4e5da5Sopenharmony_ciOpCapability Shader 3661fd4e5da5Sopenharmony_ciOpCapability Linkage 3662fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3663fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3664fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3665fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3666fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3667fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3668fd4e5da5Sopenharmony_ci%entry = OpLabel 3669fd4e5da5Sopenharmony_ciOpBranchConditional %undef %then %then 3670fd4e5da5Sopenharmony_ci%then = OpLabel 3671fd4e5da5Sopenharmony_ciOpReturn 3672fd4e5da5Sopenharmony_ciOpFunctionEnd 3673fd4e5da5Sopenharmony_ci)"; 3674fd4e5da5Sopenharmony_ci 3675fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3676fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 3677fd4e5da5Sopenharmony_ci} 3678fd4e5da5Sopenharmony_ci 3679fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, MissingMergeOneTargetSwitchBad) { 3680fd4e5da5Sopenharmony_ci const std::string text = R"( 3681fd4e5da5Sopenharmony_ciOpCapability Shader 3682fd4e5da5Sopenharmony_ciOpCapability Linkage 3683fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3684fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3685fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3686fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 3687fd4e5da5Sopenharmony_ci%undef = OpUndef %int 3688fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3689fd4e5da5Sopenharmony_ci%entry = OpLabel 3690fd4e5da5Sopenharmony_ciOpSwitch %undef %then 0 %then 1 %then 3691fd4e5da5Sopenharmony_ci%then = OpLabel 3692fd4e5da5Sopenharmony_ciOpReturn 3693fd4e5da5Sopenharmony_ciOpFunctionEnd 3694fd4e5da5Sopenharmony_ci)"; 3695fd4e5da5Sopenharmony_ci 3696fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3697fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3698fd4e5da5Sopenharmony_ci EXPECT_THAT( 3699fd4e5da5Sopenharmony_ci getDiagnosticString(), 3700fd4e5da5Sopenharmony_ci HasSubstr( 3701fd4e5da5Sopenharmony_ci "OpSwitch must be preceded by an OpSelectionMerge instruction")); 3702fd4e5da5Sopenharmony_ci} 3703fd4e5da5Sopenharmony_ci 3704fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, MissingMergeOneUnseenTargetSwitchBad) { 3705fd4e5da5Sopenharmony_ci const std::string text = R"( 3706fd4e5da5Sopenharmony_ciOpCapability Shader 3707fd4e5da5Sopenharmony_ciOpCapability Linkage 3708fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3709fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3710fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3711fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 3712fd4e5da5Sopenharmony_ci%undef_int = OpUndef %int 3713fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3714fd4e5da5Sopenharmony_ci%undef_bool = OpUndef %bool 3715fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3716fd4e5da5Sopenharmony_ci%entry = OpLabel 3717fd4e5da5Sopenharmony_ciOpSelectionMerge %merge None 3718fd4e5da5Sopenharmony_ciOpBranchConditional %undef_bool %merge %b1 3719fd4e5da5Sopenharmony_ci%b1 = OpLabel 3720fd4e5da5Sopenharmony_ciOpSwitch %undef_int %b2 0 %b2 1 %merge 2 %b2 3721fd4e5da5Sopenharmony_ci%b2 = OpLabel 3722fd4e5da5Sopenharmony_ciOpBranch %merge 3723fd4e5da5Sopenharmony_ci%merge = OpLabel 3724fd4e5da5Sopenharmony_ciOpReturn 3725fd4e5da5Sopenharmony_ciOpFunctionEnd 3726fd4e5da5Sopenharmony_ci)"; 3727fd4e5da5Sopenharmony_ci 3728fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3729fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3730fd4e5da5Sopenharmony_ci EXPECT_THAT( 3731fd4e5da5Sopenharmony_ci getDiagnosticString(), 3732fd4e5da5Sopenharmony_ci HasSubstr( 3733fd4e5da5Sopenharmony_ci "OpSwitch must be preceded by an OpSelectionMerge instruction")); 3734fd4e5da5Sopenharmony_ci} 3735fd4e5da5Sopenharmony_ci 3736fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, MissingMergeLoopBreakGood) { 3737fd4e5da5Sopenharmony_ci const std::string text = R"( 3738fd4e5da5Sopenharmony_ciOpCapability Shader 3739fd4e5da5Sopenharmony_ciOpCapability Linkage 3740fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3741fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3742fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3743fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3744fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3745fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3746fd4e5da5Sopenharmony_ci%entry = OpLabel 3747fd4e5da5Sopenharmony_ciOpBranch %loop 3748fd4e5da5Sopenharmony_ci%loop = OpLabel 3749fd4e5da5Sopenharmony_ciOpLoopMerge %exit %continue None 3750fd4e5da5Sopenharmony_ciOpBranch %body 3751fd4e5da5Sopenharmony_ci%body = OpLabel 3752fd4e5da5Sopenharmony_ciOpBranchConditional %undef %body2 %exit 3753fd4e5da5Sopenharmony_ci%body2 = OpLabel 3754fd4e5da5Sopenharmony_ciOpBranch %continue 3755fd4e5da5Sopenharmony_ci%continue = OpLabel 3756fd4e5da5Sopenharmony_ciOpBranch %loop 3757fd4e5da5Sopenharmony_ci%exit = OpLabel 3758fd4e5da5Sopenharmony_ciOpReturn 3759fd4e5da5Sopenharmony_ciOpFunctionEnd 3760fd4e5da5Sopenharmony_ci)"; 3761fd4e5da5Sopenharmony_ci 3762fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3763fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 3764fd4e5da5Sopenharmony_ci} 3765fd4e5da5Sopenharmony_ci 3766fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, MissingMergeLoopContinueGood) { 3767fd4e5da5Sopenharmony_ci const std::string text = R"( 3768fd4e5da5Sopenharmony_ciOpCapability Shader 3769fd4e5da5Sopenharmony_ciOpCapability Linkage 3770fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3771fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3772fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3773fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3774fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3775fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3776fd4e5da5Sopenharmony_ci%entry = OpLabel 3777fd4e5da5Sopenharmony_ciOpBranch %loop 3778fd4e5da5Sopenharmony_ci%loop = OpLabel 3779fd4e5da5Sopenharmony_ciOpLoopMerge %exit %continue None 3780fd4e5da5Sopenharmony_ciOpBranch %body 3781fd4e5da5Sopenharmony_ci%body = OpLabel 3782fd4e5da5Sopenharmony_ciOpBranchConditional %undef %body2 %continue 3783fd4e5da5Sopenharmony_ci%body2 = OpLabel 3784fd4e5da5Sopenharmony_ciOpBranch %continue 3785fd4e5da5Sopenharmony_ci%continue = OpLabel 3786fd4e5da5Sopenharmony_ciOpBranch %loop 3787fd4e5da5Sopenharmony_ci%exit = OpLabel 3788fd4e5da5Sopenharmony_ciOpReturn 3789fd4e5da5Sopenharmony_ciOpFunctionEnd 3790fd4e5da5Sopenharmony_ci)"; 3791fd4e5da5Sopenharmony_ci 3792fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3793fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 3794fd4e5da5Sopenharmony_ci} 3795fd4e5da5Sopenharmony_ci 3796fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, MissingMergeSwitchBreakGood) { 3797fd4e5da5Sopenharmony_ci const std::string text = R"( 3798fd4e5da5Sopenharmony_ciOpCapability Shader 3799fd4e5da5Sopenharmony_ciOpCapability Linkage 3800fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3801fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3802fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3803fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3804fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3805fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 3806fd4e5da5Sopenharmony_ci%int_0 = OpConstant %int 0 3807fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3808fd4e5da5Sopenharmony_ci%entry = OpLabel 3809fd4e5da5Sopenharmony_ciOpSelectionMerge %merge None 3810fd4e5da5Sopenharmony_ciOpSwitch %int_0 %merge 1 %b1 3811fd4e5da5Sopenharmony_ci%b1 = OpLabel 3812fd4e5da5Sopenharmony_ciOpBranchConditional %undef %merge %b2 3813fd4e5da5Sopenharmony_ci%b2 = OpLabel 3814fd4e5da5Sopenharmony_ciOpBranch %merge 3815fd4e5da5Sopenharmony_ci%merge = OpLabel 3816fd4e5da5Sopenharmony_ciOpReturn 3817fd4e5da5Sopenharmony_ciOpFunctionEnd 3818fd4e5da5Sopenharmony_ci)"; 3819fd4e5da5Sopenharmony_ci 3820fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3821fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 3822fd4e5da5Sopenharmony_ci} 3823fd4e5da5Sopenharmony_ci 3824fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, MissingMergeSwitchFallThroughGood) { 3825fd4e5da5Sopenharmony_ci const std::string text = R"( 3826fd4e5da5Sopenharmony_ciOpCapability Shader 3827fd4e5da5Sopenharmony_ciOpCapability Linkage 3828fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3829fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3830fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3831fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3832fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3833fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 3834fd4e5da5Sopenharmony_ci%int_0 = OpConstant %int 0 3835fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3836fd4e5da5Sopenharmony_ci%entry = OpLabel 3837fd4e5da5Sopenharmony_ciOpSelectionMerge %merge None 3838fd4e5da5Sopenharmony_ciOpSwitch %int_0 %b1 1 %b2 3839fd4e5da5Sopenharmony_ci%b1 = OpLabel 3840fd4e5da5Sopenharmony_ciOpBranchConditional %undef %b3 %b2 3841fd4e5da5Sopenharmony_ci%b2 = OpLabel 3842fd4e5da5Sopenharmony_ciOpBranch %merge 3843fd4e5da5Sopenharmony_ci%b3 = OpLabel 3844fd4e5da5Sopenharmony_ciOpBranch %merge 3845fd4e5da5Sopenharmony_ci%merge = OpLabel 3846fd4e5da5Sopenharmony_ciOpReturn 3847fd4e5da5Sopenharmony_ciOpFunctionEnd 3848fd4e5da5Sopenharmony_ci)"; 3849fd4e5da5Sopenharmony_ci 3850fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3851fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 3852fd4e5da5Sopenharmony_ci} 3853fd4e5da5Sopenharmony_ci 3854fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, MissingMergeInALoopBad) { 3855fd4e5da5Sopenharmony_ci const std::string text = R"( 3856fd4e5da5Sopenharmony_ciOpCapability Shader 3857fd4e5da5Sopenharmony_ciOpCapability Linkage 3858fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3859fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3860fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3861fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3862fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3863fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3864fd4e5da5Sopenharmony_ci%entry = OpLabel 3865fd4e5da5Sopenharmony_ciOpBranch %loop 3866fd4e5da5Sopenharmony_ci%loop = OpLabel 3867fd4e5da5Sopenharmony_ciOpLoopMerge %exit %continue None 3868fd4e5da5Sopenharmony_ciOpBranch %body 3869fd4e5da5Sopenharmony_ci%body = OpLabel 3870fd4e5da5Sopenharmony_ciOpBranchConditional %undef %b1 %b2 3871fd4e5da5Sopenharmony_ci%b1 = OpLabel 3872fd4e5da5Sopenharmony_ciOpBranch %exit 3873fd4e5da5Sopenharmony_ci%b2 = OpLabel 3874fd4e5da5Sopenharmony_ciOpBranch %continue 3875fd4e5da5Sopenharmony_ci%continue = OpLabel 3876fd4e5da5Sopenharmony_ciOpBranch %loop 3877fd4e5da5Sopenharmony_ci%exit = OpLabel 3878fd4e5da5Sopenharmony_ciOpReturn 3879fd4e5da5Sopenharmony_ciOpFunctionEnd 3880fd4e5da5Sopenharmony_ci)"; 3881fd4e5da5Sopenharmony_ci 3882fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3883fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3884fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured")); 3885fd4e5da5Sopenharmony_ci} 3886fd4e5da5Sopenharmony_ci 3887fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, MissingMergeCrissCrossBad) { 3888fd4e5da5Sopenharmony_ci const std::string text = R"( 3889fd4e5da5Sopenharmony_ciOpCapability Shader 3890fd4e5da5Sopenharmony_ciOpCapability Linkage 3891fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3892fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3893fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3894fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3895fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3896fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3897fd4e5da5Sopenharmony_ci%entry = OpLabel 3898fd4e5da5Sopenharmony_ciOpSelectionMerge %merge None 3899fd4e5da5Sopenharmony_ciOpBranchConditional %undef %b1 %b2 3900fd4e5da5Sopenharmony_ci%b1 = OpLabel 3901fd4e5da5Sopenharmony_ciOpBranchConditional %undef %b3 %b4 3902fd4e5da5Sopenharmony_ci%b2 = OpLabel 3903fd4e5da5Sopenharmony_ciOpBranchConditional %undef %b3 %b4 3904fd4e5da5Sopenharmony_ci%b3 = OpLabel 3905fd4e5da5Sopenharmony_ciOpBranch %merge 3906fd4e5da5Sopenharmony_ci%b4 = OpLabel 3907fd4e5da5Sopenharmony_ciOpBranch %merge 3908fd4e5da5Sopenharmony_ci%merge = OpLabel 3909fd4e5da5Sopenharmony_ciOpReturn 3910fd4e5da5Sopenharmony_ciOpFunctionEnd 3911fd4e5da5Sopenharmony_ci)"; 3912fd4e5da5Sopenharmony_ci 3913fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3914fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3915fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), HasSubstr("Selection must be structured")); 3916fd4e5da5Sopenharmony_ci} 3917fd4e5da5Sopenharmony_ci 3918fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, ContinueCannotBeSelectionMergeTarget) { 3919fd4e5da5Sopenharmony_ci const std::string text = R"( 3920fd4e5da5Sopenharmony_ciOpCapability Shader 3921fd4e5da5Sopenharmony_ciOpCapability Linkage 3922fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3923fd4e5da5Sopenharmony_ciOpName %loop "loop" 3924fd4e5da5Sopenharmony_ciOpName %continue "continue" 3925fd4e5da5Sopenharmony_ciOpName %body "body" 3926fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3927fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3928fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3929fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3930fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3931fd4e5da5Sopenharmony_ci%entry = OpLabel 3932fd4e5da5Sopenharmony_ciOpBranch %loop 3933fd4e5da5Sopenharmony_ci%loop = OpLabel 3934fd4e5da5Sopenharmony_ciOpLoopMerge %exit %continue None 3935fd4e5da5Sopenharmony_ciOpBranch %body 3936fd4e5da5Sopenharmony_ci%body = OpLabel 3937fd4e5da5Sopenharmony_ciOpSelectionMerge %continue None 3938fd4e5da5Sopenharmony_ciOpBranchConditional %undef %exit %continue 3939fd4e5da5Sopenharmony_ci%continue = OpLabel 3940fd4e5da5Sopenharmony_ciOpBranch %loop 3941fd4e5da5Sopenharmony_ci%exit = OpLabel 3942fd4e5da5Sopenharmony_ciOpReturn 3943fd4e5da5Sopenharmony_ciOpFunctionEnd 3944fd4e5da5Sopenharmony_ci)"; 3945fd4e5da5Sopenharmony_ci 3946fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3947fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3948fd4e5da5Sopenharmony_ci EXPECT_THAT( 3949fd4e5da5Sopenharmony_ci getDiagnosticString(), 3950fd4e5da5Sopenharmony_ci HasSubstr("Header block '3[%body]' is contained in the loop construct " 3951fd4e5da5Sopenharmony_ci "headed by " 3952fd4e5da5Sopenharmony_ci "'1[%loop]', but its merge block '2[%continue]' is not")); 3953fd4e5da5Sopenharmony_ci} 3954fd4e5da5Sopenharmony_ci 3955fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, ContinueCannotBeLoopMergeTarget) { 3956fd4e5da5Sopenharmony_ci const std::string text = R"( 3957fd4e5da5Sopenharmony_ciOpCapability Shader 3958fd4e5da5Sopenharmony_ciOpCapability Linkage 3959fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3960fd4e5da5Sopenharmony_ciOpName %loop "loop" 3961fd4e5da5Sopenharmony_ciOpName %continue "continue" 3962fd4e5da5Sopenharmony_ciOpName %inner "inner" 3963fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3964fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 3965fd4e5da5Sopenharmony_ci%bool = OpTypeBool 3966fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 3967fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 3968fd4e5da5Sopenharmony_ci%entry = OpLabel 3969fd4e5da5Sopenharmony_ciOpBranch %loop 3970fd4e5da5Sopenharmony_ci%loop = OpLabel 3971fd4e5da5Sopenharmony_ciOpLoopMerge %exit %continue None 3972fd4e5da5Sopenharmony_ciOpBranchConditional %undef %exit %inner 3973fd4e5da5Sopenharmony_ci%inner = OpLabel 3974fd4e5da5Sopenharmony_ciOpLoopMerge %continue %inner None 3975fd4e5da5Sopenharmony_ciOpBranchConditional %undef %inner %continue 3976fd4e5da5Sopenharmony_ci%continue = OpLabel 3977fd4e5da5Sopenharmony_ciOpBranch %loop 3978fd4e5da5Sopenharmony_ci%exit = OpLabel 3979fd4e5da5Sopenharmony_ciOpReturn 3980fd4e5da5Sopenharmony_ciOpFunctionEnd 3981fd4e5da5Sopenharmony_ci)"; 3982fd4e5da5Sopenharmony_ci 3983fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 3984fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 3985fd4e5da5Sopenharmony_ci EXPECT_THAT( 3986fd4e5da5Sopenharmony_ci getDiagnosticString(), 3987fd4e5da5Sopenharmony_ci HasSubstr("Header block '3[%inner]' is contained in the loop construct " 3988fd4e5da5Sopenharmony_ci "headed by " 3989fd4e5da5Sopenharmony_ci "'1[%loop]', but its merge block '2[%continue]' is not")); 3990fd4e5da5Sopenharmony_ci} 3991fd4e5da5Sopenharmony_ci 3992fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, ExitFromConstructWhoseHeaderIsAMerge) { 3993fd4e5da5Sopenharmony_ci const std::string text = R"( 3994fd4e5da5Sopenharmony_ciOpCapability Shader 3995fd4e5da5Sopenharmony_ciOpCapability Linkage 3996fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 3997fd4e5da5Sopenharmony_ci%void = OpTypeVoid 3998fd4e5da5Sopenharmony_ci%2 = OpTypeFunction %void 3999fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 1 4000fd4e5da5Sopenharmony_ci%4 = OpUndef %int 4001fd4e5da5Sopenharmony_ci%bool = OpTypeBool 4002fd4e5da5Sopenharmony_ci%6 = OpUndef %bool 4003fd4e5da5Sopenharmony_ci%7 = OpFunction %void None %2 4004fd4e5da5Sopenharmony_ci%8 = OpLabel 4005fd4e5da5Sopenharmony_ciOpSelectionMerge %9 None 4006fd4e5da5Sopenharmony_ciOpSwitch %4 %10 0 %11 4007fd4e5da5Sopenharmony_ci%10 = OpLabel 4008fd4e5da5Sopenharmony_ciOpBranch %9 4009fd4e5da5Sopenharmony_ci%11 = OpLabel 4010fd4e5da5Sopenharmony_ciOpBranch %12 4011fd4e5da5Sopenharmony_ci%12 = OpLabel 4012fd4e5da5Sopenharmony_ciOpLoopMerge %13 %14 None 4013fd4e5da5Sopenharmony_ciOpBranch %15 4014fd4e5da5Sopenharmony_ci%15 = OpLabel 4015fd4e5da5Sopenharmony_ciOpSelectionMerge %16 None 4016fd4e5da5Sopenharmony_ciOpSwitch %4 %17 1 %18 2 %19 4017fd4e5da5Sopenharmony_ci%17 = OpLabel 4018fd4e5da5Sopenharmony_ciOpBranch %16 4019fd4e5da5Sopenharmony_ci%18 = OpLabel 4020fd4e5da5Sopenharmony_ciOpBranch %14 4021fd4e5da5Sopenharmony_ci%19 = OpLabel 4022fd4e5da5Sopenharmony_ciOpBranch %16 4023fd4e5da5Sopenharmony_ci%16 = OpLabel 4024fd4e5da5Sopenharmony_ciOpBranch %14 4025fd4e5da5Sopenharmony_ci%14 = OpLabel 4026fd4e5da5Sopenharmony_ciOpBranchConditional %6 %12 %13 4027fd4e5da5Sopenharmony_ci%13 = OpLabel 4028fd4e5da5Sopenharmony_ciOpSelectionMerge %20 None 4029fd4e5da5Sopenharmony_ciOpBranchConditional %6 %21 %20 4030fd4e5da5Sopenharmony_ci%21 = OpLabel 4031fd4e5da5Sopenharmony_ciOpBranch %9 4032fd4e5da5Sopenharmony_ci%20 = OpLabel 4033fd4e5da5Sopenharmony_ciOpBranch %10 4034fd4e5da5Sopenharmony_ci%9 = OpLabel 4035fd4e5da5Sopenharmony_ciOpReturn 4036fd4e5da5Sopenharmony_ciOpFunctionEnd 4037fd4e5da5Sopenharmony_ci)"; 4038fd4e5da5Sopenharmony_ci 4039fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4040fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 4041fd4e5da5Sopenharmony_ci} 4042fd4e5da5Sopenharmony_ci 4043fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, ExitFromConstructWhoseHeaderIsAMerge2) { 4044fd4e5da5Sopenharmony_ci const std::string text = R"( 4045fd4e5da5Sopenharmony_ci OpCapability Shader 4046fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 4047fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 4048fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %2 "main" 4049fd4e5da5Sopenharmony_ci OpExecutionMode %2 OriginUpperLeft 4050fd4e5da5Sopenharmony_ci %void = OpTypeVoid 4051fd4e5da5Sopenharmony_ci %4 = OpTypeFunction %void 4052fd4e5da5Sopenharmony_ci %int = OpTypeInt 32 1 4053fd4e5da5Sopenharmony_ci %6 = OpUndef %int 4054fd4e5da5Sopenharmony_ci %bool = OpTypeBool 4055fd4e5da5Sopenharmony_ci %8 = OpUndef %bool 4056fd4e5da5Sopenharmony_ci %2 = OpFunction %void None %4 4057fd4e5da5Sopenharmony_ci %9 = OpLabel 4058fd4e5da5Sopenharmony_ci OpSelectionMerge %10 None 4059fd4e5da5Sopenharmony_ci OpSwitch %6 %11 0 %12 4060fd4e5da5Sopenharmony_ci %11 = OpLabel 4061fd4e5da5Sopenharmony_ci OpBranch %10 4062fd4e5da5Sopenharmony_ci %12 = OpLabel 4063fd4e5da5Sopenharmony_ci OpBranch %13 4064fd4e5da5Sopenharmony_ci %13 = OpLabel 4065fd4e5da5Sopenharmony_ci OpLoopMerge %14 %15 None 4066fd4e5da5Sopenharmony_ci OpBranch %16 4067fd4e5da5Sopenharmony_ci %16 = OpLabel 4068fd4e5da5Sopenharmony_ci OpSelectionMerge %17 None 4069fd4e5da5Sopenharmony_ci OpSwitch %6 %18 1 %19 2 %20 4070fd4e5da5Sopenharmony_ci %18 = OpLabel 4071fd4e5da5Sopenharmony_ci OpBranch %17 4072fd4e5da5Sopenharmony_ci %19 = OpLabel 4073fd4e5da5Sopenharmony_ci OpBranch %15 4074fd4e5da5Sopenharmony_ci %20 = OpLabel 4075fd4e5da5Sopenharmony_ci OpBranch %17 4076fd4e5da5Sopenharmony_ci %17 = OpLabel 4077fd4e5da5Sopenharmony_ci OpBranch %15 4078fd4e5da5Sopenharmony_ci %15 = OpLabel 4079fd4e5da5Sopenharmony_ci OpBranchConditional %8 %13 %14 4080fd4e5da5Sopenharmony_ci %14 = OpLabel 4081fd4e5da5Sopenharmony_ci OpSelectionMerge %21 None 4082fd4e5da5Sopenharmony_ci OpBranchConditional %8 %22 %21 4083fd4e5da5Sopenharmony_ci %22 = OpLabel 4084fd4e5da5Sopenharmony_ci OpSelectionMerge %23 None 4085fd4e5da5Sopenharmony_ci OpBranchConditional %8 %24 %23 4086fd4e5da5Sopenharmony_ci %24 = OpLabel 4087fd4e5da5Sopenharmony_ci OpBranch %10 4088fd4e5da5Sopenharmony_ci %23 = OpLabel 4089fd4e5da5Sopenharmony_ci OpBranch %21 4090fd4e5da5Sopenharmony_ci %21 = OpLabel 4091fd4e5da5Sopenharmony_ci OpBranch %11 4092fd4e5da5Sopenharmony_ci %10 = OpLabel 4093fd4e5da5Sopenharmony_ci OpReturn 4094fd4e5da5Sopenharmony_ci OpFunctionEnd 4095fd4e5da5Sopenharmony_ci)"; 4096fd4e5da5Sopenharmony_ci 4097fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4098fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions()); 4099fd4e5da5Sopenharmony_ci} 4100fd4e5da5Sopenharmony_ci 4101fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, PhiResultInvalidSampler) { 4102fd4e5da5Sopenharmony_ci const std::string text = R"( 4103fd4e5da5Sopenharmony_ciOpCapability Shader 4104fd4e5da5Sopenharmony_ciOpCapability Linkage 4105fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 4106fd4e5da5Sopenharmony_ci%void = OpTypeVoid 4107fd4e5da5Sopenharmony_ci%bool = OpTypeBool 4108fd4e5da5Sopenharmony_ci%f32 = OpTypeFloat 32 4109fd4e5da5Sopenharmony_ci%sampler = OpTypeSampler 4110fd4e5da5Sopenharmony_ci%ptr_uc_sampler = OpTypePointer UniformConstant %sampler 4111fd4e5da5Sopenharmony_ci%sampler_var = OpVariable %ptr_uc_sampler UniformConstant 4112fd4e5da5Sopenharmony_ci%undef_bool = OpUndef %bool 4113fd4e5da5Sopenharmony_ci%undef_sampler = OpUndef %sampler 4114fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 4115fd4e5da5Sopenharmony_ci%fn = OpFunction %void None %void_fn 4116fd4e5da5Sopenharmony_ci%entry = OpLabel 4117fd4e5da5Sopenharmony_ci%ld_sampler = OpLoad %sampler %sampler_var 4118fd4e5da5Sopenharmony_ciOpBranch %loop 4119fd4e5da5Sopenharmony_ci%loop = OpLabel 4120fd4e5da5Sopenharmony_ci%phi = OpPhi %sampler %undef_sampler %entry %ld_sampler %loop 4121fd4e5da5Sopenharmony_ciOpLoopMerge %exit %loop None 4122fd4e5da5Sopenharmony_ciOpBranchConditional %undef_bool %exit %loop 4123fd4e5da5Sopenharmony_ci%exit = OpLabel 4124fd4e5da5Sopenharmony_ciOpReturn 4125fd4e5da5Sopenharmony_ciOpFunctionEnd 4126fd4e5da5Sopenharmony_ci)"; 4127fd4e5da5Sopenharmony_ci 4128fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4129fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 4130fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 4131fd4e5da5Sopenharmony_ci HasSubstr("Result type cannot be OpTypeSampler")); 4132fd4e5da5Sopenharmony_ci} 4133fd4e5da5Sopenharmony_ci 4134fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, PhiResultInvalidImage) { 4135fd4e5da5Sopenharmony_ci const std::string text = R"( 4136fd4e5da5Sopenharmony_ciOpCapability Shader 4137fd4e5da5Sopenharmony_ciOpCapability Linkage 4138fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 4139fd4e5da5Sopenharmony_ci%void = OpTypeVoid 4140fd4e5da5Sopenharmony_ci%bool = OpTypeBool 4141fd4e5da5Sopenharmony_ci%f32 = OpTypeFloat 32 4142fd4e5da5Sopenharmony_ci%image = OpTypeImage %f32 2D 0 0 0 1 Rgba32f 4143fd4e5da5Sopenharmony_ci%ptr_uc_image = OpTypePointer UniformConstant %image 4144fd4e5da5Sopenharmony_ci%image_var = OpVariable %ptr_uc_image UniformConstant 4145fd4e5da5Sopenharmony_ci%undef_bool = OpUndef %bool 4146fd4e5da5Sopenharmony_ci%undef_image = OpUndef %image 4147fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 4148fd4e5da5Sopenharmony_ci%fn = OpFunction %void None %void_fn 4149fd4e5da5Sopenharmony_ci%entry = OpLabel 4150fd4e5da5Sopenharmony_ci%ld_image = OpLoad %image %image_var 4151fd4e5da5Sopenharmony_ciOpBranch %loop 4152fd4e5da5Sopenharmony_ci%loop = OpLabel 4153fd4e5da5Sopenharmony_ci%phi = OpPhi %image %undef_image %entry %ld_image %loop 4154fd4e5da5Sopenharmony_ciOpLoopMerge %exit %loop None 4155fd4e5da5Sopenharmony_ciOpBranchConditional %undef_bool %exit %loop 4156fd4e5da5Sopenharmony_ci%exit = OpLabel 4157fd4e5da5Sopenharmony_ciOpReturn 4158fd4e5da5Sopenharmony_ciOpFunctionEnd 4159fd4e5da5Sopenharmony_ci)"; 4160fd4e5da5Sopenharmony_ci 4161fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4162fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 4163fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 4164fd4e5da5Sopenharmony_ci HasSubstr("Result type cannot be OpTypeImage")); 4165fd4e5da5Sopenharmony_ci} 4166fd4e5da5Sopenharmony_ci 4167fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, PhiResultInvalidSampledImage) { 4168fd4e5da5Sopenharmony_ci const std::string text = R"( 4169fd4e5da5Sopenharmony_ciOpCapability Shader 4170fd4e5da5Sopenharmony_ciOpCapability Linkage 4171fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 4172fd4e5da5Sopenharmony_ci%void = OpTypeVoid 4173fd4e5da5Sopenharmony_ci%bool = OpTypeBool 4174fd4e5da5Sopenharmony_ci%f32 = OpTypeFloat 32 4175fd4e5da5Sopenharmony_ci%sampler = OpTypeSampler 4176fd4e5da5Sopenharmony_ci%ptr_uc_sampler = OpTypePointer UniformConstant %sampler 4177fd4e5da5Sopenharmony_ci%sampler_var = OpVariable %ptr_uc_sampler UniformConstant 4178fd4e5da5Sopenharmony_ci%image = OpTypeImage %f32 2D 0 0 0 1 Rgba32f 4179fd4e5da5Sopenharmony_ci%ptr_uc_image = OpTypePointer UniformConstant %image 4180fd4e5da5Sopenharmony_ci%image_var = OpVariable %ptr_uc_image UniformConstant 4181fd4e5da5Sopenharmony_ci%sampled_image = OpTypeSampledImage %image 4182fd4e5da5Sopenharmony_ci%undef_bool = OpUndef %bool 4183fd4e5da5Sopenharmony_ci%undef_sampled_image = OpUndef %sampled_image 4184fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 4185fd4e5da5Sopenharmony_ci%fn = OpFunction %void None %void_fn 4186fd4e5da5Sopenharmony_ci%entry = OpLabel 4187fd4e5da5Sopenharmony_ci%ld_image = OpLoad %image %image_var 4188fd4e5da5Sopenharmony_ci%ld_sampler = OpLoad %sampler %sampler_var 4189fd4e5da5Sopenharmony_ciOpBranch %loop 4190fd4e5da5Sopenharmony_ci%loop = OpLabel 4191fd4e5da5Sopenharmony_ci%phi = OpPhi %sampled_image %undef_sampled_image %entry %sample %loop 4192fd4e5da5Sopenharmony_ci%sample = OpSampledImage %sampled_image %ld_image %ld_sampler 4193fd4e5da5Sopenharmony_ciOpLoopMerge %exit %loop None 4194fd4e5da5Sopenharmony_ciOpBranchConditional %undef_bool %exit %loop 4195fd4e5da5Sopenharmony_ci%exit = OpLabel 4196fd4e5da5Sopenharmony_ciOpReturn 4197fd4e5da5Sopenharmony_ciOpFunctionEnd 4198fd4e5da5Sopenharmony_ci)"; 4199fd4e5da5Sopenharmony_ci 4200fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4201fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 4202fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 4203fd4e5da5Sopenharmony_ci HasSubstr("Result type cannot be OpTypeSampledImage")); 4204fd4e5da5Sopenharmony_ci} 4205fd4e5da5Sopenharmony_ci 4206fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, PhiResultValidPreLegalizationSampler) { 4207fd4e5da5Sopenharmony_ci const std::string text = R"( 4208fd4e5da5Sopenharmony_ciOpCapability Shader 4209fd4e5da5Sopenharmony_ciOpCapability Linkage 4210fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 4211fd4e5da5Sopenharmony_ci%void = OpTypeVoid 4212fd4e5da5Sopenharmony_ci%bool = OpTypeBool 4213fd4e5da5Sopenharmony_ci%f32 = OpTypeFloat 32 4214fd4e5da5Sopenharmony_ci%sampler = OpTypeSampler 4215fd4e5da5Sopenharmony_ci%ptr_uc_sampler = OpTypePointer UniformConstant %sampler 4216fd4e5da5Sopenharmony_ci%sampler_var = OpVariable %ptr_uc_sampler UniformConstant 4217fd4e5da5Sopenharmony_ci%undef_bool = OpUndef %bool 4218fd4e5da5Sopenharmony_ci%undef_sampler = OpUndef %sampler 4219fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 4220fd4e5da5Sopenharmony_ci%fn = OpFunction %void None %void_fn 4221fd4e5da5Sopenharmony_ci%entry = OpLabel 4222fd4e5da5Sopenharmony_ci%ld_sampler = OpLoad %sampler %sampler_var 4223fd4e5da5Sopenharmony_ciOpBranch %loop 4224fd4e5da5Sopenharmony_ci%loop = OpLabel 4225fd4e5da5Sopenharmony_ci%phi = OpPhi %sampler %undef_sampler %entry %ld_sampler %loop 4226fd4e5da5Sopenharmony_ciOpLoopMerge %exit %loop None 4227fd4e5da5Sopenharmony_ciOpBranchConditional %undef_bool %exit %loop 4228fd4e5da5Sopenharmony_ci%exit = OpLabel 4229fd4e5da5Sopenharmony_ciOpReturn 4230fd4e5da5Sopenharmony_ciOpFunctionEnd 4231fd4e5da5Sopenharmony_ci)"; 4232fd4e5da5Sopenharmony_ci 4233fd4e5da5Sopenharmony_ci options_->before_hlsl_legalization = true; 4234fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4235fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 4236fd4e5da5Sopenharmony_ci} 4237fd4e5da5Sopenharmony_ci 4238fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, PhiResultValidPreLegalizationImage) { 4239fd4e5da5Sopenharmony_ci const std::string text = R"( 4240fd4e5da5Sopenharmony_ciOpCapability Shader 4241fd4e5da5Sopenharmony_ciOpCapability Linkage 4242fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 4243fd4e5da5Sopenharmony_ci%void = OpTypeVoid 4244fd4e5da5Sopenharmony_ci%bool = OpTypeBool 4245fd4e5da5Sopenharmony_ci%f32 = OpTypeFloat 32 4246fd4e5da5Sopenharmony_ci%image = OpTypeImage %f32 2D 0 0 0 1 Rgba32f 4247fd4e5da5Sopenharmony_ci%ptr_uc_image = OpTypePointer UniformConstant %image 4248fd4e5da5Sopenharmony_ci%image_var = OpVariable %ptr_uc_image UniformConstant 4249fd4e5da5Sopenharmony_ci%undef_bool = OpUndef %bool 4250fd4e5da5Sopenharmony_ci%undef_image = OpUndef %image 4251fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 4252fd4e5da5Sopenharmony_ci%fn = OpFunction %void None %void_fn 4253fd4e5da5Sopenharmony_ci%entry = OpLabel 4254fd4e5da5Sopenharmony_ci%ld_image = OpLoad %image %image_var 4255fd4e5da5Sopenharmony_ciOpBranch %loop 4256fd4e5da5Sopenharmony_ci%loop = OpLabel 4257fd4e5da5Sopenharmony_ci%phi = OpPhi %image %undef_image %entry %ld_image %loop 4258fd4e5da5Sopenharmony_ciOpLoopMerge %exit %loop None 4259fd4e5da5Sopenharmony_ciOpBranchConditional %undef_bool %exit %loop 4260fd4e5da5Sopenharmony_ci%exit = OpLabel 4261fd4e5da5Sopenharmony_ciOpReturn 4262fd4e5da5Sopenharmony_ciOpFunctionEnd 4263fd4e5da5Sopenharmony_ci)"; 4264fd4e5da5Sopenharmony_ci 4265fd4e5da5Sopenharmony_ci options_->before_hlsl_legalization = true; 4266fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4267fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 4268fd4e5da5Sopenharmony_ci} 4269fd4e5da5Sopenharmony_ci 4270fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, PhiResultValidPreLegalizationSampledImage) { 4271fd4e5da5Sopenharmony_ci const std::string text = R"( 4272fd4e5da5Sopenharmony_ciOpCapability Shader 4273fd4e5da5Sopenharmony_ciOpCapability Linkage 4274fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 4275fd4e5da5Sopenharmony_ci%void = OpTypeVoid 4276fd4e5da5Sopenharmony_ci%bool = OpTypeBool 4277fd4e5da5Sopenharmony_ci%f32 = OpTypeFloat 32 4278fd4e5da5Sopenharmony_ci%sampler = OpTypeSampler 4279fd4e5da5Sopenharmony_ci%ptr_uc_sampler = OpTypePointer UniformConstant %sampler 4280fd4e5da5Sopenharmony_ci%sampler_var = OpVariable %ptr_uc_sampler UniformConstant 4281fd4e5da5Sopenharmony_ci%image = OpTypeImage %f32 2D 0 0 0 1 Rgba32f 4282fd4e5da5Sopenharmony_ci%ptr_uc_image = OpTypePointer UniformConstant %image 4283fd4e5da5Sopenharmony_ci%image_var = OpVariable %ptr_uc_image UniformConstant 4284fd4e5da5Sopenharmony_ci%sampled_image = OpTypeSampledImage %image 4285fd4e5da5Sopenharmony_ci%undef_bool = OpUndef %bool 4286fd4e5da5Sopenharmony_ci%undef_sampled_image = OpUndef %sampled_image 4287fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 4288fd4e5da5Sopenharmony_ci%fn = OpFunction %void None %void_fn 4289fd4e5da5Sopenharmony_ci%entry = OpLabel 4290fd4e5da5Sopenharmony_ci%ld_image = OpLoad %image %image_var 4291fd4e5da5Sopenharmony_ci%ld_sampler = OpLoad %sampler %sampler_var 4292fd4e5da5Sopenharmony_ciOpBranch %loop 4293fd4e5da5Sopenharmony_ci%loop = OpLabel 4294fd4e5da5Sopenharmony_ci%phi = OpPhi %sampled_image %undef_sampled_image %entry %sample %loop 4295fd4e5da5Sopenharmony_ci%sample = OpSampledImage %sampled_image %ld_image %ld_sampler 4296fd4e5da5Sopenharmony_ciOpLoopMerge %exit %loop None 4297fd4e5da5Sopenharmony_ciOpBranchConditional %undef_bool %exit %loop 4298fd4e5da5Sopenharmony_ci%exit = OpLabel 4299fd4e5da5Sopenharmony_ciOpReturn 4300fd4e5da5Sopenharmony_ciOpFunctionEnd 4301fd4e5da5Sopenharmony_ci)"; 4302fd4e5da5Sopenharmony_ci 4303fd4e5da5Sopenharmony_ci options_->before_hlsl_legalization = true; 4304fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4305fd4e5da5Sopenharmony_ci ASSERT_EQ(SPV_SUCCESS, ValidateInstructions()); 4306fd4e5da5Sopenharmony_ci} 4307fd4e5da5Sopenharmony_ci 4308fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, StructuredSelections_RegisterBothTrueAndFalse) { 4309fd4e5da5Sopenharmony_ci // In this test, we try to make a case where the false branches 4310fd4e5da5Sopenharmony_ci // to %20 and %60 from blocks %10 and %50 must be registered 4311fd4e5da5Sopenharmony_ci // during the validity check for sturctured selections. 4312fd4e5da5Sopenharmony_ci // However, an error is caught earlier in the flow, that the 4313fd4e5da5Sopenharmony_ci // branches from %100 to %20 and %60 violate dominance. 4314fd4e5da5Sopenharmony_ci const std::string text = R"( 4315fd4e5da5Sopenharmony_ci OpCapability Shader 4316fd4e5da5Sopenharmony_ci OpMemoryModel Logical Simple 4317fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %main "main" 4318fd4e5da5Sopenharmony_ci OpExecutionMode %main OriginUpperLeft 4319fd4e5da5Sopenharmony_ci 4320fd4e5da5Sopenharmony_ci %void = OpTypeVoid 4321fd4e5da5Sopenharmony_ci %void_fn = OpTypeFunction %void 4322fd4e5da5Sopenharmony_ci 4323fd4e5da5Sopenharmony_ci %bool = OpTypeBool 4324fd4e5da5Sopenharmony_ci %cond = OpUndef %bool 4325fd4e5da5Sopenharmony_ci 4326fd4e5da5Sopenharmony_ci %main = OpFunction %void None %void_fn 4327fd4e5da5Sopenharmony_ci 4328fd4e5da5Sopenharmony_ci %1 = OpLabel 4329fd4e5da5Sopenharmony_ci OpSelectionMerge %999 None 4330fd4e5da5Sopenharmony_ci OpBranchConditional %cond %10 %100 4331fd4e5da5Sopenharmony_ci 4332fd4e5da5Sopenharmony_ci %10 = OpLabel 4333fd4e5da5Sopenharmony_ci OpSelectionMerge %30 None ; force registration of %30 4334fd4e5da5Sopenharmony_ci OpBranchConditional %cond %30 %20 ; %20 should be registered too 4335fd4e5da5Sopenharmony_ci 4336fd4e5da5Sopenharmony_ci %20 = OpLabel 4337fd4e5da5Sopenharmony_ci OpBranch %30 4338fd4e5da5Sopenharmony_ci 4339fd4e5da5Sopenharmony_ci %30 = OpLabel ; merge for first if 4340fd4e5da5Sopenharmony_ci OpBranch %50 4341fd4e5da5Sopenharmony_ci 4342fd4e5da5Sopenharmony_ci 4343fd4e5da5Sopenharmony_ci %50 = OpLabel 4344fd4e5da5Sopenharmony_ci OpSelectionMerge %70 None ; force registration of %70 4345fd4e5da5Sopenharmony_ci OpBranchConditional %cond %70 %60 ; %60 should be registered 4346fd4e5da5Sopenharmony_ci 4347fd4e5da5Sopenharmony_ci %60 = OpLabel 4348fd4e5da5Sopenharmony_ci OpBranch %70 4349fd4e5da5Sopenharmony_ci 4350fd4e5da5Sopenharmony_ci %70 = OpLabel ; merge for second if 4351fd4e5da5Sopenharmony_ci OpBranch %999 4352fd4e5da5Sopenharmony_ci 4353fd4e5da5Sopenharmony_ci %100 = OpLabel 4354fd4e5da5Sopenharmony_ci OpBranchConditional %cond %20 %60 ; should require a merge 4355fd4e5da5Sopenharmony_ci 4356fd4e5da5Sopenharmony_ci %999 = OpLabel 4357fd4e5da5Sopenharmony_ci OpReturn 4358fd4e5da5Sopenharmony_ci 4359fd4e5da5Sopenharmony_ci OpFunctionEnd 4360fd4e5da5Sopenharmony_ci)"; 4361fd4e5da5Sopenharmony_ci 4362fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4363fd4e5da5Sopenharmony_ci EXPECT_NE(SPV_SUCCESS, ValidateInstructions()); 4364fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 4365fd4e5da5Sopenharmony_ci HasSubstr("The selection construct with the selection header " 4366fd4e5da5Sopenharmony_ci "'8[%8]' does not structurally dominate the merge " 4367fd4e5da5Sopenharmony_ci "block '10[%10]'\n")); 4368fd4e5da5Sopenharmony_ci} 4369fd4e5da5Sopenharmony_ci 4370fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, UnreachableIsStaticallyReachable) { 4371fd4e5da5Sopenharmony_ci const std::string text = R"( 4372fd4e5da5Sopenharmony_ciOpCapability Shader 4373fd4e5da5Sopenharmony_ciOpCapability Linkage 4374fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 4375fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 4376fd4e5da5Sopenharmony_ci%2 = OpTypeFunction %1 4377fd4e5da5Sopenharmony_ci%3 = OpFunction %1 None %2 4378fd4e5da5Sopenharmony_ci%4 = OpLabel 4379fd4e5da5Sopenharmony_ciOpBranch %5 4380fd4e5da5Sopenharmony_ci%5 = OpLabel 4381fd4e5da5Sopenharmony_ciOpUnreachable 4382fd4e5da5Sopenharmony_ciOpFunctionEnd 4383fd4e5da5Sopenharmony_ci)"; 4384fd4e5da5Sopenharmony_ci 4385fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4386fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); 4387fd4e5da5Sopenharmony_ci 4388fd4e5da5Sopenharmony_ci auto f = vstate_->function(3); 4389fd4e5da5Sopenharmony_ci auto entry = f->GetBlock(4).first; 4390fd4e5da5Sopenharmony_ci ASSERT_TRUE(entry->reachable()); 4391fd4e5da5Sopenharmony_ci auto end = f->GetBlock(5).first; 4392fd4e5da5Sopenharmony_ci ASSERT_TRUE(end->reachable()); 4393fd4e5da5Sopenharmony_ci} 4394fd4e5da5Sopenharmony_ci 4395fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, BlockOrderDoesNotAffectReachability) { 4396fd4e5da5Sopenharmony_ci const std::string text = R"( 4397fd4e5da5Sopenharmony_ciOpCapability Shader 4398fd4e5da5Sopenharmony_ciOpCapability Linkage 4399fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 4400fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 4401fd4e5da5Sopenharmony_ci%2 = OpTypeFunction %1 4402fd4e5da5Sopenharmony_ci%3 = OpTypeBool 4403fd4e5da5Sopenharmony_ci%4 = OpUndef %3 4404fd4e5da5Sopenharmony_ci%5 = OpFunction %1 None %2 4405fd4e5da5Sopenharmony_ci%6 = OpLabel 4406fd4e5da5Sopenharmony_ciOpBranch %7 4407fd4e5da5Sopenharmony_ci%7 = OpLabel 4408fd4e5da5Sopenharmony_ciOpSelectionMerge %8 None 4409fd4e5da5Sopenharmony_ciOpBranchConditional %4 %9 %10 4410fd4e5da5Sopenharmony_ci%8 = OpLabel 4411fd4e5da5Sopenharmony_ciOpReturn 4412fd4e5da5Sopenharmony_ci%9 = OpLabel 4413fd4e5da5Sopenharmony_ciOpBranch %8 4414fd4e5da5Sopenharmony_ci%10 = OpLabel 4415fd4e5da5Sopenharmony_ciOpBranch %8 4416fd4e5da5Sopenharmony_ci%11 = OpLabel 4417fd4e5da5Sopenharmony_ciOpUnreachable 4418fd4e5da5Sopenharmony_ciOpFunctionEnd 4419fd4e5da5Sopenharmony_ci)"; 4420fd4e5da5Sopenharmony_ci 4421fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4422fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateAndRetrieveValidationState()); 4423fd4e5da5Sopenharmony_ci 4424fd4e5da5Sopenharmony_ci auto f = vstate_->function(5); 4425fd4e5da5Sopenharmony_ci auto b6 = f->GetBlock(6).first; 4426fd4e5da5Sopenharmony_ci auto b7 = f->GetBlock(7).first; 4427fd4e5da5Sopenharmony_ci auto b8 = f->GetBlock(8).first; 4428fd4e5da5Sopenharmony_ci auto b9 = f->GetBlock(9).first; 4429fd4e5da5Sopenharmony_ci auto b10 = f->GetBlock(10).first; 4430fd4e5da5Sopenharmony_ci auto b11 = f->GetBlock(11).first; 4431fd4e5da5Sopenharmony_ci 4432fd4e5da5Sopenharmony_ci ASSERT_TRUE(b6->reachable()); 4433fd4e5da5Sopenharmony_ci ASSERT_TRUE(b7->reachable()); 4434fd4e5da5Sopenharmony_ci ASSERT_TRUE(b8->reachable()); 4435fd4e5da5Sopenharmony_ci ASSERT_TRUE(b9->reachable()); 4436fd4e5da5Sopenharmony_ci ASSERT_TRUE(b10->reachable()); 4437fd4e5da5Sopenharmony_ci ASSERT_FALSE(b11->reachable()); 4438fd4e5da5Sopenharmony_ci} 4439fd4e5da5Sopenharmony_ci 4440fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, PhiInstructionWithDuplicateIncomingEdges) { 4441fd4e5da5Sopenharmony_ci const std::string text = R"( 4442fd4e5da5Sopenharmony_ci OpCapability Shader 4443fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 4444fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 4445fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %4 "main" 4446fd4e5da5Sopenharmony_ci OpExecutionMode %4 OriginUpperLeft 4447fd4e5da5Sopenharmony_ci OpSource ESSL 320 4448fd4e5da5Sopenharmony_ci %2 = OpTypeVoid 4449fd4e5da5Sopenharmony_ci %3 = OpTypeFunction %2 4450fd4e5da5Sopenharmony_ci %6 = OpTypeBool 4451fd4e5da5Sopenharmony_ci %7 = OpConstantTrue %6 4452fd4e5da5Sopenharmony_ci %4 = OpFunction %2 None %3 4453fd4e5da5Sopenharmony_ci %5 = OpLabel 4454fd4e5da5Sopenharmony_ci OpSelectionMerge %10 None 4455fd4e5da5Sopenharmony_ci OpBranchConditional %7 %8 %9 4456fd4e5da5Sopenharmony_ci %8 = OpLabel 4457fd4e5da5Sopenharmony_ci OpBranch %10 4458fd4e5da5Sopenharmony_ci %9 = OpLabel 4459fd4e5da5Sopenharmony_ci OpBranch %10 4460fd4e5da5Sopenharmony_ci %10 = OpLabel 4461fd4e5da5Sopenharmony_ci %11 = OpPhi %6 %7 %8 %7 %8 4462fd4e5da5Sopenharmony_ci OpReturn 4463fd4e5da5Sopenharmony_ci OpFunctionEnd 4464fd4e5da5Sopenharmony_ci)"; 4465fd4e5da5Sopenharmony_ci 4466fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4467fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 4468fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 4469fd4e5da5Sopenharmony_ci HasSubstr("OpPhi references incoming basic block <id> ")); 4470fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), HasSubstr("multiple times.")); 4471fd4e5da5Sopenharmony_ci} 4472fd4e5da5Sopenharmony_ci 4473fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, PhiOnVoid) { 4474fd4e5da5Sopenharmony_ci const std::string text = R"( 4475fd4e5da5Sopenharmony_ci OpCapability Shader 4476fd4e5da5Sopenharmony_ci %1 = OpExtInstImport "GLSL.std.450" 4477fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 4478fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %4 "main" 4479fd4e5da5Sopenharmony_ci OpExecutionMode %4 OriginUpperLeft 4480fd4e5da5Sopenharmony_ci OpSource ESSL 320 4481fd4e5da5Sopenharmony_ci OpName %4 "main" 4482fd4e5da5Sopenharmony_ci OpName %6 "foo(" 4483fd4e5da5Sopenharmony_ci %2 = OpTypeVoid 4484fd4e5da5Sopenharmony_ci %3 = OpTypeFunction %2 4485fd4e5da5Sopenharmony_ci %4 = OpFunction %2 None %3 4486fd4e5da5Sopenharmony_ci %5 = OpLabel 4487fd4e5da5Sopenharmony_ci %8 = OpFunctionCall %2 %6 4488fd4e5da5Sopenharmony_ci OpBranch %20 4489fd4e5da5Sopenharmony_ci %20 = OpLabel 4490fd4e5da5Sopenharmony_ci %21 = OpPhi %2 %8 %20 4491fd4e5da5Sopenharmony_ci OpReturn 4492fd4e5da5Sopenharmony_ci OpFunctionEnd 4493fd4e5da5Sopenharmony_ci %6 = OpFunction %2 None %3 4494fd4e5da5Sopenharmony_ci %7 = OpLabel 4495fd4e5da5Sopenharmony_ci OpReturn 4496fd4e5da5Sopenharmony_ci OpFunctionEnd 4497fd4e5da5Sopenharmony_ci)"; 4498fd4e5da5Sopenharmony_ci 4499fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4500fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions()); 4501fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 4502fd4e5da5Sopenharmony_ci HasSubstr("OpPhi must not have void result type")); 4503fd4e5da5Sopenharmony_ci} 4504fd4e5da5Sopenharmony_ci 4505fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, InvalidExitSingleBlockLoop) { 4506fd4e5da5Sopenharmony_ci const std::string text = R"( 4507fd4e5da5Sopenharmony_ciOpCapability Shader 4508fd4e5da5Sopenharmony_ciOpCapability Linkage 4509fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 4510fd4e5da5Sopenharmony_ciOpName %5 "BAD" 4511fd4e5da5Sopenharmony_ci%void = OpTypeVoid 4512fd4e5da5Sopenharmony_ci%bool = OpTypeBool 4513fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 4514fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 4515fd4e5da5Sopenharmony_ci%fn = OpFunction %void None %void_fn 4516fd4e5da5Sopenharmony_ci%1 = OpLabel 4517fd4e5da5Sopenharmony_ciOpBranch %2 4518fd4e5da5Sopenharmony_ci%2 = OpLabel 4519fd4e5da5Sopenharmony_ciOpLoopMerge %3 %4 None 4520fd4e5da5Sopenharmony_ciOpBranchConditional %undef %3 %5 4521fd4e5da5Sopenharmony_ci%5 = OpLabel 4522fd4e5da5Sopenharmony_ciOpLoopMerge %6 %5 None 4523fd4e5da5Sopenharmony_ciOpBranchConditional %undef %5 %4 4524fd4e5da5Sopenharmony_ci%6 = OpLabel 4525fd4e5da5Sopenharmony_ciOpReturn 4526fd4e5da5Sopenharmony_ci%4 = OpLabel 4527fd4e5da5Sopenharmony_ciOpBranch %2 4528fd4e5da5Sopenharmony_ci%3 = OpLabel 4529fd4e5da5Sopenharmony_ciOpReturn 4530fd4e5da5Sopenharmony_ciOpFunctionEnd 4531fd4e5da5Sopenharmony_ci)"; 4532fd4e5da5Sopenharmony_ci 4533fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4534fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 4535fd4e5da5Sopenharmony_ci EXPECT_THAT( 4536fd4e5da5Sopenharmony_ci getDiagnosticString(), 4537fd4e5da5Sopenharmony_ci HasSubstr("block <ID> '1[%BAD]' exits the continue headed by <ID> " 4538fd4e5da5Sopenharmony_ci "'1[%BAD]', but not via a structured exit")); 4539fd4e5da5Sopenharmony_ci} 4540fd4e5da5Sopenharmony_ci 4541fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, SwitchSelectorNotAnInt) { 4542fd4e5da5Sopenharmony_ci const std::string spirv = R"( 4543fd4e5da5Sopenharmony_ciOpCapability Shader 4544fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 4545fd4e5da5Sopenharmony_ciOpEntryPoint GLCompute %main "main" 4546fd4e5da5Sopenharmony_ciOpExecutionMode %main LocalSize 1 1 1 4547fd4e5da5Sopenharmony_ci%void = OpTypeVoid 4548fd4e5da5Sopenharmony_ci%float = OpTypeFloat 32 4549fd4e5da5Sopenharmony_ci%float_1 = OpConstant %float 1 4550fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 4551fd4e5da5Sopenharmony_ci%main = OpFunction %void None %void_fn 4552fd4e5da5Sopenharmony_ci%entry = OpLabel 4553fd4e5da5Sopenharmony_ciOpSelectionMerge %default None 4554fd4e5da5Sopenharmony_ciOpSwitch %float_1 %default 4555fd4e5da5Sopenharmony_ci%default = OpLabel 4556fd4e5da5Sopenharmony_ciOpReturn 4557fd4e5da5Sopenharmony_ciOpFunctionEnd 4558fd4e5da5Sopenharmony_ci)"; 4559fd4e5da5Sopenharmony_ci 4560fd4e5da5Sopenharmony_ci CompileSuccessfully(spirv); 4561fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 4562fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 4563fd4e5da5Sopenharmony_ci HasSubstr("Selector type must be OpTypeInt")); 4564fd4e5da5Sopenharmony_ci} 4565fd4e5da5Sopenharmony_ci 4566fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, SwitchDefaultNotALabel) { 4567fd4e5da5Sopenharmony_ci const std::string spirv = R"( 4568fd4e5da5Sopenharmony_ciOpCapability Shader 4569fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 4570fd4e5da5Sopenharmony_ciOpEntryPoint GLCompute %main "main" 4571fd4e5da5Sopenharmony_ciOpExecutionMode %main LocalSize 1 1 1 4572fd4e5da5Sopenharmony_ci%void = OpTypeVoid 4573fd4e5da5Sopenharmony_ci%int = OpTypeInt 32 0 4574fd4e5da5Sopenharmony_ci%int_1 = OpConstant %int 1 4575fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 4576fd4e5da5Sopenharmony_ci%main = OpFunction %void None %void_fn 4577fd4e5da5Sopenharmony_ci%entry = OpLabel 4578fd4e5da5Sopenharmony_ciOpSelectionMerge %default None 4579fd4e5da5Sopenharmony_ciOpSwitch %int_1 %int_1 4580fd4e5da5Sopenharmony_ci%default = OpLabel 4581fd4e5da5Sopenharmony_ciOpReturn 4582fd4e5da5Sopenharmony_ciOpFunctionEnd 4583fd4e5da5Sopenharmony_ci)"; 4584fd4e5da5Sopenharmony_ci 4585fd4e5da5Sopenharmony_ci CompileSuccessfully(spirv); 4586fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions()); 4587fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 4588fd4e5da5Sopenharmony_ci HasSubstr("Default must be an OpLabel instruction")); 4589fd4e5da5Sopenharmony_ci} 4590fd4e5da5Sopenharmony_ci 4591fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, BlockDepthRecursion) { 4592fd4e5da5Sopenharmony_ci const std::string text = R"( 4593fd4e5da5Sopenharmony_ciOpCapability Shader 4594fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 4595fd4e5da5Sopenharmony_ciOpEntryPoint GLCompute %main "main" 4596fd4e5da5Sopenharmony_ci%void = OpTypeVoid 4597fd4e5da5Sopenharmony_ci%bool = OpTypeBool 4598fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 4599fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 4600fd4e5da5Sopenharmony_ci%main = OpFunction %void None %void_fn 4601fd4e5da5Sopenharmony_ci%1 = OpLabel 4602fd4e5da5Sopenharmony_ciOpBranch %2 4603fd4e5da5Sopenharmony_ci%2 = OpLabel 4604fd4e5da5Sopenharmony_ciOpLoopMerge %3 %4 None 4605fd4e5da5Sopenharmony_ciOpBranchConditional %undef %3 %4 4606fd4e5da5Sopenharmony_ci%4 = OpLabel 4607fd4e5da5Sopenharmony_ciOpBranch %2 4608fd4e5da5Sopenharmony_ci%3 = OpLabel 4609fd4e5da5Sopenharmony_ciOpBranch %5 4610fd4e5da5Sopenharmony_ci%5 = OpLabel 4611fd4e5da5Sopenharmony_ciOpSelectionMerge %2 None 4612fd4e5da5Sopenharmony_ciOpBranchConditional %undef %6 %7 4613fd4e5da5Sopenharmony_ci%6 = OpLabel 4614fd4e5da5Sopenharmony_ciOpReturn 4615fd4e5da5Sopenharmony_ci%7 = OpLabel 4616fd4e5da5Sopenharmony_ciOpReturn 4617fd4e5da5Sopenharmony_ciOpFunctionEnd 4618fd4e5da5Sopenharmony_ci)"; 4619fd4e5da5Sopenharmony_ci 4620fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4621fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 4622fd4e5da5Sopenharmony_ci} 4623fd4e5da5Sopenharmony_ci 4624fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, BadStructuredExitBackwardsMerge) { 4625fd4e5da5Sopenharmony_ci const std::string spirv = R"( 4626fd4e5da5Sopenharmony_ciOpCapability Shader 4627fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 4628fd4e5da5Sopenharmony_ciOpEntryPoint GLCompute %main "main" 4629fd4e5da5Sopenharmony_ci%void = OpTypeVoid 4630fd4e5da5Sopenharmony_ci%bool = OpTypeBool 4631fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 4632fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 4633fd4e5da5Sopenharmony_ci%main = OpFunction %void None %void_fn 4634fd4e5da5Sopenharmony_ci%1 = OpLabel 4635fd4e5da5Sopenharmony_ciOpBranch %2 4636fd4e5da5Sopenharmony_ci%2 = OpLabel 4637fd4e5da5Sopenharmony_ciOpLoopMerge %4 %5 None 4638fd4e5da5Sopenharmony_ciOpBranchConditional %undef %4 %6 4639fd4e5da5Sopenharmony_ci%6 = OpLabel 4640fd4e5da5Sopenharmony_ciOpSelectionMerge %7 None 4641fd4e5da5Sopenharmony_ciOpBranchConditional %undef %8 %9 4642fd4e5da5Sopenharmony_ci%7 = OpLabel 4643fd4e5da5Sopenharmony_ciOpReturn 4644fd4e5da5Sopenharmony_ci%8 = OpLabel 4645fd4e5da5Sopenharmony_ciOpBranch %5 4646fd4e5da5Sopenharmony_ci%9 = OpLabel 4647fd4e5da5Sopenharmony_ciOpSelectionMerge %6 None 4648fd4e5da5Sopenharmony_ciOpBranchConditional %undef %5 %5 4649fd4e5da5Sopenharmony_ci%5 = OpLabel 4650fd4e5da5Sopenharmony_ciOpBranch %2 4651fd4e5da5Sopenharmony_ci%4 = OpLabel 4652fd4e5da5Sopenharmony_ciOpReturn 4653fd4e5da5Sopenharmony_ciOpFunctionEnd 4654fd4e5da5Sopenharmony_ci)"; 4655fd4e5da5Sopenharmony_ci 4656fd4e5da5Sopenharmony_ci CompileSuccessfully(spirv); 4657fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 4658fd4e5da5Sopenharmony_ci} 4659fd4e5da5Sopenharmony_ci 4660fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, BranchConditionalDifferentTargetsPre1p6) { 4661fd4e5da5Sopenharmony_ci const std::string text = R"( 4662fd4e5da5Sopenharmony_ciOpCapability Shader 4663fd4e5da5Sopenharmony_ciOpCapability Linkage 4664fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 4665fd4e5da5Sopenharmony_ci%void = OpTypeVoid 4666fd4e5da5Sopenharmony_ci%bool = OpTypeBool 4667fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 4668fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 4669fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 4670fd4e5da5Sopenharmony_ci%entry = OpLabel 4671fd4e5da5Sopenharmony_ciOpBranchConditional %undef %target %target 4672fd4e5da5Sopenharmony_ci%target = OpLabel 4673fd4e5da5Sopenharmony_ciOpReturn 4674fd4e5da5Sopenharmony_ciOpFunctionEnd 4675fd4e5da5Sopenharmony_ci)"; 4676fd4e5da5Sopenharmony_ci 4677fd4e5da5Sopenharmony_ci CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_5); 4678fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_UNIVERSAL_1_5)); 4679fd4e5da5Sopenharmony_ci} 4680fd4e5da5Sopenharmony_ci 4681fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, BranchConditionalDifferentTargetsPost1p6) { 4682fd4e5da5Sopenharmony_ci const std::string text = R"( 4683fd4e5da5Sopenharmony_ciOpCapability Shader 4684fd4e5da5Sopenharmony_ciOpCapability Linkage 4685fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 4686fd4e5da5Sopenharmony_ci%void = OpTypeVoid 4687fd4e5da5Sopenharmony_ci%bool = OpTypeBool 4688fd4e5da5Sopenharmony_ci%undef = OpUndef %bool 4689fd4e5da5Sopenharmony_ci%void_fn = OpTypeFunction %void 4690fd4e5da5Sopenharmony_ci%func = OpFunction %void None %void_fn 4691fd4e5da5Sopenharmony_ci%entry = OpLabel 4692fd4e5da5Sopenharmony_ciOpBranchConditional %undef %target %target 4693fd4e5da5Sopenharmony_ci%target = OpLabel 4694fd4e5da5Sopenharmony_ciOpReturn 4695fd4e5da5Sopenharmony_ciOpFunctionEnd 4696fd4e5da5Sopenharmony_ci)"; 4697fd4e5da5Sopenharmony_ci 4698fd4e5da5Sopenharmony_ci CompileSuccessfully(text, SPV_ENV_UNIVERSAL_1_6); 4699fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_UNIVERSAL_1_6)); 4700fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 4701fd4e5da5Sopenharmony_ci HasSubstr("In SPIR-V 1.6 or later, True Label and False Label " 4702fd4e5da5Sopenharmony_ci "must be different labels")); 4703fd4e5da5Sopenharmony_ci} 4704fd4e5da5Sopenharmony_ci 4705fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, BadBackEdgeUnreachableContinue) { 4706fd4e5da5Sopenharmony_ci const std::string text = R"( 4707fd4e5da5Sopenharmony_ciOpCapability Shader 4708fd4e5da5Sopenharmony_ciOpCapability Linkage 4709fd4e5da5Sopenharmony_ciOpMemoryModel Logical GLSL450 4710fd4e5da5Sopenharmony_ci%1 = OpTypeVoid 4711fd4e5da5Sopenharmony_ci%2 = OpTypeFunction %1 4712fd4e5da5Sopenharmony_ci%3 = OpFunction %1 None %2 4713fd4e5da5Sopenharmony_ci%4 = OpLabel 4714fd4e5da5Sopenharmony_ciOpBranch %5 4715fd4e5da5Sopenharmony_ci%5 = OpLabel 4716fd4e5da5Sopenharmony_ciOpLoopMerge %6 %7 None 4717fd4e5da5Sopenharmony_ciOpBranch %8 4718fd4e5da5Sopenharmony_ci%8 = OpLabel 4719fd4e5da5Sopenharmony_ciOpBranch %5 4720fd4e5da5Sopenharmony_ci%7 = OpLabel 4721fd4e5da5Sopenharmony_ciOpUnreachable 4722fd4e5da5Sopenharmony_ci%6 = OpLabel 4723fd4e5da5Sopenharmony_ciOpUnreachable 4724fd4e5da5Sopenharmony_ciOpFunctionEnd 4725fd4e5da5Sopenharmony_ci)"; 4726fd4e5da5Sopenharmony_ci 4727fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4728fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 4729fd4e5da5Sopenharmony_ci EXPECT_THAT( 4730fd4e5da5Sopenharmony_ci getDiagnosticString(), 4731fd4e5da5Sopenharmony_ci HasSubstr("The continue construct with the continue target '7[%7]' " 4732fd4e5da5Sopenharmony_ci "does not structurally dominate the back-edge block '8[%8]'")); 4733fd4e5da5Sopenharmony_ci} 4734fd4e5da5Sopenharmony_ci 4735fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, BadLoop) { 4736fd4e5da5Sopenharmony_ci const std::string text = R"( 4737fd4e5da5Sopenharmony_ciOpCapability Shader 4738fd4e5da5Sopenharmony_ciOpMemoryModel Logical Simple 4739fd4e5da5Sopenharmony_ciOpEntryPoint Fragment %2 " " 4740fd4e5da5Sopenharmony_ciOpExecutionMode %2 OriginUpperLeft 4741fd4e5da5Sopenharmony_ciOpName %49 "loop" 4742fd4e5da5Sopenharmony_ci%void = OpTypeVoid 4743fd4e5da5Sopenharmony_ci%12 = OpTypeFunction %void 4744fd4e5da5Sopenharmony_ci%2 = OpFunction %void None %12 4745fd4e5da5Sopenharmony_ci%33 = OpLabel 4746fd4e5da5Sopenharmony_ciOpBranch %49 4747fd4e5da5Sopenharmony_ci%50 = OpLabel 4748fd4e5da5Sopenharmony_ciOpBranch %49 4749fd4e5da5Sopenharmony_ci%49 = OpLabel 4750fd4e5da5Sopenharmony_ciOpLoopMerge %33 %50 Unroll 4751fd4e5da5Sopenharmony_ciOpBranch %49 4752fd4e5da5Sopenharmony_ciOpFunctionEnd 4753fd4e5da5Sopenharmony_ci)"; 4754fd4e5da5Sopenharmony_ci 4755fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4756fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 4757fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 4758fd4e5da5Sopenharmony_ci HasSubstr("Loop header '2[%loop]' is targeted by 2 back-edge " 4759fd4e5da5Sopenharmony_ci "blocks but the standard requires exactly one")); 4760fd4e5da5Sopenharmony_ci} 4761fd4e5da5Sopenharmony_ci 4762fd4e5da5Sopenharmony_ciTEST_F(ValidateCFG, BadSwitch) { 4763fd4e5da5Sopenharmony_ci const std::string text = R"( 4764fd4e5da5Sopenharmony_ci OpCapability StorageImageExtendedFormats 4765fd4e5da5Sopenharmony_ci OpMemoryModel Logical GLSL450 4766fd4e5da5Sopenharmony_ci OpEntryPoint Fragment %2 "blah" %58 4767fd4e5da5Sopenharmony_ci OpExecutionMode %2 OriginUpperLeft 4768fd4e5da5Sopenharmony_ci OpName %BAD "BAD" 4769fd4e5da5Sopenharmony_ci %11 = OpTypeVoid 4770fd4e5da5Sopenharmony_ci %12 = OpTypeFunction %11 4771fd4e5da5Sopenharmony_ci %19 = OpTypeInt 32 1 4772fd4e5da5Sopenharmony_ci %21 = OpConstant %19 555758549 4773fd4e5da5Sopenharmony_ci %2 = OpFunction %11 None %12 4774fd4e5da5Sopenharmony_ci %4 = OpLabel 4775fd4e5da5Sopenharmony_ci OpBranch %33 4776fd4e5da5Sopenharmony_ci %33 = OpLabel 4777fd4e5da5Sopenharmony_ci OpLoopMerge %34 %35 None 4778fd4e5da5Sopenharmony_ci OpBranch %55 4779fd4e5da5Sopenharmony_ci %BAD = OpLabel 4780fd4e5da5Sopenharmony_ci OpSelectionMerge %53 None 4781fd4e5da5Sopenharmony_ci OpSwitch %21 %34 196153896 %53 20856160 %34 33570306 %34 593494531 %52 4782fd4e5da5Sopenharmony_ci %55 = OpLabel 4783fd4e5da5Sopenharmony_ci OpLoopMerge %52 %58 DontUnroll 4784fd4e5da5Sopenharmony_ci OpBranch %35 4785fd4e5da5Sopenharmony_ci %58 = OpLabel 4786fd4e5da5Sopenharmony_ci OpSelectionMerge %58 None 4787fd4e5da5Sopenharmony_ci OpSwitch %21 %52 178168 %55 608223677 %34 604111047 %34 -553516825 %34 -106432813 %BAD 6946864 %55 1257373689 %55 973090296 %35 -113180668 %55 537002232 %BAD 13762553 %BAD 1030172152 %35 -553516825 %55 -262137 %35 -1091822332 %BAD 131320 %52 131321 %35 131320 %52 131321 %35 -1091822332 %BAD 4788fd4e5da5Sopenharmony_ci %53 = OpLabel 4789fd4e5da5Sopenharmony_ci OpBranch %35 4790fd4e5da5Sopenharmony_ci %52 = OpLabel 4791fd4e5da5Sopenharmony_ci OpBranch %34 4792fd4e5da5Sopenharmony_ci %35 = OpLabel 4793fd4e5da5Sopenharmony_ci OpBranch %33 4794fd4e5da5Sopenharmony_ci %34 = OpLabel 4795fd4e5da5Sopenharmony_ci OpKill 4796fd4e5da5Sopenharmony_ci OpFunctionEnd 4797fd4e5da5Sopenharmony_ci)"; 4798fd4e5da5Sopenharmony_ci 4799fd4e5da5Sopenharmony_ci CompileSuccessfully(text); 4800fd4e5da5Sopenharmony_ci EXPECT_EQ(SPV_ERROR_INVALID_CFG, ValidateInstructions()); 4801fd4e5da5Sopenharmony_ci EXPECT_THAT(getDiagnosticString(), 4802fd4e5da5Sopenharmony_ci HasSubstr("exits the selection headed by <ID> '3[%BAD]', but not " 4803fd4e5da5Sopenharmony_ci "via a structured exit")); 4804fd4e5da5Sopenharmony_ci} 4805fd4e5da5Sopenharmony_ci 4806fd4e5da5Sopenharmony_ci} // namespace 4807fd4e5da5Sopenharmony_ci} // namespace val 4808fd4e5da5Sopenharmony_ci} // namespace spvtools 4809