1// Copyright (c) 2023 Google Inc. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15#include "spirv-tools/optimizer.hpp" 16#include "test/opt/pass_fixture.h" 17#include "test/opt/pass_utils.h" 18 19namespace spvtools { 20namespace opt { 21namespace { 22 23using InterlockInvocationPlacementTest = PassTest<::testing::Test>; 24 25TEST_F(InterlockInvocationPlacementTest, CheckUnchangedIfNotFragment) { 26 const std::string kTest = R"( 27 OpCapability Shader 28 OpCapability FragmentShaderSampleInterlockEXT 29 OpExtension "SPV_EXT_fragment_shader_interlock" 30 OpMemoryModel Logical GLSL450 31 OpEntryPoint Vertex %main "main" 32 OpExecutionMode %main SampleInterlockOrderedEXT 33 OpName %main "main" 34 %void = OpTypeVoid 35 %1 = OpTypeFunction %void 36 %main = OpFunction %void None %1 37 %2 = OpLabel 38 OpBeginInvocationInterlockEXT 39 OpBeginInvocationInterlockEXT 40 OpEndInvocationInterlockEXT 41 OpBeginInvocationInterlockEXT 42 OpEndInvocationInterlockEXT 43 OpReturn 44 OpFunctionEnd 45 )"; 46 SetTargetEnv(SPV_ENV_VULKAN_1_3); 47 EXPECT_EQ( 48 Pass::Status::SuccessWithoutChange, 49 std::get<1>(SinglePassRunAndDisassemble<InvocationInterlockPlacementPass>( 50 kTest, /* skip_nop= */ false, /* do_validation= */ false))); 51} 52 53TEST_F(InterlockInvocationPlacementTest, CheckUnchangedWithoutCapability) { 54 const std::string kTest = R"( 55 OpCapability Shader 56 OpExtension "SPV_EXT_fragment_shader_interlock" 57 OpMemoryModel Logical GLSL450 58 OpEntryPoint Fragment %main "main" 59 OpExecutionMode %main OriginUpperLeft 60 OpExecutionMode %main SampleInterlockOrderedEXT 61 OpName %main "main" 62 %void = OpTypeVoid 63 %1 = OpTypeFunction %void 64 %main = OpFunction %void None %1 65 %2 = OpLabel 66 OpBeginInvocationInterlockEXT 67 OpBeginInvocationInterlockEXT 68 OpEndInvocationInterlockEXT 69 OpBeginInvocationInterlockEXT 70 OpEndInvocationInterlockEXT 71 OpReturn 72 OpFunctionEnd 73 )"; 74 SetTargetEnv(SPV_ENV_VULKAN_1_3); 75 EXPECT_EQ( 76 Pass::Status::SuccessWithoutChange, 77 std::get<1>(SinglePassRunAndDisassemble<InvocationInterlockPlacementPass>( 78 kTest, /* skip_nop= */ false, /* do_validation= */ false))); 79} 80 81TEST_F(InterlockInvocationPlacementTest, CheckSingleBasicBlock) { 82 // We're using OpNoLine as a generic standin for any other instruction, to 83 // test that begin and end aren't moved. 84 const std::string kTest = R"( 85 OpCapability Shader 86 OpCapability FragmentShaderSampleInterlockEXT 87 OpExtension "SPV_EXT_fragment_shader_interlock" 88 OpMemoryModel Logical GLSL450 89 OpEntryPoint Fragment %main "main" 90 OpExecutionMode %main OriginUpperLeft 91 OpExecutionMode %main SampleInterlockOrderedEXT 92 OpName %main "main" 93 %void = OpTypeVoid 94 %1 = OpTypeFunction %void 95 %main = OpFunction %void None %1 96; CHECK: OpLabel 97 %2 = OpLabel 98; CHECK-NEXT: OpNoLine 99 OpNoLine 100; CHECK-NEXT: OpBeginInvocationInterlockEXT 101 OpBeginInvocationInterlockEXT 102 OpBeginInvocationInterlockEXT 103 OpEndInvocationInterlockEXT 104 OpBeginInvocationInterlockEXT 105; CHECK-NEXT: OpNoLine 106 OpNoLine 107; CHECK-NEXT: OpEndInvocationInterlockEXT 108 OpEndInvocationInterlockEXT 109; CHECK-NEXT: OpNoLine 110 OpNoLine 111; CHECK-NEXT: OpReturn 112 OpReturn 113 OpFunctionEnd 114 )"; 115 SetTargetEnv(SPV_ENV_VULKAN_1_3); 116 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>( 117 kTest, /* skip_nop= */ false); 118 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); 119} 120 121TEST_F(InterlockInvocationPlacementTest, CheckFunctionCallExtractionBegin) { 122 const std::string kTest = R"( 123 OpCapability Shader 124 OpCapability FragmentShaderSampleInterlockEXT 125 OpExtension "SPV_EXT_fragment_shader_interlock" 126 OpMemoryModel Logical GLSL450 127 OpEntryPoint Fragment %main "main" 128 OpExecutionMode %main OriginUpperLeft 129 OpExecutionMode %main SampleInterlockOrderedEXT 130 OpName %main "main" 131 %void = OpTypeVoid 132 %1 = OpTypeFunction %void 133 %foo = OpFunction %void None %1 134; CHECK: OpLabel 135; CHECK-NOT: OpBeginInvocationInterlockEXT 136 %2 = OpLabel 137 OpBeginInvocationInterlockEXT 138 OpBeginInvocationInterlockEXT 139 OpReturn 140; CHECK: OpFunctionEnd 141 OpFunctionEnd 142 %main = OpFunction %void None %1 143; CHECK: OpLabel 144 %3 = OpLabel 145; CHECK-NEXT: OpBeginInvocationInterlockEXT 146; CHECK-NEXT: OpFunctionCall 147 %4 = OpFunctionCall %void %foo 148; CHECK-NEXT: OpReturn 149 OpReturn 150 OpFunctionEnd 151 )"; 152 SetTargetEnv(SPV_ENV_VULKAN_1_3); 153 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>( 154 kTest, /* skip_nop= */ false); 155 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); 156} 157 158TEST_F(InterlockInvocationPlacementTest, CheckFunctionCallExtractionEnd) { 159 const std::string kTest = R"( 160 OpCapability Shader 161 OpCapability FragmentShaderSampleInterlockEXT 162 OpExtension "SPV_EXT_fragment_shader_interlock" 163 OpMemoryModel Logical GLSL450 164 OpEntryPoint Fragment %main "main" 165 OpExecutionMode %main OriginUpperLeft 166 OpExecutionMode %main SampleInterlockOrderedEXT 167 OpName %main "main" 168 %void = OpTypeVoid 169 %1 = OpTypeFunction %void 170 %foo = OpFunction %void None %1 171; CHECK: OpLabel 172; CHECK-NOT: OpEndInvocationInterlockEXT 173 %2 = OpLabel 174 OpEndInvocationInterlockEXT 175 OpEndInvocationInterlockEXT 176 OpReturn 177; CHECK: OpFunctionEnd 178 OpFunctionEnd 179 %main = OpFunction %void None %1 180; CHECK: OpLabel 181 %3 = OpLabel 182; CHECK-NEXT: OpFunctionCall 183 %4 = OpFunctionCall %void %foo 184; CHECK-NEXT: OpEndInvocationInterlockEXT 185; CHECK-NEXT: OpReturn 186 OpReturn 187 OpFunctionEnd 188 )"; 189 SetTargetEnv(SPV_ENV_VULKAN_1_3); 190 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>( 191 kTest, /* skip_nop= */ false); 192 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); 193} 194 195TEST_F(InterlockInvocationPlacementTest, 196 CheckFunctionCallExtractionRepeatedCall) { 197 const std::string kTest = R"( 198 OpCapability Shader 199 OpCapability FragmentShaderSampleInterlockEXT 200 OpExtension "SPV_EXT_fragment_shader_interlock" 201 OpMemoryModel Logical GLSL450 202 OpEntryPoint Fragment %main "main" 203 OpExecutionMode %main OriginUpperLeft 204 OpExecutionMode %main SampleInterlockOrderedEXT 205 OpName %main "main" 206 %void = OpTypeVoid 207 %1 = OpTypeFunction %void 208 %foo = OpFunction %void None %1 209; CHECK: OpLabel 210; CHECK-NOT: OpBeginInvocationInterlockEXT 211; CHECK-NOT: OpEndInvocationInterlockEXT 212 %2 = OpLabel 213 OpBeginInvocationInterlockEXT 214 OpEndInvocationInterlockEXT 215 OpReturn 216; CHECK: OpFunctionEnd 217 OpFunctionEnd 218 %main = OpFunction %void None %1 219; CHECK: OpLabel 220 %3 = OpLabel 221; CHECK-NEXT: OpBeginInvocationInterlockEXT 222; CHECK-NEXT: OpFunctionCall 223 %4 = OpFunctionCall %void %foo 224; CHECK-NEXT: OpFunctionCall 225 %5 = OpFunctionCall %void %foo 226; CHECK-NEXT: OpEndInvocationInterlockEXT 227; CHECK-NEXT: OpReturn 228 OpReturn 229 OpFunctionEnd 230 )"; 231 SetTargetEnv(SPV_ENV_VULKAN_1_3); 232 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>( 233 kTest, /* skip_nop= */ false); 234 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); 235} 236 237TEST_F(InterlockInvocationPlacementTest, 238 CheckFunctionCallExtractionNestedCall) { 239 const std::string kTest = R"( 240 OpCapability Shader 241 OpCapability FragmentShaderSampleInterlockEXT 242 OpExtension "SPV_EXT_fragment_shader_interlock" 243 OpMemoryModel Logical GLSL450 244 OpEntryPoint Fragment %main "main" 245 OpExecutionMode %main OriginUpperLeft 246 OpExecutionMode %main SampleInterlockOrderedEXT 247 OpName %main "main" 248 %void = OpTypeVoid 249 %1 = OpTypeFunction %void 250 %foo = OpFunction %void None %1 251; CHECK: OpLabel 252; CHECK-NOT: OpBeginInvocationInterlockEXT 253; CHECK-NOT: OpEndInvocationInterlockEXT 254 %2 = OpLabel 255 OpBeginInvocationInterlockEXT 256 OpEndInvocationInterlockEXT 257 OpReturn 258; CHECK: OpFunctionEnd 259 OpFunctionEnd 260 %bar = OpFunction %void None %1 261; CHECK: OpLabel 262; CHECK-NOT: OpBeginInvocationInterlockEXT 263; CHECK-NOT: OpEndInvocationInterlockEXT 264 %3 = OpLabel 265 %4 = OpFunctionCall %void %foo 266 OpReturn 267; CHECK: OpFunctionEnd 268 OpFunctionEnd 269 %main = OpFunction %void None %1 270; CHECK: OpLabel 271 %5 = OpLabel 272; CHECK-NEXT: OpBeginInvocationInterlockEXT 273; CHECK-NEXT: OpFunctionCall 274 %6 = OpFunctionCall %void %bar 275; CHECK-NEXT: OpEndInvocationInterlockEXT 276; CHECK-NEXT: OpReturn 277 OpReturn 278 OpFunctionEnd 279 )"; 280 SetTargetEnv(SPV_ENV_VULKAN_1_3); 281 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>( 282 kTest, /* skip_nop= */ false); 283 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); 284} 285 286TEST_F(InterlockInvocationPlacementTest, CheckLoopExtraction) { 287 // Tests that any begin or end instructions in a loop are moved outside of the 288 // loop. 289 const std::string kTest = R"( 290 OpCapability Shader 291 OpCapability FragmentShaderSampleInterlockEXT 292 OpExtension "SPV_EXT_fragment_shader_interlock" 293 OpMemoryModel Logical GLSL450 294 OpEntryPoint Fragment %main "main" 295 OpExecutionMode %main OriginUpperLeft 296 OpExecutionMode %main SampleInterlockOrderedEXT 297 %void = OpTypeVoid 298 %bool = OpTypeBool 299 %true = OpConstantTrue %bool 300 %1 = OpTypeFunction %void 301 %main = OpFunction %void None %1 302 303 %2 = OpLabel 304; CHECK: OpBeginInvocationInterlockEXT 305; CHECK-NOT: OpBeginInvocationInterlockEXT 306; CHECK-NOT: OpEndInvocationInterlockEXT 307 OpBranch %3 308 309 %3 = OpLabel 310 OpLoopMerge %3 %4 None 311; CHECK: OpBranchConditional 312; CHECK-NOT: OpBeginInvocationInterlockEXT 313; CHECK-NOT: OpEndInvocationInterlockEXT 314 OpBranchConditional %true %4 %5 315 316 %4 = OpLabel 317 OpBeginInvocationInterlockEXT 318 OpEndInvocationInterlockEXT 319; CHECK: OpBranch 320 OpBranch %3 321 322; CHECK-NEXT: OpLabel 323 %5 = OpLabel 324; CHECK-NEXT: OpEndInvocationInterlockEXT 325; CHECK-NOT: OpEndInvocationInterlockEXT 326 OpEndInvocationInterlockEXT 327 OpReturn 328 OpFunctionEnd 329 )"; 330 SetTargetEnv(SPV_ENV_VULKAN_1_3); 331 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>( 332 kTest, /* skip_nop= */ false); 333 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); 334} 335 336TEST_F(InterlockInvocationPlacementTest, CheckAddBeginToElse) { 337 // Test that if there is a begin in a single branch of a conditional, begin 338 // will be added to the other branch. 339 const std::string kTest = R"( 340 OpCapability Shader 341 OpCapability FragmentShaderSampleInterlockEXT 342 OpExtension "SPV_EXT_fragment_shader_interlock" 343 OpMemoryModel Logical GLSL450 344 OpEntryPoint Fragment %main "main" 345 OpExecutionMode %main OriginUpperLeft 346 OpExecutionMode %main SampleInterlockOrderedEXT 347 OpName %main "main" 348 %void = OpTypeVoid 349 %bool = OpTypeBool 350 %true = OpConstantTrue %bool 351 %1 = OpTypeFunction %void 352 %main = OpFunction %void None %1 353 354 %2 = OpLabel 355; CHECK-NOT: OpBeginInvocationInterlockEXT 356 OpSelectionMerge %5 None 357; CHECK: OpBranchConditional 358 OpBranchConditional %true %3 %4 359 360; CHECK-NEXT: OpLabel 361 %3 = OpLabel 362; CHECK-NEXT: OpBeginInvocationInterlockEXT 363 OpBeginInvocationInterlockEXT 364 OpEndInvocationInterlockEXT 365; CHECK-NEXT: OpBranch 366 OpBranch %5 367 368 %4 = OpLabel 369; CHECK: OpBeginInvocationInterlockEXT 370; CHECK-NEXT: OpBranch 371 OpBranch %5 372 373; CHECK-NEXT: OpLabel 374 %5 = OpLabel 375 OpBeginInvocationInterlockEXT 376; CHECK-NEXT: OpEndInvocationInterlockEXT 377 OpEndInvocationInterlockEXT 378 OpReturn 379 OpFunctionEnd 380 )"; 381 SetTargetEnv(SPV_ENV_VULKAN_1_3); 382 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>( 383 kTest, /* skip_nop= */ false); 384 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); 385} 386 387TEST_F(InterlockInvocationPlacementTest, CheckAddEndToElse) { 388 const std::string kTest = R"( 389 OpCapability Shader 390 OpCapability FragmentShaderSampleInterlockEXT 391 OpExtension "SPV_EXT_fragment_shader_interlock" 392 OpMemoryModel Logical GLSL450 393 OpEntryPoint Fragment %main "main" 394 OpExecutionMode %main OriginUpperLeft 395 OpExecutionMode %main SampleInterlockOrderedEXT 396 OpName %main "main" 397 %void = OpTypeVoid 398 %bool = OpTypeBool 399 %true = OpConstantTrue %bool 400 %1 = OpTypeFunction %void 401 %main = OpFunction %void None %1 402 403 %2 = OpLabel 404; CHECK: OpBeginInvocationInterlockEXT 405 OpBeginInvocationInterlockEXT 406; CHECK-NOT: OpEndInvocationInterlockEXT 407 OpEndInvocationInterlockEXT 408 OpSelectionMerge %5 None 409; CHECK: OpBranchConditional 410 OpBranchConditional %true %3 %4 411 412; CHECK-NEXT: OpLabel 413 %3 = OpLabel 414 OpBeginInvocationInterlockEXT 415; CHECK-NEXT: OpEndInvocationInterlockEXT 416 OpEndInvocationInterlockEXT 417; CHECK-NEXT: OpBranch 418 OpBranch %5 419 420 %4 = OpLabel 421; CHECK: OpEndInvocationInterlockEXT 422; CHECK-NEXT: OpBranch 423 OpBranch %5 424 425; CHECK-NEXT: OpLabel 426 %5 = OpLabel 427; CHECK-NOT: OpEndInvocationInterlockEXT 428 OpReturn 429 OpFunctionEnd 430 )"; 431 SetTargetEnv(SPV_ENV_VULKAN_1_3); 432 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>( 433 kTest, /* skip_nop= */ false); 434 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); 435} 436 437TEST_F(InterlockInvocationPlacementTest, CheckSplitIfWithoutElseBegin) { 438 // Test that if there is a begin in the then branch of a conditional, and no 439 // else branch, an else branch with a begin will created. 440 const std::string kTest = R"( 441 OpCapability Shader 442 OpCapability FragmentShaderSampleInterlockEXT 443 OpExtension "SPV_EXT_fragment_shader_interlock" 444 OpMemoryModel Logical GLSL450 445 OpEntryPoint Fragment %main "main" 446 OpExecutionMode %main OriginUpperLeft 447 OpExecutionMode %main SampleInterlockOrderedEXT 448 OpName %main "main" 449 %void = OpTypeVoid 450 %bool = OpTypeBool 451 %true = OpConstantTrue %bool 452 %1 = OpTypeFunction %void 453 %main = OpFunction %void None %1 454 455 %2 = OpLabel 456; CHECK-NOT: OpBeginInvocationInterlockEXT 457 OpSelectionMerge %5 None 458; CHECK: OpBranchConditional 459 OpBranchConditional %true %3 %5 460 461; CHECK-NEXT: OpLabel 462; CHECK-NEXT: OpBeginInvocationInterlockEXT 463; CHECK-NEXT: OpBranch 464 465; CHECK-NEXT: OpLabel 466 %3 = OpLabel 467; CHECK-NEXT: OpBeginInvocationInterlockEXT 468; CHECK-NOT: OpEndInvocationInterlockEXT 469 OpBeginInvocationInterlockEXT 470 OpEndInvocationInterlockEXT 471 OpBranch %5 472 473; CHECK: OpLabel 474 %5 = OpLabel 475; CHECK-NOT: OpBeginInvocationInterlockEXT 476 OpBeginInvocationInterlockEXT 477; CHECK-NEXT: OpEndInvocationInterlockEXT 478 OpEndInvocationInterlockEXT 479 OpReturn 480 OpFunctionEnd 481 )"; 482 SetTargetEnv(SPV_ENV_VULKAN_1_3); 483 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>( 484 kTest, /* skip_nop= */ false); 485 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); 486} 487 488TEST_F(InterlockInvocationPlacementTest, CheckSplitIfWithoutElseEnd) { 489 const std::string kTest = R"( 490 OpCapability Shader 491 OpCapability FragmentShaderSampleInterlockEXT 492 OpExtension "SPV_EXT_fragment_shader_interlock" 493 OpMemoryModel Logical GLSL450 494 OpEntryPoint Fragment %main "main" 495 OpExecutionMode %main OriginUpperLeft 496 OpExecutionMode %main SampleInterlockOrderedEXT 497 OpName %main "main" 498 %void = OpTypeVoid 499 %bool = OpTypeBool 500 %true = OpConstantTrue %bool 501 %1 = OpTypeFunction %void 502 %main = OpFunction %void None %1 503 504 %2 = OpLabel 505 506; CHECK: OpBeginInvocationInterlockEXT 507 OpBeginInvocationInterlockEXT 508; CHECK-NOT: OpEndInvocationInterlockEXT 509 OpEndInvocationInterlockEXT 510; CHECK-NEXT: OpSelectionMerge [[merge:%\d+]] 511 OpSelectionMerge %5 None 512; CHECK-NEXT: OpBranchConditional %true [[then:%\d+]] [[else:%\d+]] 513 OpBranchConditional %true %3 %5 514 515; CHECK-NEXT: [[else]] = OpLabel 516; CHECK-NEXT: OpEndInvocationInterlockEXT 517; CHECK-NEXT: OpBranch [[merge]] 518 519; CHECK-NEXT: [[then]] = OpLabel 520 %3 = OpLabel 521; CHECK-NEXT: OpEndInvocationInterlockEXT 522 OpBeginInvocationInterlockEXT 523 OpEndInvocationInterlockEXT 524; CHECK-NEXT: OpBranch [[merge]] 525 OpBranch %5 526 527; CHECK-NEXT: [[merge]] = OpLabel 528 %5 = OpLabel 529; CHECK-NEXT: OpReturn 530 OpReturn 531 OpFunctionEnd 532 )"; 533 SetTargetEnv(SPV_ENV_VULKAN_1_3); 534 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>( 535 kTest, /* skip_nop= */ false); 536 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); 537} 538 539TEST_F(InterlockInvocationPlacementTest, CheckSplitSwitch) { 540 // Test that if there is a begin or end in a single branch of a switch, begin 541 // or end will be added to all the other branches. 542 const std::string kTest = R"( 543 OpCapability Shader 544 OpCapability FragmentShaderSampleInterlockEXT 545 OpExtension "SPV_EXT_fragment_shader_interlock" 546 OpMemoryModel Logical GLSL450 547 OpEntryPoint Fragment %main "main" 548 OpExecutionMode %main OriginUpperLeft 549 OpExecutionMode %main SampleInterlockOrderedEXT 550 OpName %main "main" 551 %void = OpTypeVoid 552 %uint = OpTypeInt 32 0 553 %uint_1 = OpConstant %uint 1 554 %1 = OpTypeFunction %void 555 %main = OpFunction %void None %1 556 557; CHECK: OpLabel 558 %2 = OpLabel 559; CHECK-NEXT: OpSelectionMerge [[merge:%\d+]] 560 OpSelectionMerge %8 None 561; CHECK-NEXT: OpSwitch %uint_1 [[default:%\d+]] 0 [[case_0:%\d+]] 1 [[case_1:%\d+]] 2 [[case_2:%\d+]] 562 OpSwitch %uint_1 %8 0 %4 1 %5 2 %8 563 564; CHECK-NEXT: [[case_2]] = OpLabel 565; CHECK-NEXT: OpBeginInvocationInterlockEXT 566; CHECK-NEXT: OpBranch [[merge]] 567 568; CHECK-NEXT: [[default]] = OpLabel 569; CHECK-NEXT: OpBeginInvocationInterlockEXT 570; CHECK-NEXT: OpBranch [[merge]] 571 572; CHECK-NEXT: [[case_0]] = OpLabel 573 %4 = OpLabel 574; CHECK-NEXT: OpBeginInvocationInterlockEXT 575; CHECK-NOT: OpEndInvocationInterlockEXT 576 OpBeginInvocationInterlockEXT 577 OpEndInvocationInterlockEXT 578; CHECK-NEXT: OpNoLine 579 OpNoLine 580; CHECK-NEXT: OpBranch [[merge]] 581 OpBranch %8 582 583; CHECK-NEXT: [[case_1]] = OpLabel 584 %5 = OpLabel 585; CHECK-NEXT: OpBeginInvocationInterlockEXT 586; CHECK-NOT: OpEndInvocationInterlockEXT 587 OpBeginInvocationInterlockEXT 588 OpEndInvocationInterlockEXT 589; CHECK-NEXT: OpNoLine 590 OpNoLine 591; CHECK-NEXT: OpNoLine 592 OpNoLine 593; CHECK-NEXT: OpBranch [[merge]] 594 OpBranch %8 595 596; CHECK-NEXT: [[merge]] = OpLabel 597 %8 = OpLabel 598; CHECK-NOT: OpBeginInvocationInterlockEXT 599 OpBeginInvocationInterlockEXT 600; CHECK-NEXT: OpEndInvocationInterlockEXT 601 OpEndInvocationInterlockEXT 602 OpReturn 603 OpFunctionEnd 604 )"; 605 SetTargetEnv(SPV_ENV_VULKAN_1_3); 606 const auto result = SinglePassRunAndMatch<InvocationInterlockPlacementPass>( 607 kTest, /* skip_nop= */ false); 608 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithChange); 609} 610 611} // namespace 612} // namespace opt 613} // namespace spvtools 614