1 // Copyright (c) 2017 Valve Corporation 2 // Copyright (c) 2017 LunarG Inc. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 #include <string> 17 18 #include "test/opt/pass_fixture.h" 19 #include "test/opt/pass_utils.h" 20 21 namespace spvtools { 22 namespace opt { 23 namespace { 24 25 using DeadBranchElimTest = PassTest<::testing::Test>; 26 27 TEST_F(DeadBranchElimTest, IfThenElseTrue) { 28 // #version 140 29 // 30 // in vec4 BaseColor; 31 // 32 // void main() 33 // { 34 // vec4 v; 35 // if (true) 36 // v = vec4(0.0,0.0,0.0,0.0); 37 // else 38 // v = vec4(1.0,1.0,1.0,1.0); 39 // gl_FragColor = v; 40 // } 41 42 const std::string predefs = 43 R"(OpCapability Shader 44 %1 = OpExtInstImport "GLSL.std.450" 45 OpMemoryModel Logical GLSL450 46 OpEntryPoint Fragment %main "main" %gl_FragColor %BaseColor 47 OpExecutionMode %main OriginUpperLeft 48 OpSource GLSL 140 49 OpName %main "main" 50 OpName %v "v" 51 OpName %gl_FragColor "gl_FragColor" 52 OpName %BaseColor "BaseColor" 53 %void = OpTypeVoid 54 %7 = OpTypeFunction %void 55 %bool = OpTypeBool 56 %true = OpConstantTrue %bool 57 %float = OpTypeFloat 32 58 %v4float = OpTypeVector %float 4 59 %_ptr_Function_v4float = OpTypePointer Function %v4float 60 %float_0 = OpConstant %float 0 61 %14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 62 %float_1 = OpConstant %float 1 63 %16 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 64 %_ptr_Output_v4float = OpTypePointer Output %v4float 65 %gl_FragColor = OpVariable %_ptr_Output_v4float Output 66 %_ptr_Input_v4float = OpTypePointer Input %v4float 67 %BaseColor = OpVariable %_ptr_Input_v4float Input 68 )"; 69 70 const std::string before = 71 R"(%main = OpFunction %void None %7 72 %19 = OpLabel 73 %v = OpVariable %_ptr_Function_v4float Function 74 OpSelectionMerge %20 None 75 OpBranchConditional %true %21 %22 76 %21 = OpLabel 77 OpStore %v %14 78 OpBranch %20 79 %22 = OpLabel 80 OpStore %v %16 81 OpBranch %20 82 %20 = OpLabel 83 %23 = OpLoad %v4float %v 84 OpStore %gl_FragColor %23 85 OpReturn 86 OpFunctionEnd 87 )"; 88 89 const std::string after = 90 R"(%main = OpFunction %void None %7 91 %19 = OpLabel 92 %v = OpVariable %_ptr_Function_v4float Function 93 OpBranch %21 94 %21 = OpLabel 95 OpStore %v %14 96 OpBranch %20 97 %20 = OpLabel 98 %23 = OpLoad %v4float %v 99 OpStore %gl_FragColor %23 100 OpReturn 101 OpFunctionEnd 102 )"; 103 104 SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after, 105 true, true); 106 } 107 108 TEST_F(DeadBranchElimTest, IfThenElseFalse) { 109 // #version 140 110 // 111 // in vec4 BaseColor; 112 // 113 // void main() 114 // { 115 // vec4 v; 116 // if (false) 117 // v = vec4(0.0,0.0,0.0,0.0); 118 // else 119 // v = vec4(1.0,1.0,1.0,1.0); 120 // gl_FragColor = v; 121 // } 122 123 const std::string predefs = 124 R"(OpCapability Shader 125 %1 = OpExtInstImport "GLSL.std.450" 126 OpMemoryModel Logical GLSL450 127 OpEntryPoint Fragment %main "main" %gl_FragColor %BaseColor 128 OpExecutionMode %main OriginUpperLeft 129 OpSource GLSL 140 130 OpName %main "main" 131 OpName %v "v" 132 OpName %gl_FragColor "gl_FragColor" 133 OpName %BaseColor "BaseColor" 134 %void = OpTypeVoid 135 %7 = OpTypeFunction %void 136 %bool = OpTypeBool 137 %false = OpConstantFalse %bool 138 %float = OpTypeFloat 32 139 %v4float = OpTypeVector %float 4 140 %_ptr_Function_v4float = OpTypePointer Function %v4float 141 %float_0 = OpConstant %float 0 142 %14 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 143 %float_1 = OpConstant %float 1 144 %16 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 145 %_ptr_Output_v4float = OpTypePointer Output %v4float 146 %gl_FragColor = OpVariable %_ptr_Output_v4float Output 147 %_ptr_Input_v4float = OpTypePointer Input %v4float 148 %BaseColor = OpVariable %_ptr_Input_v4float Input 149 )"; 150 151 const std::string before = 152 R"(%main = OpFunction %void None %7 153 %19 = OpLabel 154 %v = OpVariable %_ptr_Function_v4float Function 155 OpSelectionMerge %20 None 156 OpBranchConditional %false %21 %22 157 %21 = OpLabel 158 OpStore %v %14 159 OpBranch %20 160 %22 = OpLabel 161 OpStore %v %16 162 OpBranch %20 163 %20 = OpLabel 164 %23 = OpLoad %v4float %v 165 OpStore %gl_FragColor %23 166 OpReturn 167 OpFunctionEnd 168 )"; 169 170 const std::string after = 171 R"(%main = OpFunction %void None %7 172 %19 = OpLabel 173 %v = OpVariable %_ptr_Function_v4float Function 174 OpBranch %22 175 %22 = OpLabel 176 OpStore %v %16 177 OpBranch %20 178 %20 = OpLabel 179 %23 = OpLoad %v4float %v 180 OpStore %gl_FragColor %23 181 OpReturn 182 OpFunctionEnd 183 )"; 184 185 SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after, 186 true, true); 187 } 188 189 TEST_F(DeadBranchElimTest, IfThenTrue) { 190 // #version 140 191 // 192 // in vec4 BaseColor; 193 // 194 // void main() 195 // { 196 // vec4 v = BaseColor; 197 // if (true) 198 // v = v * vec4(0.5,0.5,0.5,0.5); 199 // gl_FragColor = v; 200 // } 201 202 const std::string predefs = 203 R"(OpCapability Shader 204 %1 = OpExtInstImport "GLSL.std.450" 205 OpMemoryModel Logical GLSL450 206 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor 207 OpExecutionMode %main OriginUpperLeft 208 OpSource GLSL 140 209 OpName %main "main" 210 OpName %v "v" 211 OpName %BaseColor "BaseColor" 212 OpName %gl_FragColor "gl_FragColor" 213 %void = OpTypeVoid 214 %7 = OpTypeFunction %void 215 %float = OpTypeFloat 32 216 %v4float = OpTypeVector %float 4 217 %_ptr_Function_v4float = OpTypePointer Function %v4float 218 %_ptr_Input_v4float = OpTypePointer Input %v4float 219 %BaseColor = OpVariable %_ptr_Input_v4float Input 220 %bool = OpTypeBool 221 %true = OpConstantTrue %bool 222 %float_0_5 = OpConstant %float 0.5 223 %15 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5 224 %_ptr_Output_v4float = OpTypePointer Output %v4float 225 %gl_FragColor = OpVariable %_ptr_Output_v4float Output 226 )"; 227 228 const std::string before = 229 R"(%main = OpFunction %void None %7 230 %17 = OpLabel 231 %v = OpVariable %_ptr_Function_v4float Function 232 %18 = OpLoad %v4float %BaseColor 233 OpStore %v %18 234 OpSelectionMerge %19 None 235 OpBranchConditional %true %20 %19 236 %20 = OpLabel 237 %21 = OpLoad %v4float %v 238 %22 = OpFMul %v4float %21 %15 239 OpStore %v %22 240 OpBranch %19 241 %19 = OpLabel 242 %23 = OpLoad %v4float %v 243 OpStore %gl_FragColor %23 244 OpReturn 245 OpFunctionEnd 246 )"; 247 248 const std::string after = 249 R"(%main = OpFunction %void None %7 250 %17 = OpLabel 251 %v = OpVariable %_ptr_Function_v4float Function 252 %18 = OpLoad %v4float %BaseColor 253 OpStore %v %18 254 OpBranch %20 255 %20 = OpLabel 256 %21 = OpLoad %v4float %v 257 %22 = OpFMul %v4float %21 %15 258 OpStore %v %22 259 OpBranch %19 260 %19 = OpLabel 261 %23 = OpLoad %v4float %v 262 OpStore %gl_FragColor %23 263 OpReturn 264 OpFunctionEnd 265 )"; 266 267 SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after, 268 true, true); 269 } 270 271 TEST_F(DeadBranchElimTest, IfThenFalse) { 272 // #version 140 273 // 274 // in vec4 BaseColor; 275 // 276 // void main() 277 // { 278 // vec4 v = BaseColor; 279 // if (false) 280 // v = v * vec4(0.5,0.5,0.5,0.5); 281 // gl_FragColor = v; 282 // } 283 284 const std::string predefs = 285 R"(OpCapability Shader 286 %1 = OpExtInstImport "GLSL.std.450" 287 OpMemoryModel Logical GLSL450 288 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor 289 OpExecutionMode %main OriginUpperLeft 290 OpSource GLSL 140 291 OpName %main "main" 292 OpName %v "v" 293 OpName %BaseColor "BaseColor" 294 OpName %gl_FragColor "gl_FragColor" 295 %void = OpTypeVoid 296 %7 = OpTypeFunction %void 297 %float = OpTypeFloat 32 298 %v4float = OpTypeVector %float 4 299 %_ptr_Function_v4float = OpTypePointer Function %v4float 300 %_ptr_Input_v4float = OpTypePointer Input %v4float 301 %BaseColor = OpVariable %_ptr_Input_v4float Input 302 %bool = OpTypeBool 303 %false = OpConstantFalse %bool 304 %float_0_5 = OpConstant %float 0.5 305 %15 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5 306 %_ptr_Output_v4float = OpTypePointer Output %v4float 307 %gl_FragColor = OpVariable %_ptr_Output_v4float Output 308 )"; 309 310 const std::string before = 311 R"(%main = OpFunction %void None %7 312 %17 = OpLabel 313 %v = OpVariable %_ptr_Function_v4float Function 314 %18 = OpLoad %v4float %BaseColor 315 OpStore %v %18 316 OpSelectionMerge %19 None 317 OpBranchConditional %false %20 %19 318 %20 = OpLabel 319 %21 = OpLoad %v4float %v 320 %22 = OpFMul %v4float %21 %15 321 OpStore %v %22 322 OpBranch %19 323 %19 = OpLabel 324 %23 = OpLoad %v4float %v 325 OpStore %gl_FragColor %23 326 OpReturn 327 OpFunctionEnd 328 )"; 329 330 const std::string after = 331 R"(%main = OpFunction %void None %7 332 %17 = OpLabel 333 %v = OpVariable %_ptr_Function_v4float Function 334 %18 = OpLoad %v4float %BaseColor 335 OpStore %v %18 336 OpBranch %19 337 %19 = OpLabel 338 %23 = OpLoad %v4float %v 339 OpStore %gl_FragColor %23 340 OpReturn 341 OpFunctionEnd 342 )"; 343 344 SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after, 345 true, true); 346 } 347 348 TEST_F(DeadBranchElimTest, IfThenElsePhiTrue) { 349 // Test handling of phi in merge block after dead branch elimination. 350 // Note: The SPIR-V has had store/load elimination and phi insertion 351 // 352 // #version 140 353 // 354 // void main() 355 // { 356 // vec4 v; 357 // if (true) 358 // v = vec4(0.0,0.0,0.0,0.0); 359 // else 360 // v = vec4(1.0,1.0,1.0,1.0); 361 // gl_FragColor = v; 362 // } 363 364 const std::string predefs = 365 R"(OpCapability Shader 366 %1 = OpExtInstImport "GLSL.std.450" 367 OpMemoryModel Logical GLSL450 368 OpEntryPoint Fragment %main "main" %gl_FragColor 369 OpExecutionMode %main OriginUpperLeft 370 OpSource GLSL 140 371 OpName %main "main" 372 OpName %gl_FragColor "gl_FragColor" 373 %void = OpTypeVoid 374 %5 = OpTypeFunction %void 375 %bool = OpTypeBool 376 %true = OpConstantTrue %bool 377 %float = OpTypeFloat 32 378 %v4float = OpTypeVector %float 4 379 %_ptr_Function_v4float = OpTypePointer Function %v4float 380 %float_0 = OpConstant %float 0 381 %12 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 382 %float_1 = OpConstant %float 1 383 %14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 384 %_ptr_Output_v4float = OpTypePointer Output %v4float 385 %gl_FragColor = OpVariable %_ptr_Output_v4float Output 386 %_ptr_Input_v4float = OpTypePointer Input %v4float 387 )"; 388 389 const std::string before = 390 R"(%main = OpFunction %void None %5 391 %17 = OpLabel 392 OpSelectionMerge %18 None 393 OpBranchConditional %true %19 %20 394 %19 = OpLabel 395 OpBranch %18 396 %20 = OpLabel 397 OpBranch %18 398 %18 = OpLabel 399 %21 = OpPhi %v4float %12 %19 %14 %20 400 OpStore %gl_FragColor %21 401 OpReturn 402 OpFunctionEnd 403 )"; 404 405 const std::string after = 406 R"(%main = OpFunction %void None %5 407 %17 = OpLabel 408 OpBranch %19 409 %19 = OpLabel 410 OpBranch %18 411 %18 = OpLabel 412 OpStore %gl_FragColor %12 413 OpReturn 414 OpFunctionEnd 415 )"; 416 417 SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after, 418 true, true); 419 } 420 421 TEST_F(DeadBranchElimTest, IfThenElsePhiFalse) { 422 // Test handling of phi in merge block after dead branch elimination. 423 // Note: The SPIR-V has had store/load elimination and phi insertion 424 // 425 // #version 140 426 // 427 // void main() 428 // { 429 // vec4 v; 430 // if (true) 431 // v = vec4(0.0,0.0,0.0,0.0); 432 // else 433 // v = vec4(1.0,1.0,1.0,1.0); 434 // gl_FragColor = v; 435 // } 436 437 const std::string predefs = 438 R"(OpCapability Shader 439 %1 = OpExtInstImport "GLSL.std.450" 440 OpMemoryModel Logical GLSL450 441 OpEntryPoint Fragment %main "main" %gl_FragColor 442 OpExecutionMode %main OriginUpperLeft 443 OpSource GLSL 140 444 OpName %main "main" 445 OpName %gl_FragColor "gl_FragColor" 446 %void = OpTypeVoid 447 %5 = OpTypeFunction %void 448 %bool = OpTypeBool 449 %false = OpConstantFalse %bool 450 %float = OpTypeFloat 32 451 %v4float = OpTypeVector %float 4 452 %_ptr_Function_v4float = OpTypePointer Function %v4float 453 %float_0 = OpConstant %float 0 454 %12 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 455 %float_1 = OpConstant %float 1 456 %14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 457 %_ptr_Output_v4float = OpTypePointer Output %v4float 458 %gl_FragColor = OpVariable %_ptr_Output_v4float Output 459 %_ptr_Input_v4float = OpTypePointer Input %v4float 460 )"; 461 462 const std::string before = 463 R"(%main = OpFunction %void None %5 464 %17 = OpLabel 465 OpSelectionMerge %18 None 466 OpBranchConditional %false %19 %20 467 %19 = OpLabel 468 OpBranch %18 469 %20 = OpLabel 470 OpBranch %18 471 %18 = OpLabel 472 %21 = OpPhi %v4float %12 %19 %14 %20 473 OpStore %gl_FragColor %21 474 OpReturn 475 OpFunctionEnd 476 )"; 477 478 const std::string after = 479 R"(%main = OpFunction %void None %5 480 %17 = OpLabel 481 OpBranch %20 482 %20 = OpLabel 483 OpBranch %18 484 %18 = OpLabel 485 OpStore %gl_FragColor %14 486 OpReturn 487 OpFunctionEnd 488 )"; 489 490 SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after, 491 true, true); 492 } 493 494 TEST_F(DeadBranchElimTest, CompoundIfThenElseFalse) { 495 // #version 140 496 // 497 // layout(std140) uniform U_t 498 // { 499 // bool g_B ; 500 // } ; 501 // 502 // void main() 503 // { 504 // vec4 v; 505 // if (false) { 506 // if (g_B) 507 // v = vec4(0.0,0.0,0.0,0.0); 508 // else 509 // v = vec4(1.0,1.0,1.0,1.0); 510 // } else { 511 // if (g_B) 512 // v = vec4(1.0,1.0,1.0,1.0); 513 // else 514 // v = vec4(0.0,0.0,0.0,0.0); 515 // } 516 // gl_FragColor = v; 517 // } 518 519 const std::string predefs = 520 R"(OpCapability Shader 521 %1 = OpExtInstImport "GLSL.std.450" 522 OpMemoryModel Logical GLSL450 523 OpEntryPoint Fragment %main "main" %gl_FragColor 524 OpExecutionMode %main OriginUpperLeft 525 OpSource GLSL 140 526 OpName %main "main" 527 OpName %U_t "U_t" 528 OpMemberName %U_t 0 "g_B" 529 OpName %_ "" 530 OpName %v "v" 531 OpName %gl_FragColor "gl_FragColor" 532 OpMemberDecorate %U_t 0 Offset 0 533 OpDecorate %U_t Block 534 OpDecorate %_ DescriptorSet 0 535 %void = OpTypeVoid 536 %8 = OpTypeFunction %void 537 %bool = OpTypeBool 538 %false = OpConstantFalse %bool 539 %uint = OpTypeInt 32 0 540 %U_t = OpTypeStruct %uint 541 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t 542 %_ = OpVariable %_ptr_Uniform_U_t Uniform 543 %int = OpTypeInt 32 1 544 %int_0 = OpConstant %int 0 545 %_ptr_Uniform_uint = OpTypePointer Uniform %uint 546 %uint_0 = OpConstant %uint 0 547 %float = OpTypeFloat 32 548 %v4float = OpTypeVector %float 4 549 %_ptr_Function_v4float = OpTypePointer Function %v4float 550 %float_0 = OpConstant %float 0 551 %21 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 552 %float_1 = OpConstant %float 1 553 %23 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 554 %_ptr_Output_v4float = OpTypePointer Output %v4float 555 %gl_FragColor = OpVariable %_ptr_Output_v4float Output 556 )"; 557 558 const std::string before = 559 R"(%main = OpFunction %void None %8 560 %25 = OpLabel 561 %v = OpVariable %_ptr_Function_v4float Function 562 OpSelectionMerge %26 None 563 OpBranchConditional %false %27 %28 564 %27 = OpLabel 565 %29 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 566 %30 = OpLoad %uint %29 567 %31 = OpINotEqual %bool %30 %uint_0 568 OpSelectionMerge %32 None 569 OpBranchConditional %31 %33 %34 570 %33 = OpLabel 571 OpStore %v %21 572 OpBranch %32 573 %34 = OpLabel 574 OpStore %v %23 575 OpBranch %32 576 %32 = OpLabel 577 OpBranch %26 578 %28 = OpLabel 579 %35 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 580 %36 = OpLoad %uint %35 581 %37 = OpINotEqual %bool %36 %uint_0 582 OpSelectionMerge %38 None 583 OpBranchConditional %37 %39 %40 584 %39 = OpLabel 585 OpStore %v %23 586 OpBranch %38 587 %40 = OpLabel 588 OpStore %v %21 589 OpBranch %38 590 %38 = OpLabel 591 OpBranch %26 592 %26 = OpLabel 593 %41 = OpLoad %v4float %v 594 OpStore %gl_FragColor %41 595 OpReturn 596 OpFunctionEnd 597 )"; 598 599 const std::string after = 600 R"(%main = OpFunction %void None %8 601 %25 = OpLabel 602 %v = OpVariable %_ptr_Function_v4float Function 603 OpBranch %28 604 %28 = OpLabel 605 %35 = OpAccessChain %_ptr_Uniform_uint %_ %int_0 606 %36 = OpLoad %uint %35 607 %37 = OpINotEqual %bool %36 %uint_0 608 OpSelectionMerge %38 None 609 OpBranchConditional %37 %39 %40 610 %40 = OpLabel 611 OpStore %v %21 612 OpBranch %38 613 %39 = OpLabel 614 OpStore %v %23 615 OpBranch %38 616 %38 = OpLabel 617 OpBranch %26 618 %26 = OpLabel 619 %41 = OpLoad %v4float %v 620 OpStore %gl_FragColor %41 621 OpReturn 622 OpFunctionEnd 623 )"; 624 625 SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after, 626 true, true); 627 } 628 629 TEST_F(DeadBranchElimTest, PreventOrphanMerge) { 630 const std::string predefs = 631 R"(OpCapability Shader 632 %1 = OpExtInstImport "GLSL.std.450" 633 OpMemoryModel Logical GLSL450 634 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor 635 OpExecutionMode %main OriginUpperLeft 636 OpSource GLSL 140 637 OpName %main "main" 638 OpName %v "v" 639 OpName %BaseColor "BaseColor" 640 OpName %gl_FragColor "gl_FragColor" 641 %void = OpTypeVoid 642 %7 = OpTypeFunction %void 643 %float = OpTypeFloat 32 644 %v4float = OpTypeVector %float 4 645 %_ptr_Function_v4float = OpTypePointer Function %v4float 646 %_ptr_Input_v4float = OpTypePointer Input %v4float 647 %BaseColor = OpVariable %_ptr_Input_v4float Input 648 %bool = OpTypeBool 649 %true = OpConstantTrue %bool 650 %float_0_5 = OpConstant %float 0.5 651 %_ptr_Output_v4float = OpTypePointer Output %v4float 652 %gl_FragColor = OpVariable %_ptr_Output_v4float Output 653 )"; 654 655 const std::string before = 656 R"(%main = OpFunction %void None %7 657 %16 = OpLabel 658 %v = OpVariable %_ptr_Function_v4float Function 659 %17 = OpLoad %v4float %BaseColor 660 OpStore %v %17 661 OpSelectionMerge %18 None 662 OpBranchConditional %true %19 %20 663 %19 = OpLabel 664 OpKill 665 %20 = OpLabel 666 %21 = OpLoad %v4float %v 667 %22 = OpVectorTimesScalar %v4float %21 %float_0_5 668 OpStore %v %22 669 OpBranch %18 670 %18 = OpLabel 671 %23 = OpLoad %v4float %v 672 OpStore %gl_FragColor %23 673 OpReturn 674 OpFunctionEnd 675 )"; 676 677 const std::string after = 678 R"(%main = OpFunction %void None %7 679 %16 = OpLabel 680 %v = OpVariable %_ptr_Function_v4float Function 681 %17 = OpLoad %v4float %BaseColor 682 OpStore %v %17 683 OpBranch %19 684 %19 = OpLabel 685 OpKill 686 OpFunctionEnd 687 )"; 688 689 SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after, 690 true, true); 691 } 692 693 TEST_F(DeadBranchElimTest, HandleOrphanMerge) { 694 const std::string predefs = 695 R"(OpCapability Shader 696 %1 = OpExtInstImport "GLSL.std.450" 697 OpMemoryModel Logical GLSL450 698 OpEntryPoint Fragment %main "main" %gl_FragColor 699 OpExecutionMode %main OriginUpperLeft 700 OpSource GLSL 140 701 OpName %main "main" 702 OpName %foo_ "foo(" 703 OpName %gl_FragColor "gl_FragColor" 704 OpDecorate %gl_FragColor Location 0 705 %void = OpTypeVoid 706 %6 = OpTypeFunction %void 707 %float = OpTypeFloat 32 708 %v4float = OpTypeVector %float 4 709 %9 = OpTypeFunction %v4float 710 %bool = OpTypeBool 711 %true = OpConstantTrue %bool 712 %float_0 = OpConstant %float 0 713 %13 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 714 %float_1 = OpConstant %float 1 715 %15 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 716 %_ptr_Output_v4float = OpTypePointer Output %v4float 717 %gl_FragColor = OpVariable %_ptr_Output_v4float Output 718 %main = OpFunction %void None %6 719 %17 = OpLabel 720 %18 = OpFunctionCall %v4float %foo_ 721 OpStore %gl_FragColor %18 722 OpReturn 723 OpFunctionEnd 724 )"; 725 726 const std::string before = 727 R"(%foo_ = OpFunction %v4float None %9 728 %19 = OpLabel 729 OpSelectionMerge %20 None 730 OpBranchConditional %true %21 %22 731 %21 = OpLabel 732 OpReturnValue %13 733 %22 = OpLabel 734 OpReturnValue %15 735 %20 = OpLabel 736 %23 = OpUndef %v4float 737 OpReturnValue %23 738 OpFunctionEnd 739 )"; 740 741 const std::string after = 742 R"(%foo_ = OpFunction %v4float None %9 743 %19 = OpLabel 744 OpBranch %21 745 %21 = OpLabel 746 OpReturnValue %13 747 OpFunctionEnd 748 )"; 749 750 SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after, 751 true, true); 752 } 753 754 TEST_F(DeadBranchElimTest, KeepContinueTargetWhenKillAfterMerge) { 755 // #version 450 756 // void main() { 757 // bool c; 758 // bool d; 759 // while(c) { 760 // if(d) { 761 // continue; 762 // } 763 // if(false) { 764 // continue; 765 // } 766 // discard; 767 // } 768 // } 769 770 const std::string predefs = 771 R"(OpCapability Shader 772 %1 = OpExtInstImport "GLSL.std.450" 773 OpMemoryModel Logical GLSL450 774 OpEntryPoint Fragment %main "main" 775 OpExecutionMode %main OriginUpperLeft 776 OpSource GLSL 450 777 OpName %main "main" 778 OpName %c "c" 779 OpName %d "d" 780 %void = OpTypeVoid 781 %6 = OpTypeFunction %void 782 %bool = OpTypeBool 783 %_ptr_Function_bool = OpTypePointer Function %bool 784 %false = OpConstantFalse %bool 785 )"; 786 787 const std::string before = 788 R"(%main = OpFunction %void None %6 789 %10 = OpLabel 790 %c = OpVariable %_ptr_Function_bool Function 791 %d = OpVariable %_ptr_Function_bool Function 792 OpBranch %11 793 %11 = OpLabel 794 OpLoopMerge %12 %13 None 795 OpBranch %14 796 %14 = OpLabel 797 %15 = OpLoad %bool %c 798 OpBranchConditional %15 %16 %12 799 %16 = OpLabel 800 %17 = OpLoad %bool %d 801 OpSelectionMerge %18 None 802 OpBranchConditional %17 %19 %18 803 %19 = OpLabel 804 OpBranch %13 805 %18 = OpLabel 806 OpSelectionMerge %20 None 807 OpBranchConditional %false %21 %20 808 %21 = OpLabel 809 OpBranch %13 810 %20 = OpLabel 811 OpKill 812 %13 = OpLabel 813 OpBranch %11 814 %12 = OpLabel 815 OpReturn 816 OpFunctionEnd 817 )"; 818 819 const std::string after = 820 R"(%main = OpFunction %void None %6 821 %10 = OpLabel 822 %c = OpVariable %_ptr_Function_bool Function 823 %d = OpVariable %_ptr_Function_bool Function 824 OpBranch %11 825 %11 = OpLabel 826 OpLoopMerge %12 %13 None 827 OpBranch %14 828 %14 = OpLabel 829 %15 = OpLoad %bool %c 830 OpBranchConditional %15 %16 %12 831 %16 = OpLabel 832 %17 = OpLoad %bool %d 833 OpSelectionMerge %18 None 834 OpBranchConditional %17 %19 %18 835 %19 = OpLabel 836 OpBranch %13 837 %18 = OpLabel 838 OpBranch %20 839 %20 = OpLabel 840 OpKill 841 %13 = OpLabel 842 OpBranch %11 843 %12 = OpLabel 844 OpReturn 845 OpFunctionEnd 846 )"; 847 848 SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after, 849 true, true); 850 } 851 852 TEST_F(DeadBranchElimTest, DecorateDeleted) { 853 // Note: SPIR-V hand-edited to add decoration 854 // #version 140 855 // 856 // in vec4 BaseColor; 857 // 858 // void main() 859 // { 860 // vec4 v = BaseColor; 861 // if (false) 862 // v = v * vec4(0.5,0.5,0.5,0.5); 863 // gl_FragColor = v; 864 // } 865 866 const std::string predefs_before = 867 R"(OpCapability Shader 868 %1 = OpExtInstImport "GLSL.std.450" 869 OpMemoryModel Logical GLSL450 870 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor 871 OpExecutionMode %main OriginUpperLeft 872 OpSource GLSL 140 873 OpName %main "main" 874 OpName %v "v" 875 OpName %BaseColor "BaseColor" 876 OpName %gl_FragColor "gl_FragColor" 877 OpDecorate %22 RelaxedPrecision 878 %void = OpTypeVoid 879 %7 = OpTypeFunction %void 880 %float = OpTypeFloat 32 881 %v4float = OpTypeVector %float 4 882 %_ptr_Function_v4float = OpTypePointer Function %v4float 883 %_ptr_Input_v4float = OpTypePointer Input %v4float 884 %BaseColor = OpVariable %_ptr_Input_v4float Input 885 %bool = OpTypeBool 886 %false = OpConstantFalse %bool 887 %float_0_5 = OpConstant %float 0.5 888 %15 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5 889 %_ptr_Output_v4float = OpTypePointer Output %v4float 890 %gl_FragColor = OpVariable %_ptr_Output_v4float Output 891 )"; 892 893 const std::string predefs_after = 894 R"(OpCapability Shader 895 %1 = OpExtInstImport "GLSL.std.450" 896 OpMemoryModel Logical GLSL450 897 OpEntryPoint Fragment %main "main" %BaseColor %gl_FragColor 898 OpExecutionMode %main OriginUpperLeft 899 OpSource GLSL 140 900 OpName %main "main" 901 OpName %v "v" 902 OpName %BaseColor "BaseColor" 903 OpName %gl_FragColor "gl_FragColor" 904 %void = OpTypeVoid 905 %8 = OpTypeFunction %void 906 %float = OpTypeFloat 32 907 %v4float = OpTypeVector %float 4 908 %_ptr_Function_v4float = OpTypePointer Function %v4float 909 %_ptr_Input_v4float = OpTypePointer Input %v4float 910 %BaseColor = OpVariable %_ptr_Input_v4float Input 911 %bool = OpTypeBool 912 %false = OpConstantFalse %bool 913 %float_0_5 = OpConstant %float 0.5 914 %16 = OpConstantComposite %v4float %float_0_5 %float_0_5 %float_0_5 %float_0_5 915 %_ptr_Output_v4float = OpTypePointer Output %v4float 916 %gl_FragColor = OpVariable %_ptr_Output_v4float Output 917 )"; 918 919 const std::string before = 920 R"(%main = OpFunction %void None %7 921 %17 = OpLabel 922 %v = OpVariable %_ptr_Function_v4float Function 923 %18 = OpLoad %v4float %BaseColor 924 OpStore %v %18 925 OpSelectionMerge %19 None 926 OpBranchConditional %false %20 %19 927 %20 = OpLabel 928 %21 = OpLoad %v4float %v 929 %22 = OpFMul %v4float %21 %15 930 OpStore %v %22 931 OpBranch %19 932 %19 = OpLabel 933 %23 = OpLoad %v4float %v 934 OpStore %gl_FragColor %23 935 OpReturn 936 OpFunctionEnd 937 )"; 938 939 const std::string after = 940 R"(%main = OpFunction %void None %8 941 %18 = OpLabel 942 %v = OpVariable %_ptr_Function_v4float Function 943 %19 = OpLoad %v4float %BaseColor 944 OpStore %v %19 945 OpBranch %20 946 %20 = OpLabel 947 %23 = OpLoad %v4float %v 948 OpStore %gl_FragColor %23 949 OpReturn 950 OpFunctionEnd 951 )"; 952 953 SinglePassRunAndCheck<DeadBranchElimPass>(predefs_before + before, 954 predefs_after + after, true, true); 955 } 956 957 TEST_F(DeadBranchElimTest, LoopInDeadBranch) { 958 // #version 450 959 // 960 // layout(location = 0) in vec4 BaseColor; 961 // layout(location = 0) out vec4 OutColor; 962 // 963 // void main() 964 // { 965 // vec4 v = BaseColor; 966 // if (false) 967 // for (int i=0; i<3; i++) 968 // v = v * 0.5; 969 // OutColor = v; 970 // } 971 972 const std::string predefs = 973 R"(OpCapability Shader 974 %1 = OpExtInstImport "GLSL.std.450" 975 OpMemoryModel Logical GLSL450 976 OpEntryPoint Fragment %main "main" %BaseColor %OutColor 977 OpExecutionMode %main OriginUpperLeft 978 OpSource GLSL 450 979 OpName %main "main" 980 OpName %v "v" 981 OpName %BaseColor "BaseColor" 982 OpName %i "i" 983 OpName %OutColor "OutColor" 984 OpDecorate %BaseColor Location 0 985 OpDecorate %OutColor Location 0 986 %void = OpTypeVoid 987 %8 = OpTypeFunction %void 988 %float = OpTypeFloat 32 989 %v4float = OpTypeVector %float 4 990 %_ptr_Function_v4float = OpTypePointer Function %v4float 991 %_ptr_Input_v4float = OpTypePointer Input %v4float 992 %BaseColor = OpVariable %_ptr_Input_v4float Input 993 %bool = OpTypeBool 994 %false = OpConstantFalse %bool 995 %int = OpTypeInt 32 1 996 %_ptr_Function_int = OpTypePointer Function %int 997 %int_0 = OpConstant %int 0 998 %int_3 = OpConstant %int 3 999 %float_0_5 = OpConstant %float 0.5 1000 %int_1 = OpConstant %int 1 1001 %_ptr_Output_v4float = OpTypePointer Output %v4float 1002 %OutColor = OpVariable %_ptr_Output_v4float Output 1003 )"; 1004 1005 const std::string before = 1006 R"(%main = OpFunction %void None %8 1007 %22 = OpLabel 1008 %v = OpVariable %_ptr_Function_v4float Function 1009 %i = OpVariable %_ptr_Function_int Function 1010 %23 = OpLoad %v4float %BaseColor 1011 OpStore %v %23 1012 OpSelectionMerge %24 None 1013 OpBranchConditional %false %25 %24 1014 %25 = OpLabel 1015 OpStore %i %int_0 1016 OpBranch %26 1017 %26 = OpLabel 1018 OpLoopMerge %27 %28 None 1019 OpBranch %29 1020 %29 = OpLabel 1021 %30 = OpLoad %int %i 1022 %31 = OpSLessThan %bool %30 %int_3 1023 OpBranchConditional %31 %32 %27 1024 %32 = OpLabel 1025 %33 = OpLoad %v4float %v 1026 %34 = OpVectorTimesScalar %v4float %33 %float_0_5 1027 OpStore %v %34 1028 OpBranch %28 1029 %28 = OpLabel 1030 %35 = OpLoad %int %i 1031 %36 = OpIAdd %int %35 %int_1 1032 OpStore %i %36 1033 OpBranch %26 1034 %27 = OpLabel 1035 OpBranch %24 1036 %24 = OpLabel 1037 %37 = OpLoad %v4float %v 1038 OpStore %OutColor %37 1039 OpReturn 1040 OpFunctionEnd 1041 )"; 1042 1043 const std::string after = 1044 R"(%main = OpFunction %void None %8 1045 %22 = OpLabel 1046 %v = OpVariable %_ptr_Function_v4float Function 1047 %i = OpVariable %_ptr_Function_int Function 1048 %23 = OpLoad %v4float %BaseColor 1049 OpStore %v %23 1050 OpBranch %24 1051 %24 = OpLabel 1052 %37 = OpLoad %v4float %v 1053 OpStore %OutColor %37 1054 OpReturn 1055 OpFunctionEnd 1056 )"; 1057 1058 SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after, 1059 true, true); 1060 } 1061 1062 TEST_F(DeadBranchElimTest, SwitchLiveCase) { 1063 // #version 450 1064 // 1065 // layout (location=0) in vec4 BaseColor; 1066 // layout (location=0) out vec4 OutColor; 1067 // 1068 // void main() 1069 // { 1070 // switch (1) { 1071 // case 0: 1072 // OutColor = vec4(0.0,0.0,0.0,0.0); 1073 // break; 1074 // case 1: 1075 // OutColor = vec4(0.125,0.125,0.125,0.125); 1076 // break; 1077 // case 2: 1078 // OutColor = vec4(0.25,0.25,0.25,0.25); 1079 // break; 1080 // default: 1081 // OutColor = vec4(1.0,1.0,1.0,1.0); 1082 // } 1083 // } 1084 1085 const std::string predefs = 1086 R"(OpCapability Shader 1087 %1 = OpExtInstImport "GLSL.std.450" 1088 OpMemoryModel Logical GLSL450 1089 OpEntryPoint Fragment %main "main" %OutColor %BaseColor 1090 OpExecutionMode %main OriginUpperLeft 1091 OpSource GLSL 450 1092 OpName %main "main" 1093 OpName %OutColor "OutColor" 1094 OpName %BaseColor "BaseColor" 1095 OpDecorate %OutColor Location 0 1096 OpDecorate %BaseColor Location 0 1097 %void = OpTypeVoid 1098 %6 = OpTypeFunction %void 1099 %int = OpTypeInt 32 1 1100 %int_1 = OpConstant %int 1 1101 %float = OpTypeFloat 32 1102 %v4float = OpTypeVector %float 4 1103 %_ptr_Output_v4float = OpTypePointer Output %v4float 1104 %OutColor = OpVariable %_ptr_Output_v4float Output 1105 %float_0 = OpConstant %float 0 1106 %13 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 1107 %float_0_125 = OpConstant %float 0.125 1108 %15 = OpConstantComposite %v4float %float_0_125 %float_0_125 %float_0_125 %float_0_125 1109 %float_0_25 = OpConstant %float 0.25 1110 %17 = OpConstantComposite %v4float %float_0_25 %float_0_25 %float_0_25 %float_0_25 1111 %float_1 = OpConstant %float 1 1112 %19 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 1113 %_ptr_Input_v4float = OpTypePointer Input %v4float 1114 %BaseColor = OpVariable %_ptr_Input_v4float Input 1115 )"; 1116 1117 const std::string before = 1118 R"(%main = OpFunction %void None %6 1119 %21 = OpLabel 1120 OpSelectionMerge %22 None 1121 OpSwitch %int_1 %23 0 %24 1 %25 2 %26 1122 %23 = OpLabel 1123 OpStore %OutColor %19 1124 OpBranch %22 1125 %24 = OpLabel 1126 OpStore %OutColor %13 1127 OpBranch %22 1128 %25 = OpLabel 1129 OpStore %OutColor %15 1130 OpBranch %22 1131 %26 = OpLabel 1132 OpStore %OutColor %17 1133 OpBranch %22 1134 %22 = OpLabel 1135 OpReturn 1136 OpFunctionEnd 1137 )"; 1138 1139 const std::string after = 1140 R"(%main = OpFunction %void None %6 1141 %21 = OpLabel 1142 OpBranch %25 1143 %25 = OpLabel 1144 OpStore %OutColor %15 1145 OpBranch %22 1146 %22 = OpLabel 1147 OpReturn 1148 OpFunctionEnd 1149 )"; 1150 1151 SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after, 1152 true, true); 1153 } 1154 1155 TEST_F(DeadBranchElimTest, SwitchLiveDefault) { 1156 // #version 450 1157 // 1158 // layout (location=0) in vec4 BaseColor; 1159 // layout (location=0) out vec4 OutColor; 1160 // 1161 // void main() 1162 // { 1163 // switch (7) { 1164 // case 0: 1165 // OutColor = vec4(0.0,0.0,0.0,0.0); 1166 // break; 1167 // case 1: 1168 // OutColor = vec4(0.125,0.125,0.125,0.125); 1169 // break; 1170 // case 2: 1171 // OutColor = vec4(0.25,0.25,0.25,0.25); 1172 // break; 1173 // default: 1174 // OutColor = vec4(1.0,1.0,1.0,1.0); 1175 // } 1176 // } 1177 1178 const std::string predefs = 1179 R"(OpCapability Shader 1180 %1 = OpExtInstImport "GLSL.std.450" 1181 OpMemoryModel Logical GLSL450 1182 OpEntryPoint Fragment %main "main" %OutColor %BaseColor 1183 OpExecutionMode %main OriginUpperLeft 1184 OpSource GLSL 450 1185 OpName %main "main" 1186 OpName %OutColor "OutColor" 1187 OpName %BaseColor "BaseColor" 1188 OpDecorate %OutColor Location 0 1189 OpDecorate %BaseColor Location 0 1190 %void = OpTypeVoid 1191 %6 = OpTypeFunction %void 1192 %int = OpTypeInt 32 1 1193 %int_7 = OpConstant %int 7 1194 %float = OpTypeFloat 32 1195 %v4float = OpTypeVector %float 4 1196 %_ptr_Output_v4float = OpTypePointer Output %v4float 1197 %OutColor = OpVariable %_ptr_Output_v4float Output 1198 %float_0 = OpConstant %float 0 1199 %13 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 1200 %float_0_125 = OpConstant %float 0.125 1201 %15 = OpConstantComposite %v4float %float_0_125 %float_0_125 %float_0_125 %float_0_125 1202 %float_0_25 = OpConstant %float 0.25 1203 %17 = OpConstantComposite %v4float %float_0_25 %float_0_25 %float_0_25 %float_0_25 1204 %float_1 = OpConstant %float 1 1205 %19 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 1206 %_ptr_Input_v4float = OpTypePointer Input %v4float 1207 %BaseColor = OpVariable %_ptr_Input_v4float Input 1208 )"; 1209 1210 const std::string before = 1211 R"(%main = OpFunction %void None %6 1212 %21 = OpLabel 1213 OpSelectionMerge %22 None 1214 OpSwitch %int_7 %23 0 %24 1 %25 2 %26 1215 %23 = OpLabel 1216 OpStore %OutColor %19 1217 OpBranch %22 1218 %24 = OpLabel 1219 OpStore %OutColor %13 1220 OpBranch %22 1221 %25 = OpLabel 1222 OpStore %OutColor %15 1223 OpBranch %22 1224 %26 = OpLabel 1225 OpStore %OutColor %17 1226 OpBranch %22 1227 %22 = OpLabel 1228 OpReturn 1229 OpFunctionEnd 1230 )"; 1231 1232 const std::string after = 1233 R"(%main = OpFunction %void None %6 1234 %21 = OpLabel 1235 OpBranch %23 1236 %23 = OpLabel 1237 OpStore %OutColor %19 1238 OpBranch %22 1239 %22 = OpLabel 1240 OpReturn 1241 OpFunctionEnd 1242 )"; 1243 1244 SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after, 1245 true, true); 1246 } 1247 1248 TEST_F(DeadBranchElimTest, SwitchLiveCaseBreakFromLoop) { 1249 // This sample does not directly translate to GLSL/HLSL as 1250 // direct breaks from a loop cannot be made from a switch. 1251 // This construct is currently formed by inlining a function 1252 // containing early returns from the cases of a switch. The 1253 // function is wrapped in a one-trip loop and returns are 1254 // translated to branches to the loop's merge block. 1255 1256 const std::string predefs = 1257 R"(OpCapability Shader 1258 %1 = OpExtInstImport "GLSL.std.450" 1259 OpMemoryModel Logical GLSL450 1260 OpEntryPoint Fragment %main "main" %OutColor %BaseColor 1261 OpExecutionMode %main OriginUpperLeft 1262 OpSource GLSL 450 1263 OpName %main "main" 1264 OpName %oc "oc" 1265 OpName %OutColor "OutColor" 1266 OpName %BaseColor "BaseColor" 1267 OpDecorate %OutColor Location 0 1268 OpDecorate %BaseColor Location 0 1269 %void = OpTypeVoid 1270 %7 = OpTypeFunction %void 1271 %bool = OpTypeBool 1272 %true = OpConstantTrue %bool 1273 %false = OpConstantFalse %bool 1274 %int = OpTypeInt 32 1 1275 %int_1 = OpConstant %int 1 1276 %float = OpTypeFloat 32 1277 %v4float = OpTypeVector %float 4 1278 %_ptr_Function_v4float = OpTypePointer Function %v4float 1279 %float_0 = OpConstant %float 0 1280 %17 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 1281 %float_0_125 = OpConstant %float 0.125 1282 %19 = OpConstantComposite %v4float %float_0_125 %float_0_125 %float_0_125 %float_0_125 1283 %float_0_25 = OpConstant %float 0.25 1284 %21 = OpConstantComposite %v4float %float_0_25 %float_0_25 %float_0_25 %float_0_25 1285 %float_1 = OpConstant %float 1 1286 %23 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 1287 %_ptr_Output_v4float = OpTypePointer Output %v4float 1288 %OutColor = OpVariable %_ptr_Output_v4float Output 1289 %_ptr_Input_v4float = OpTypePointer Input %v4float 1290 %BaseColor = OpVariable %_ptr_Input_v4float Input 1291 )"; 1292 1293 const std::string before = 1294 R"(%main = OpFunction %void None %7 1295 %26 = OpLabel 1296 %oc = OpVariable %_ptr_Function_v4float Function 1297 OpBranch %27 1298 %27 = OpLabel 1299 OpLoopMerge %28 %29 None 1300 OpBranch %30 1301 %30 = OpLabel 1302 OpSelectionMerge %31 None 1303 OpSwitch %int_1 %31 0 %32 1 %33 2 %34 1304 %32 = OpLabel 1305 OpStore %oc %17 1306 OpBranch %28 1307 %33 = OpLabel 1308 OpStore %oc %19 1309 OpBranch %28 1310 %34 = OpLabel 1311 OpStore %oc %21 1312 OpBranch %28 1313 %31 = OpLabel 1314 OpStore %oc %23 1315 OpBranch %28 1316 %29 = OpLabel 1317 OpBranchConditional %false %27 %28 1318 %28 = OpLabel 1319 %35 = OpLoad %v4float %oc 1320 OpStore %OutColor %35 1321 OpReturn 1322 OpFunctionEnd 1323 )"; 1324 1325 const std::string after = 1326 R"(%main = OpFunction %void None %7 1327 %26 = OpLabel 1328 %oc = OpVariable %_ptr_Function_v4float Function 1329 OpBranch %27 1330 %27 = OpLabel 1331 OpLoopMerge %28 %29 None 1332 OpBranch %30 1333 %30 = OpLabel 1334 OpBranch %33 1335 %33 = OpLabel 1336 OpStore %oc %19 1337 OpBranch %28 1338 %29 = OpLabel 1339 OpBranch %27 1340 %28 = OpLabel 1341 %35 = OpLoad %v4float %oc 1342 OpStore %OutColor %35 1343 OpReturn 1344 OpFunctionEnd 1345 )"; 1346 1347 SinglePassRunAndCheck<DeadBranchElimPass>(predefs + before, predefs + after, 1348 true, true); 1349 } 1350 1351 TEST_F(DeadBranchElimTest, LeaveContinueBackedge) { 1352 const std::string text = R"( 1353 ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None 1354 ; CHECK: [[continue]] = OpLabel 1355 ; CHECK-NEXT: OpBranchConditional {{%\w+}} {{%\w+}} [[merge]] 1356 ; CHECK-NEXT: [[merge]] = OpLabel 1357 ; CHECK-NEXT: OpReturn 1358 OpCapability Kernel 1359 OpCapability Linkage 1360 OpMemoryModel Logical OpenCL 1361 %bool = OpTypeBool 1362 %false = OpConstantFalse %bool 1363 %void = OpTypeVoid 1364 %funcTy = OpTypeFunction %void 1365 %func = OpFunction %void None %funcTy 1366 %1 = OpLabel 1367 OpBranch %2 1368 %2 = OpLabel 1369 OpLoopMerge %3 %4 None 1370 OpBranch %4 1371 %4 = OpLabel 1372 ; Be careful we don't remove the backedge to %2 despite never taking it. 1373 OpBranchConditional %false %2 %3 1374 %3 = OpLabel 1375 OpReturn 1376 OpFunctionEnd 1377 )"; 1378 1379 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 1380 } 1381 TEST_F(DeadBranchElimTest, LeaveContinueBackedgeExtraBlock) { 1382 const std::string text = R"( 1383 ; CHECK: OpBranch [[header:%\w+]] 1384 ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None 1385 ; CHECK-NEXT: OpBranch [[continue]] 1386 ; CHECK-NEXT: [[continue]] = OpLabel 1387 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[extra:%\w+]] [[merge]] 1388 ; CHECK-NEXT: [[extra]] = OpLabel 1389 ; CHECK-NEXT: OpBranch [[header]] 1390 ; CHECK-NEXT: [[merge]] = OpLabel 1391 ; CHECK-NEXT: OpReturn 1392 OpCapability Kernel 1393 OpCapability Linkage 1394 OpMemoryModel Logical OpenCL 1395 %bool = OpTypeBool 1396 %false = OpConstantFalse %bool 1397 %void = OpTypeVoid 1398 %funcTy = OpTypeFunction %void 1399 %func = OpFunction %void None %funcTy 1400 %1 = OpLabel 1401 OpBranch %2 1402 %2 = OpLabel 1403 OpLoopMerge %3 %4 None 1404 OpBranch %4 1405 %4 = OpLabel 1406 ; Be careful we don't remove the backedge to %2 despite never taking it. 1407 OpBranchConditional %false %5 %3 1408 ; This block remains live despite being unreachable. 1409 %5 = OpLabel 1410 OpBranch %2 1411 %3 = OpLabel 1412 OpReturn 1413 OpFunctionEnd 1414 )"; 1415 1416 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 1417 } 1418 1419 TEST_F(DeadBranchElimTest, RemovePhiWithUnreachableContinue) { 1420 const std::string text = R"( 1421 ; CHECK: [[entry:%\w+]] = OpLabel 1422 ; CHECK-NEXT: OpBranch [[header:%\w+]] 1423 ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None 1424 ; CHECK-NEXT: OpBranch [[ret:%\w+]] 1425 ; CHECK-NEXT: [[ret]] = OpLabel 1426 ; CHECK-NEXT: OpReturn 1427 ; CHECK: [[continue]] = OpLabel 1428 ; CHECK-NEXT: OpBranch [[header]] 1429 ; CHECK: [[merge]] = OpLabel 1430 ; CHECK-NEXT: OpUnreachable 1431 OpCapability Kernel 1432 OpCapability Linkage 1433 OpMemoryModel Logical OpenCL 1434 OpName %func "func" 1435 OpDecorate %func LinkageAttributes "func" Export 1436 %bool = OpTypeBool 1437 %false = OpConstantFalse %bool 1438 %true = OpConstantTrue %bool 1439 %void = OpTypeVoid 1440 %funcTy = OpTypeFunction %void 1441 %func = OpFunction %void None %funcTy 1442 %1 = OpLabel 1443 OpBranch %2 1444 %2 = OpLabel 1445 %phi = OpPhi %bool %false %1 %true %continue 1446 OpLoopMerge %merge %continue None 1447 OpBranch %3 1448 %3 = OpLabel 1449 OpReturn 1450 %continue = OpLabel 1451 OpBranch %2 1452 %merge = OpLabel 1453 OpReturn 1454 OpFunctionEnd 1455 )"; 1456 1457 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 1458 } 1459 1460 TEST_F(DeadBranchElimTest, UnreachableLoopMergeAndContinueTargets) { 1461 const std::string text = R"( 1462 ; CHECK: [[undef:%\w+]] = OpUndef %bool 1463 ; CHECK: OpSelectionMerge [[header:%\w+]] 1464 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[if_lab:%\w+]] [[else_lab:%\w+]] 1465 ; CHECK: OpPhi %bool %false [[if_lab]] %false [[else_lab]] [[undef]] [[continue:%\w+]] 1466 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue]] None 1467 ; CHECK-NEXT: OpBranch [[ret:%\w+]] 1468 ; CHECK-NEXT: [[ret]] = OpLabel 1469 ; CHECK-NEXT: OpReturn 1470 ; CHECK: [[continue]] = OpLabel 1471 ; CHECK-NEXT: OpBranch [[header]] 1472 ; CHECK: [[merge]] = OpLabel 1473 ; CHECK-NEXT: OpUnreachable 1474 OpCapability Kernel 1475 OpCapability Linkage 1476 OpMemoryModel Logical OpenCL 1477 OpName %func "func" 1478 OpDecorate %func LinkageAttributes "func" Export 1479 %bool = OpTypeBool 1480 %false = OpConstantFalse %bool 1481 %true = OpConstantTrue %bool 1482 %void = OpTypeVoid 1483 %funcTy = OpTypeFunction %void 1484 %func = OpFunction %void None %funcTy 1485 %1 = OpLabel 1486 %c = OpUndef %bool 1487 OpSelectionMerge %2 None 1488 OpBranchConditional %c %if %else 1489 %if = OpLabel 1490 OpBranch %2 1491 %else = OpLabel 1492 OpBranch %2 1493 %2 = OpLabel 1494 %phi = OpPhi %bool %false %if %false %else %true %continue 1495 OpLoopMerge %merge %continue None 1496 OpBranch %3 1497 %3 = OpLabel 1498 OpReturn 1499 %continue = OpLabel 1500 OpBranch %2 1501 %merge = OpLabel 1502 OpReturn 1503 OpFunctionEnd 1504 )"; 1505 1506 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 1507 } 1508 TEST_F(DeadBranchElimTest, EarlyReconvergence) { 1509 const std::string text = R"( 1510 ; CHECK-NOT: OpBranchConditional 1511 ; CHECK: [[logical:%\w+]] = OpLogicalOr 1512 ; CHECK-NOT: OpPhi 1513 ; CHECK: OpLogicalAnd {{%\w+}} {{%\w+}} [[logical]] 1514 OpCapability Shader 1515 OpMemoryModel Logical GLSL450 1516 OpEntryPoint Fragment %func "func" 1517 OpExecutionMode %func OriginUpperLeft 1518 %void = OpTypeVoid 1519 %bool = OpTypeBool 1520 %false = OpConstantFalse %bool 1521 %true = OpConstantTrue %bool 1522 %func_ty = OpTypeFunction %void 1523 %func = OpFunction %void None %func_ty 1524 %1 = OpLabel 1525 OpSelectionMerge %2 None 1526 OpBranchConditional %false %3 %4 1527 %3 = OpLabel 1528 %12 = OpLogicalNot %bool %true 1529 OpBranch %2 1530 %4 = OpLabel 1531 OpSelectionMerge %14 None 1532 OpBranchConditional %false %5 %6 1533 %5 = OpLabel 1534 %10 = OpLogicalAnd %bool %true %false 1535 OpBranch %7 1536 %6 = OpLabel 1537 %11 = OpLogicalOr %bool %true %false 1538 OpBranch %7 1539 %7 = OpLabel 1540 ; This phi is in a block preceeding the merge %14! 1541 %8 = OpPhi %bool %10 %5 %11 %6 1542 OpBranch %14 1543 %14 = OpLabel 1544 OpBranch %2 1545 %2 = OpLabel 1546 %9 = OpPhi %bool %12 %3 %8 %14 1547 %13 = OpLogicalAnd %bool %true %9 1548 OpReturn 1549 OpFunctionEnd 1550 )"; 1551 1552 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 1553 } 1554 1555 TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksFloating) { 1556 const std::string text = R"( 1557 ; CHECK: OpFunction 1558 ; CHECK-NEXT: OpLabel 1559 ; CHECK-NEXT: OpReturn 1560 ; CHECK-NEXT: OpFunctionEnd 1561 OpCapability Kernel 1562 OpCapability Linkage 1563 OpMemoryModel Logical OpenCL 1564 OpName %func "func" 1565 OpDecorate %func LinkageAttributes "func" Export 1566 %void = OpTypeVoid 1567 %1 = OpTypeFunction %void 1568 %func = OpFunction %void None %1 1569 %2 = OpLabel 1570 OpReturn 1571 %3 = OpLabel 1572 OpReturn 1573 OpFunctionEnd 1574 )"; 1575 1576 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 1577 } 1578 1579 TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksFloatingJoin) { 1580 const std::string text = R"( 1581 ; CHECK: OpFunction 1582 ; CHECK-NEXT: OpFunctionParameter 1583 ; CHECK-NEXT: OpLabel 1584 ; CHECK-NEXT: OpReturn 1585 ; CHECK-NEXT: OpFunctionEnd 1586 OpCapability Kernel 1587 OpCapability Linkage 1588 OpMemoryModel Logical OpenCL 1589 OpName %func "func" 1590 OpDecorate %func LinkageAttributes "func" Export 1591 %void = OpTypeVoid 1592 %bool = OpTypeBool 1593 %false = OpConstantFalse %bool 1594 %true = OpConstantTrue %bool 1595 %1 = OpTypeFunction %void %bool 1596 %func = OpFunction %void None %1 1597 %bool_param = OpFunctionParameter %bool 1598 %2 = OpLabel 1599 OpReturn 1600 %3 = OpLabel 1601 OpSelectionMerge %6 None 1602 OpBranchConditional %bool_param %4 %5 1603 %4 = OpLabel 1604 OpBranch %6 1605 %5 = OpLabel 1606 OpBranch %6 1607 %6 = OpLabel 1608 %7 = OpPhi %bool %true %4 %false %6 1609 OpReturn 1610 OpFunctionEnd 1611 )"; 1612 1613 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 1614 } 1615 1616 TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksDeadPhi) { 1617 const std::string text = R"( 1618 ; CHECK: OpFunction 1619 ; CHECK-NEXT: OpFunctionParameter 1620 ; CHECK-NEXT: OpLabel 1621 ; CHECK-NEXT: OpBranch [[label:%\w+]] 1622 ; CHECK-NEXT: [[label]] = OpLabel 1623 ; CHECK-NEXT: OpLogicalNot %bool %true 1624 ; CHECK-NEXT: OpReturn 1625 ; CHECK-NEXT: OpFunctionEnd 1626 OpCapability Kernel 1627 OpCapability Linkage 1628 OpMemoryModel Logical OpenCL 1629 OpName %func "func" 1630 OpDecorate %func LinkageAttributes "func" Export 1631 %void = OpTypeVoid 1632 %bool = OpTypeBool 1633 %false = OpConstantFalse %bool 1634 %true = OpConstantTrue %bool 1635 %1 = OpTypeFunction %void %bool 1636 %func = OpFunction %void None %1 1637 %bool_param = OpFunctionParameter %bool 1638 %2 = OpLabel 1639 OpBranch %3 1640 %4 = OpLabel 1641 OpBranch %3 1642 %3 = OpLabel 1643 %5 = OpPhi %bool %true %2 %false %4 1644 %6 = OpLogicalNot %bool %5 1645 OpReturn 1646 OpFunctionEnd 1647 )"; 1648 1649 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 1650 } 1651 1652 TEST_F(DeadBranchElimTest, RemoveUnreachableBlocksPartiallyDeadPhi) { 1653 const std::string text = R"( 1654 ; CHECK: OpFunction 1655 ; CHECK-NEXT: [[param:%\w+]] = OpFunctionParameter 1656 ; CHECK-NEXT: OpLabel 1657 ; CHECK-NEXT: OpBranchConditional [[param]] [[merge:%\w+]] [[br:%\w+]] 1658 ; CHECK-NEXT: [[merge]] = OpLabel 1659 ; CHECK-NEXT: [[phi:%\w+]] = OpPhi %bool %true %2 %false [[br]] 1660 ; CHECK-NEXT: OpLogicalNot %bool [[phi]] 1661 ; CHECK-NEXT: OpReturn 1662 ; CHECK-NEXT: [[br]] = OpLabel 1663 ; CHECK-NEXT: OpBranch [[merge]] 1664 ; CHECK-NEXT: OpFunctionEnd 1665 OpCapability Kernel 1666 OpCapability Linkage 1667 OpMemoryModel Logical OpenCL 1668 OpName %func "func" 1669 OpDecorate %func LinkageAttributes "func" Export 1670 %void = OpTypeVoid 1671 %bool = OpTypeBool 1672 %false = OpConstantFalse %bool 1673 %true = OpConstantTrue %bool 1674 %1 = OpTypeFunction %void %bool 1675 %func = OpFunction %void None %1 1676 %bool_param = OpFunctionParameter %bool 1677 %2 = OpLabel 1678 OpBranchConditional %bool_param %3 %7 1679 %7 = OpLabel 1680 OpBranch %3 1681 %4 = OpLabel 1682 OpBranch %3 1683 %3 = OpLabel 1684 %5 = OpPhi %bool %true %2 %false %7 %false %4 1685 %6 = OpLogicalNot %bool %5 1686 OpReturn 1687 OpFunctionEnd 1688 )"; 1689 1690 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1691 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 1692 } 1693 1694 TEST_F(DeadBranchElimTest, LiveHeaderDeadPhi) { 1695 const std::string text = R"( 1696 ; CHECK: OpLabel 1697 ; CHECK-NOT: OpBranchConditional 1698 ; CHECK-NOT: OpPhi 1699 ; CHECK: OpLogicalNot %bool %false 1700 OpCapability Kernel 1701 OpCapability Linkage 1702 OpMemoryModel Logical OpenCL 1703 OpName %func "func" 1704 OpDecorate %func LinkageAttributes "func" Export 1705 %void = OpTypeVoid 1706 %bool = OpTypeBool 1707 %true = OpConstantTrue %bool 1708 %false = OpConstantFalse %bool 1709 %func_ty = OpTypeFunction %void 1710 %func = OpFunction %void None %func_ty 1711 %1 = OpLabel 1712 OpSelectionMerge %3 None 1713 OpBranchConditional %true %2 %3 1714 %2 = OpLabel 1715 OpBranch %3 1716 %3 = OpLabel 1717 %5 = OpPhi %bool %true %3 %false %2 1718 %6 = OpLogicalNot %bool %5 1719 OpReturn 1720 OpFunctionEnd 1721 )"; 1722 1723 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 1724 } 1725 1726 TEST_F(DeadBranchElimTest, ExtraBackedgeBlocksLive) { 1727 const std::string text = R"( 1728 ; CHECK: [[entry:%\w+]] = OpLabel 1729 ; CHECK-NOT: OpSelectionMerge 1730 ; CHECK: OpBranch [[header:%\w+]] 1731 ; CHECK-NEXT: [[header]] = OpLabel 1732 ; CHECK-NEXT: OpPhi %bool %true [[entry]] %false [[backedge:%\w+]] 1733 ; CHECK-NEXT: OpLoopMerge 1734 OpCapability Kernel 1735 OpCapability Linkage 1736 OpMemoryModel Logical OpenCL 1737 OpName %func "func" 1738 OpDecorate %func LinkageAttributes "func" Export 1739 %void = OpTypeVoid 1740 %bool = OpTypeBool 1741 %true = OpConstantTrue %bool 1742 %false = OpConstantFalse %bool 1743 %func_ty = OpTypeFunction %void %bool 1744 %func = OpFunction %void None %func_ty 1745 %param = OpFunctionParameter %bool 1746 %entry = OpLabel 1747 OpSelectionMerge %if_merge None 1748 ; This dead branch is included to ensure the pass does work. 1749 OpBranchConditional %false %if_merge %loop_header 1750 %loop_header = OpLabel 1751 ; Both incoming edges are live, so the phi should be untouched. 1752 %phi = OpPhi %bool %true %entry %false %backedge 1753 OpLoopMerge %loop_merge %continue None 1754 OpBranchConditional %param %loop_merge %continue 1755 %continue = OpLabel 1756 OpBranch %backedge 1757 %backedge = OpLabel 1758 OpBranch %loop_header 1759 %loop_merge = OpLabel 1760 OpBranch %if_merge 1761 %if_merge = OpLabel 1762 OpReturn 1763 OpFunctionEnd 1764 )"; 1765 1766 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 1767 } 1768 1769 TEST_F(DeadBranchElimTest, ExtraBackedgeBlocksUnreachable) { 1770 const std::string text = R"( 1771 ; CHECK: [[entry:%\w+]] = OpLabel 1772 ; CHECK-NEXT: OpBranch [[header:%\w+]] 1773 ; CHECK-NEXT: [[header]] = OpLabel 1774 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None 1775 ; CHECK-NEXT: OpBranch [[merge]] 1776 ; CHECK-NEXT: [[merge]] = OpLabel 1777 ; CHECK-NEXT: OpReturn 1778 ; CHECK-NEXT: [[continue]] = OpLabel 1779 ; CHECK-NEXT: OpBranch [[header]] 1780 OpCapability Kernel 1781 OpCapability Linkage 1782 OpMemoryModel Logical OpenCL 1783 OpName %func "func" 1784 OpDecorate %func LinkageAttributes "func" Export 1785 %void = OpTypeVoid 1786 %bool = OpTypeBool 1787 %true = OpConstantTrue %bool 1788 %false = OpConstantFalse %bool 1789 %func_ty = OpTypeFunction %void %bool 1790 %func = OpFunction %void None %func_ty 1791 %param = OpFunctionParameter %bool 1792 %entry = OpLabel 1793 OpBranch %loop_header 1794 %loop_header = OpLabel 1795 ; Since the continue is unreachable, %backedge will be removed. The phi will 1796 ; instead require an edge from %continue. 1797 %phi = OpPhi %bool %true %entry %false %backedge 1798 OpLoopMerge %merge %continue None 1799 OpBranch %merge 1800 %continue = OpLabel 1801 OpBranch %backedge 1802 %backedge = OpLabel 1803 OpBranch %loop_header 1804 %merge = OpLabel 1805 OpReturn 1806 OpFunctionEnd 1807 )"; 1808 1809 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 1810 } 1811 1812 TEST_F(DeadBranchElimTest, NoUnnecessaryChanges) { 1813 const std::string text = R"( 1814 OpCapability Shader 1815 OpMemoryModel Logical GLSL450 1816 OpEntryPoint Fragment %func "func" 1817 %void = OpTypeVoid 1818 %bool = OpTypeBool 1819 %true = OpConstantTrue %bool 1820 %undef = OpUndef %bool 1821 %functy = OpTypeFunction %void 1822 %func = OpFunction %void None %functy 1823 %1 = OpLabel 1824 OpBranch %2 1825 %2 = OpLabel 1826 OpLoopMerge %4 %5 None 1827 OpBranch %6 1828 %6 = OpLabel 1829 OpReturn 1830 %5 = OpLabel 1831 OpBranch %2 1832 %4 = OpLabel 1833 OpUnreachable 1834 OpFunctionEnd 1835 )"; 1836 1837 auto result = SinglePassRunToBinary<DeadBranchElimPass>(text, true); 1838 EXPECT_EQ(std::get<1>(result), Pass::Status::SuccessWithoutChange); 1839 } 1840 1841 TEST_F(DeadBranchElimTest, ExtraBackedgePartiallyDead) { 1842 const std::string text = R"( 1843 ; CHECK: OpLabel 1844 ; CHECK: [[header:%\w+]] = OpLabel 1845 ; CHECK: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None 1846 ; CHECK: [[merge]] = OpLabel 1847 ; CHECK: [[continue]] = OpLabel 1848 ; CHECK: OpBranch [[extra:%\w+]] 1849 ; CHECK: [[extra]] = OpLabel 1850 ; CHECK-NOT: OpSelectionMerge 1851 ; CHECK-NEXT: OpBranch [[else:%\w+]] 1852 ; CHECK-NEXT: [[else]] = OpLabel 1853 ; CHECK-NEXT: OpLogicalOr 1854 ; CHECK-NEXT: OpBranch [[backedge:%\w+]] 1855 ; CHECK-NEXT: [[backedge:%\w+]] = OpLabel 1856 ; CHECK-NEXT: OpBranch [[header]] 1857 OpCapability Kernel 1858 OpCapability Linkage 1859 OpMemoryModel Logical OpenCL 1860 OpName %func "func" 1861 OpDecorate %func LinkageAttributes "func" Export 1862 %void = OpTypeVoid 1863 %bool = OpTypeBool 1864 %true = OpConstantTrue %bool 1865 %false = OpConstantFalse %bool 1866 %func_ty = OpTypeFunction %void %bool 1867 %func = OpFunction %void None %func_ty 1868 %param = OpFunctionParameter %bool 1869 %entry = OpLabel 1870 OpBranch %loop_header 1871 %loop_header = OpLabel 1872 OpLoopMerge %loop_merge %continue None 1873 OpBranchConditional %param %loop_merge %continue 1874 %continue = OpLabel 1875 OpBranch %extra 1876 %extra = OpLabel 1877 OpSelectionMerge %backedge None 1878 OpBranchConditional %false %then %else 1879 %then = OpLabel 1880 %and = OpLogicalAnd %bool %true %false 1881 OpBranch %backedge 1882 %else = OpLabel 1883 %or = OpLogicalOr %bool %true %false 1884 OpBranch %backedge 1885 %backedge = OpLabel 1886 OpBranch %loop_header 1887 %loop_merge = OpLabel 1888 OpReturn 1889 OpFunctionEnd 1890 )"; 1891 1892 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 1893 } 1894 1895 TEST_F(DeadBranchElimTest, UnreachableContinuePhiInMerge) { 1896 const std::string text = R"( 1897 ; CHECK: [[entry:%\w+]] = OpLabel 1898 ; CHECK-NEXT: OpBranch [[header:%\w+]] 1899 ; CHECK-NEXT: [[header]] = OpLabel 1900 ; CHECK-NEXT: OpLoopMerge [[merge:%\w+]] [[continue:%\w+]] None 1901 ; CHECK-NEXT: OpBranch [[label:%\w+]] 1902 ; CHECK-NEXT: [[label]] = OpLabel 1903 ; CHECK-NEXT: [[fadd:%\w+]] = OpFAdd 1904 ; CHECK-NEXT: OpBranch [[label:%\w+]] 1905 ; CHECK-NEXT: [[label]] = OpLabel 1906 ; CHECK-NEXT: OpBranch [[merge]] 1907 ; CHECK-NEXT: [[continue]] = OpLabel 1908 ; CHECK-NEXT: OpBranch [[header]] 1909 ; CHECK-NEXT: [[merge]] = OpLabel 1910 ; CHECK-NEXT: OpStore {{%\w+}} [[fadd]] 1911 OpCapability Shader 1912 %1 = OpExtInstImport "GLSL.std.450" 1913 OpMemoryModel Logical GLSL450 1914 OpEntryPoint Fragment %main "main" %o 1915 OpExecutionMode %main OriginUpperLeft 1916 OpSource GLSL 430 1917 OpSourceExtension "GL_GOOGLE_cpp_style_line_directive" 1918 OpSourceExtension "GL_GOOGLE_include_directive" 1919 OpName %main "main" 1920 OpName %o "o" 1921 OpName %S "S" 1922 OpMemberName %S 0 "a" 1923 OpName %U_t "U_t" 1924 OpMemberName %U_t 0 "g_F" 1925 OpMemberName %U_t 1 "g_F2" 1926 OpDecorate %o Location 0 1927 OpMemberDecorate %S 0 Offset 0 1928 OpMemberDecorate %U_t 0 Volatile 1929 OpMemberDecorate %U_t 0 Offset 0 1930 OpMemberDecorate %U_t 1 Offset 4 1931 OpDecorate %U_t BufferBlock 1932 %void = OpTypeVoid 1933 %7 = OpTypeFunction %void 1934 %float = OpTypeFloat 32 1935 %_ptr_Function_float = OpTypePointer Function %float 1936 %float_0 = OpConstant %float 0 1937 %int = OpTypeInt 32 1 1938 %_ptr_Function_int = OpTypePointer Function %int 1939 %int_0 = OpConstant %int 0 1940 %int_10 = OpConstant %int 10 1941 %bool = OpTypeBool 1942 %true = OpConstantTrue %bool 1943 %float_1 = OpConstant %float 1 1944 %float_5 = OpConstant %float 5 1945 %int_1 = OpConstant %int 1 1946 %_ptr_Output_float = OpTypePointer Output %float 1947 %o = OpVariable %_ptr_Output_float Output 1948 %S = OpTypeStruct %float 1949 %U_t = OpTypeStruct %S %S 1950 %_ptr_Uniform_U_t = OpTypePointer Uniform %U_t 1951 %main = OpFunction %void None %7 1952 %22 = OpLabel 1953 OpBranch %23 1954 %23 = OpLabel 1955 %24 = OpPhi %float %float_0 %22 %25 %26 1956 %27 = OpPhi %int %int_0 %22 %28 %26 1957 OpLoopMerge %29 %26 None 1958 OpBranch %40 1959 %40 = OpLabel 1960 %25 = OpFAdd %float %24 %float_1 1961 OpSelectionMerge %30 None 1962 OpBranchConditional %true %31 %30 1963 %31 = OpLabel 1964 OpBranch %29 1965 %30 = OpLabel 1966 OpBranch %26 1967 %26 = OpLabel 1968 %28 = OpIAdd %int %27 %int_1 1969 %32 = OpSLessThan %bool %27 %int_10 1970 ; continue block branches to the header or another none dead block. 1971 OpBranchConditional %32 %23 %29 1972 %29 = OpLabel 1973 %33 = OpPhi %float %24 %26 %25 %31 1974 OpStore %o %33 1975 OpReturn 1976 OpFunctionEnd 1977 )"; 1978 1979 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 1980 } 1981 1982 TEST_F(DeadBranchElimTest, NonStructuredIf) { 1983 const std::string text = R"( 1984 ; CHECK-NOT: OpBranchConditional 1985 OpCapability Kernel 1986 OpCapability Linkage 1987 OpMemoryModel Logical OpenCL 1988 OpDecorate %func LinkageAttributes "func" Export 1989 %void = OpTypeVoid 1990 %bool = OpTypeBool 1991 %true = OpConstantTrue %bool 1992 %functy = OpTypeFunction %void 1993 %func = OpFunction %void None %functy 1994 %entry = OpLabel 1995 OpBranchConditional %true %then %else 1996 %then = OpLabel 1997 OpBranch %final 1998 %else = OpLabel 1999 OpBranch %final 2000 %final = OpLabel 2001 OpReturn 2002 OpFunctionEnd 2003 )"; 2004 2005 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 2006 } 2007 2008 TEST_F(DeadBranchElimTest, ReorderBlocks) { 2009 const std::string text = R"( 2010 ; CHECK: OpLabel 2011 ; CHECK: OpBranch [[label:%\w+]] 2012 ; CHECK: [[label:%\w+]] = OpLabel 2013 ; CHECK-NEXT: OpLogicalNot 2014 ; CHECK-NEXT: OpBranch [[label:%\w+]] 2015 ; CHECK: [[label]] = OpLabel 2016 ; CHECK-NEXT: OpReturn 2017 OpCapability Shader 2018 OpMemoryModel Logical GLSL450 2019 OpEntryPoint Fragment %func "func" 2020 OpExecutionMode %func OriginUpperLeft 2021 %void = OpTypeVoid 2022 %bool = OpTypeBool 2023 %true = OpConstantTrue %bool 2024 %func_ty = OpTypeFunction %void 2025 %func = OpFunction %void None %func_ty 2026 %1 = OpLabel 2027 OpSelectionMerge %3 None 2028 OpBranchConditional %true %2 %3 2029 %3 = OpLabel 2030 OpReturn 2031 %2 = OpLabel 2032 %not = OpLogicalNot %bool %true 2033 OpBranch %3 2034 OpFunctionEnd 2035 )"; 2036 2037 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 2038 } 2039 2040 TEST_F(DeadBranchElimTest, ReorderBlocksMultiple) { 2041 // Checks are not important. The validation post optimization is the 2042 // important part. 2043 const std::string text = R"( 2044 ; CHECK: OpLabel 2045 OpCapability Shader 2046 OpMemoryModel Logical GLSL450 2047 OpEntryPoint Fragment %func "func" 2048 OpExecutionMode %func OriginUpperLeft 2049 %void = OpTypeVoid 2050 %bool = OpTypeBool 2051 %true = OpConstantTrue %bool 2052 %func_ty = OpTypeFunction %void 2053 %func = OpFunction %void None %func_ty 2054 %1 = OpLabel 2055 OpSelectionMerge %3 None 2056 OpBranchConditional %true %2 %3 2057 %3 = OpLabel 2058 OpReturn 2059 %2 = OpLabel 2060 OpBranch %4 2061 %4 = OpLabel 2062 OpBranch %3 2063 OpFunctionEnd 2064 )"; 2065 2066 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 2067 } 2068 2069 TEST_F(DeadBranchElimTest, ReorderBlocksMultiple2) { 2070 // Checks are not important. The validation post optimization is the 2071 // important part. 2072 const std::string text = R"( 2073 ; CHECK: OpLabel 2074 OpCapability Shader 2075 OpMemoryModel Logical GLSL450 2076 OpEntryPoint Fragment %func "func" 2077 OpExecutionMode %func OriginUpperLeft 2078 %void = OpTypeVoid 2079 %bool = OpTypeBool 2080 %true = OpConstantTrue %bool 2081 %func_ty = OpTypeFunction %void 2082 %func = OpFunction %void None %func_ty 2083 %1 = OpLabel 2084 OpSelectionMerge %3 None 2085 OpBranchConditional %true %2 %3 2086 %3 = OpLabel 2087 OpBranch %5 2088 %5 = OpLabel 2089 OpReturn 2090 %2 = OpLabel 2091 OpBranch %4 2092 %4 = OpLabel 2093 OpBranch %3 2094 OpFunctionEnd 2095 )"; 2096 2097 SinglePassRunAndMatch<DeadBranchElimPass>(text, true); 2098 } 2099 2100 TEST_F(DeadBranchElimTest, SelectionMergeWithEarlyExit1) { 2101 // Checks that if a selection merge construct contains a conditional branch 2102 // to the merge node, then the OpSelectionMerge instruction is positioned 2103 // correctly. 2104 const std::string predefs = R"( 2105 OpCapability Shader 2106 %1 = OpExtInstImport "GLSL.std.450" 2107 OpMemoryModel Logical GLSL450 2108 OpEntryPoint Fragment %main "main" 2109 OpExecutionMode %main OriginUpperLeft 2110 OpSource GLSL 140 2111 %void = OpTypeVoid 2112 %func_type = OpTypeFunction %void 2113 %bool = OpTypeBool 2114 %true = OpConstantTrue %bool 2115 %undef_bool = OpUndef %bool 2116 )"; 2117 2118 const std::string body = 2119 R"( 2120 ; CHECK: OpFunction 2121 ; CHECK-NEXT: OpLabel 2122 ; CHECK-NEXT: OpBranch [[taken_branch:%\w+]] 2123 ; CHECK-NEXT: [[taken_branch]] = OpLabel 2124 ; CHECK-NEXT: OpSelectionMerge [[merge:%\w+]] 2125 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[merge]] {{%\w+}} 2126 %main = OpFunction %void None %func_type 2127 %entry_bb = OpLabel 2128 OpSelectionMerge %outer_merge None 2129 OpBranchConditional %true %bb1 %bb3 2130 %bb1 = OpLabel 2131 OpBranchConditional %undef_bool %outer_merge %bb2 2132 %bb2 = OpLabel 2133 OpBranch %outer_merge 2134 %bb3 = OpLabel 2135 OpBranch %outer_merge 2136 %outer_merge = OpLabel 2137 OpReturn 2138 OpFunctionEnd 2139 )"; 2140 2141 SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true); 2142 } 2143 2144 TEST_F(DeadBranchElimTest, SelectionMergeWithEarlyExit2) { 2145 // Checks that if a selection merge construct contains a conditional branch 2146 // to the merge node, then the OpSelectionMerge instruction is positioned 2147 // correctly. 2148 const std::string predefs = R"( 2149 OpCapability Shader 2150 %1 = OpExtInstImport "GLSL.std.450" 2151 OpMemoryModel Logical GLSL450 2152 OpEntryPoint Fragment %main "main" 2153 OpExecutionMode %main OriginUpperLeft 2154 OpSource GLSL 140 2155 %void = OpTypeVoid 2156 %func_type = OpTypeFunction %void 2157 %bool = OpTypeBool 2158 %true = OpConstantTrue %bool 2159 %undef_bool = OpUndef %bool 2160 )"; 2161 2162 const std::string body = 2163 R"( 2164 ; CHECK: OpFunction 2165 ; CHECK-NEXT: OpLabel 2166 ; CHECK-NEXT: OpBranch [[bb1:%\w+]] 2167 ; CHECK-NEXT: [[bb1]] = OpLabel 2168 ; CHECK-NEXT: OpSelectionMerge [[inner_merge:%\w+]] 2169 ; CHECK: [[inner_merge]] = OpLabel 2170 ; CHECK-NEXT: OpSelectionMerge [[outer_merge:%\w+]] 2171 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[outer_merge]:%\w+]] {{%\w+}} 2172 ; CHECK: [[outer_merge]] = OpLabel 2173 ; CHECK-NEXT: OpReturn 2174 %main = OpFunction %void None %func_type 2175 %entry_bb = OpLabel 2176 OpSelectionMerge %outer_merge None 2177 OpBranchConditional %true %bb1 %bb5 2178 %bb1 = OpLabel 2179 OpSelectionMerge %inner_merge None 2180 OpBranchConditional %undef_bool %bb2 %bb3 2181 %bb2 = OpLabel 2182 OpBranch %inner_merge 2183 %bb3 = OpLabel 2184 OpBranch %inner_merge 2185 %inner_merge = OpLabel 2186 OpBranchConditional %undef_bool %outer_merge %bb4 2187 %bb4 = OpLabel 2188 OpBranch %outer_merge 2189 %bb5 = OpLabel 2190 OpBranch %outer_merge 2191 %outer_merge = OpLabel 2192 OpReturn 2193 OpFunctionEnd 2194 )"; 2195 2196 SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true); 2197 } 2198 2199 TEST_F(DeadBranchElimTest, SelectionMergeWithConditionalExit) { 2200 // Checks that if a selection merge construct contains a conditional branch 2201 // to the merge node, then we keep the OpSelectionMerge on that branch. 2202 const std::string predefs = R"( 2203 OpCapability Shader 2204 %1 = OpExtInstImport "GLSL.std.450" 2205 OpMemoryModel Logical GLSL450 2206 OpEntryPoint Fragment %main "main" 2207 OpExecutionMode %main OriginUpperLeft 2208 OpSource GLSL 140 2209 %void = OpTypeVoid 2210 %func_type = OpTypeFunction %void 2211 %bool = OpTypeBool 2212 %true = OpConstantTrue %bool 2213 %uint = OpTypeInt 32 0 2214 %undef_int = OpUndef %uint 2215 )"; 2216 2217 const std::string body = 2218 R"( 2219 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] 2220 ; CHECK-NEXT: OpBranch [[bb1:%\w+]] 2221 ; CHECK: [[bb1]] = OpLabel 2222 ; CHECK-NEXT: OpBranch [[bb2:%\w+]] 2223 ; CHECK: [[bb2]] = OpLabel 2224 ; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None 2225 ; CHECK-NEXT: OpSwitch {{%\w+}} [[sel_merge]] 1 [[bb3:%\w+]] 2226 ; CHECK: [[bb3]] = OpLabel 2227 ; CHECK-NEXT: OpBranch [[sel_merge]] 2228 ; CHECK: [[sel_merge]] = OpLabel 2229 ; CHECK-NEXT: OpBranch [[loop_merge]] 2230 ; CHECK: [[loop_merge]] = OpLabel 2231 ; CHECK-NEXT: OpReturn 2232 %main = OpFunction %void None %func_type 2233 %entry_bb = OpLabel 2234 OpBranch %loop_header 2235 %loop_header = OpLabel 2236 OpLoopMerge %loop_merge %cont None 2237 OpBranch %bb1 2238 %bb1 = OpLabel 2239 OpSelectionMerge %sel_merge None 2240 OpBranchConditional %true %bb2 %bb4 2241 %bb2 = OpLabel 2242 OpSwitch %undef_int %sel_merge 1 %bb3 2243 %bb3 = OpLabel 2244 OpBranch %sel_merge 2245 %bb4 = OpLabel 2246 OpBranch %sel_merge 2247 %sel_merge = OpLabel 2248 OpBranch %loop_merge 2249 %cont = OpLabel 2250 OpBranch %loop_header 2251 %loop_merge = OpLabel 2252 OpReturn 2253 OpFunctionEnd 2254 )"; 2255 2256 SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true); 2257 } 2258 2259 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop) { 2260 // Checks that if a selection merge construct contains a conditional branch 2261 // to a loop surrounding the selection merge, then we do not keep the 2262 // OpSelectionMerge instruction. 2263 const std::string predefs = R"( 2264 OpCapability Shader 2265 %1 = OpExtInstImport "GLSL.std.450" 2266 OpMemoryModel Logical GLSL450 2267 OpEntryPoint Fragment %main "main" 2268 OpExecutionMode %main OriginUpperLeft 2269 OpSource GLSL 140 2270 %void = OpTypeVoid 2271 %func_type = OpTypeFunction %void 2272 %bool = OpTypeBool 2273 %true = OpConstantTrue %bool 2274 %undef_bool = OpUndef %bool 2275 )"; 2276 2277 const std::string body = 2278 R"( 2279 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] 2280 ; CHECK-NEXT: OpBranch [[bb1:%\w+]] 2281 ; CHECK: [[bb1]] = OpLabel 2282 ; CHECK-NEXT: OpBranch [[bb2:%\w+]] 2283 ; CHECK: [[bb2]] = OpLabel 2284 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_merge]] 2285 ; CHECK: [[bb3]] = OpLabel 2286 ; CHECK-NEXT: OpBranch [[sel_merge:%\w+]] 2287 ; CHECK: [[sel_merge]] = OpLabel 2288 ; CHECK-NEXT: OpBranch [[loop_merge]] 2289 ; CHECK: [[loop_merge]] = OpLabel 2290 ; CHECK-NEXT: OpReturn 2291 %main = OpFunction %void None %func_type 2292 %entry_bb = OpLabel 2293 OpBranch %loop_header 2294 %loop_header = OpLabel 2295 OpLoopMerge %loop_merge %cont None 2296 OpBranch %bb1 2297 %bb1 = OpLabel 2298 OpSelectionMerge %sel_merge None 2299 OpBranchConditional %true %bb2 %bb4 2300 %bb2 = OpLabel 2301 OpBranchConditional %undef_bool %bb3 %loop_merge 2302 %bb3 = OpLabel 2303 OpBranch %sel_merge 2304 %bb4 = OpLabel 2305 OpBranch %sel_merge 2306 %sel_merge = OpLabel 2307 OpBranch %loop_merge 2308 %cont = OpLabel 2309 OpBranch %loop_header 2310 %loop_merge = OpLabel 2311 OpReturn 2312 OpFunctionEnd 2313 )"; 2314 2315 SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true); 2316 } 2317 2318 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue) { 2319 // Checks that if a selection merge construct contains a conditional branch 2320 // to continue of a loop surrounding the selection merge, then we do not keep 2321 // the OpSelectionMerge instruction. 2322 const std::string predefs = R"( 2323 OpCapability Shader 2324 %1 = OpExtInstImport "GLSL.std.450" 2325 OpMemoryModel Logical GLSL450 2326 OpEntryPoint Fragment %main "main" 2327 OpExecutionMode %main OriginUpperLeft 2328 OpSource GLSL 140 2329 %void = OpTypeVoid 2330 %func_type = OpTypeFunction %void 2331 %bool = OpTypeBool 2332 %true = OpConstantTrue %bool 2333 %undef_bool = OpUndef %bool 2334 )"; 2335 2336 const std::string body = 2337 R"(; 2338 ; CHECK: OpLabel 2339 ; CHECK: [[loop_header:%\w+]] = OpLabel 2340 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]] 2341 ; CHECK-NEXT: OpBranch [[bb1:%\w+]] 2342 ; CHECK: [[bb1]] = OpLabel 2343 ; CHECK-NEXT: OpBranch [[bb2:%\w+]] 2344 ; CHECK: [[bb2]] = OpLabel 2345 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_cont]] 2346 ; CHECK: [[bb3]] = OpLabel 2347 ; CHECK-NEXT: OpBranch [[sel_merge:%\w+]] 2348 ; CHECK: [[sel_merge]] = OpLabel 2349 ; CHECK-NEXT: OpBranch [[loop_merge]] 2350 ; CHECK: [[loop_cont]] = OpLabel 2351 ; CHECK-NEXT: OpBranch [[loop_header]] 2352 ; CHECK: [[loop_merge]] = OpLabel 2353 ; CHECK-NEXT: OpReturn 2354 %main = OpFunction %void None %func_type 2355 %entry_bb = OpLabel 2356 OpBranch %loop_header 2357 %loop_header = OpLabel 2358 OpLoopMerge %loop_merge %cont None 2359 OpBranch %bb1 2360 %bb1 = OpLabel 2361 OpSelectionMerge %sel_merge None 2362 OpBranchConditional %true %bb2 %bb4 2363 %bb2 = OpLabel 2364 OpBranchConditional %undef_bool %bb3 %cont 2365 %bb3 = OpLabel 2366 OpBranch %sel_merge 2367 %bb4 = OpLabel 2368 OpBranch %sel_merge 2369 %sel_merge = OpLabel 2370 OpBranch %loop_merge 2371 %cont = OpLabel 2372 OpBranch %loop_header 2373 %loop_merge = OpLabel 2374 OpReturn 2375 OpFunctionEnd 2376 )"; 2377 2378 SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true); 2379 } 2380 2381 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop2) { 2382 // Same as |SelectionMergeWithExitToLoop|, except the switch goes to the loop 2383 // merge or the selection merge. In this case, we do not need an 2384 // OpSelectionMerge either. 2385 const std::string predefs = R"( 2386 OpCapability Shader 2387 %1 = OpExtInstImport "GLSL.std.450" 2388 OpMemoryModel Logical GLSL450 2389 OpEntryPoint Fragment %main "main" 2390 OpExecutionMode %main OriginUpperLeft 2391 OpSource GLSL 140 2392 %void = OpTypeVoid 2393 %func_type = OpTypeFunction %void 2394 %bool = OpTypeBool 2395 %true = OpConstantTrue %bool 2396 %undef_bool = OpUndef %bool 2397 )"; 2398 2399 const std::string body = 2400 R"( 2401 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] 2402 ; CHECK-NEXT: OpBranch [[bb1:%\w+]] 2403 ; CHECK: [[bb1]] = OpLabel 2404 ; CHECK-NEXT: OpBranch [[bb2:%\w+]] 2405 ; CHECK: [[bb2]] = OpLabel 2406 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[sel_merge:%\w+]] [[loop_merge]] 2407 ; CHECK: [[sel_merge]] = OpLabel 2408 ; CHECK-NEXT: OpBranch [[loop_merge]] 2409 ; CHECK: [[loop_merge]] = OpLabel 2410 ; CHECK-NEXT: OpReturn 2411 %main = OpFunction %void None %func_type 2412 %entry_bb = OpLabel 2413 OpBranch %loop_header 2414 %loop_header = OpLabel 2415 OpLoopMerge %loop_merge %cont None 2416 OpBranch %bb1 2417 %bb1 = OpLabel 2418 OpSelectionMerge %sel_merge None 2419 OpBranchConditional %true %bb2 %bb4 2420 %bb2 = OpLabel 2421 OpBranchConditional %undef_bool %sel_merge %loop_merge 2422 %bb4 = OpLabel 2423 OpBranch %sel_merge 2424 %sel_merge = OpLabel 2425 OpBranch %loop_merge 2426 %cont = OpLabel 2427 OpBranch %loop_header 2428 %loop_merge = OpLabel 2429 OpReturn 2430 OpFunctionEnd 2431 )"; 2432 2433 SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true); 2434 } 2435 2436 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue2) { 2437 // Same as |SelectionMergeWithExitToLoopContinue|, except the branch goes to 2438 // the loop continue or the selection merge. In this case, we do not need an 2439 // OpSelectionMerge either. 2440 const std::string predefs = R"( 2441 OpCapability Shader 2442 %1 = OpExtInstImport "GLSL.std.450" 2443 OpMemoryModel Logical GLSL450 2444 OpEntryPoint Fragment %main "main" 2445 OpExecutionMode %main OriginUpperLeft 2446 OpSource GLSL 140 2447 %void = OpTypeVoid 2448 %func_type = OpTypeFunction %void 2449 %bool = OpTypeBool 2450 %true = OpConstantTrue %bool 2451 %undef_bool = OpUndef %bool 2452 )"; 2453 2454 const std::string body = 2455 R"( 2456 ; CHECK: OpLabel 2457 ; CHECK: [[loop_header:%\w+]] = OpLabel 2458 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]] 2459 ; CHECK-NEXT: OpBranch [[bb1:%\w+]] 2460 ; CHECK: [[bb1]] = OpLabel 2461 ; CHECK-NEXT: OpBranch [[bb2:%\w+]] 2462 ; CHECK: [[bb2]] = OpLabel 2463 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[sel_merge:%\w+]] [[loop_cont]] 2464 ; CHECK: [[sel_merge]] = OpLabel 2465 ; CHECK-NEXT: OpBranch [[loop_merge]] 2466 ; CHECK: [[loop_cont]] = OpLabel 2467 ; CHECK: OpBranch [[loop_header]] 2468 ; CHECK: [[loop_merge]] = OpLabel 2469 ; CHECK-NEXT: OpReturn 2470 %main = OpFunction %void None %func_type 2471 %entry_bb = OpLabel 2472 OpBranch %loop_header 2473 %loop_header = OpLabel 2474 OpLoopMerge %loop_merge %cont None 2475 OpBranch %bb1 2476 %bb1 = OpLabel 2477 OpSelectionMerge %sel_merge None 2478 OpBranchConditional %true %bb2 %bb4 2479 %bb2 = OpLabel 2480 OpBranchConditional %undef_bool %sel_merge %cont 2481 %bb4 = OpLabel 2482 OpBranch %sel_merge 2483 %sel_merge = OpLabel 2484 OpBranch %loop_merge 2485 %cont = OpLabel 2486 OpBranch %loop_header 2487 %loop_merge = OpLabel 2488 OpReturn 2489 OpFunctionEnd 2490 )"; 2491 2492 SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true); 2493 } 2494 2495 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop3) { 2496 // Checks that if a selection merge construct contains a conditional branch 2497 // to the merge of a surrounding loop, the selection merge, and another block 2498 // inside the selection merge, then we must keep the OpSelectionMerge 2499 // instruction on that branch. 2500 const std::string predefs = R"( 2501 OpCapability Shader 2502 %1 = OpExtInstImport "GLSL.std.450" 2503 OpMemoryModel Logical GLSL450 2504 OpEntryPoint Fragment %main "main" 2505 OpExecutionMode %main OriginUpperLeft 2506 OpSource GLSL 140 2507 %void = OpTypeVoid 2508 %func_type = OpTypeFunction %void 2509 %bool = OpTypeBool 2510 %true = OpConstantTrue %bool 2511 %uint = OpTypeInt 32 0 2512 %undef_int = OpUndef %uint 2513 )"; 2514 2515 const std::string body = 2516 R"( 2517 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] 2518 ; CHECK-NEXT: OpBranch [[bb1:%\w+]] 2519 ; CHECK: [[bb1]] = OpLabel 2520 ; CHECK-NEXT: OpBranch [[bb2:%\w+]] 2521 ; CHECK: [[bb2]] = OpLabel 2522 ; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None 2523 ; CHECK-NEXT: OpSwitch {{%\w+}} [[sel_merge]] 0 [[loop_merge]] 1 [[bb3:%\w+]] 2524 ; CHECK: [[bb3]] = OpLabel 2525 ; CHECK-NEXT: OpBranch [[sel_merge]] 2526 ; CHECK: [[sel_merge]] = OpLabel 2527 ; CHECK-NEXT: OpBranch [[loop_merge]] 2528 ; CHECK: [[loop_merge]] = OpLabel 2529 ; CHECK-NEXT: OpReturn 2530 %main = OpFunction %void None %func_type 2531 %entry_bb = OpLabel 2532 OpBranch %loop_header 2533 %loop_header = OpLabel 2534 OpLoopMerge %loop_merge %cont None 2535 OpBranch %bb1 2536 %bb1 = OpLabel 2537 OpSelectionMerge %sel_merge None 2538 OpBranchConditional %true %bb2 %bb4 2539 %bb2 = OpLabel 2540 OpSwitch %undef_int %sel_merge 0 %loop_merge 1 %bb3 2541 %bb3 = OpLabel 2542 OpBranch %sel_merge 2543 %bb4 = OpLabel 2544 OpBranch %sel_merge 2545 %sel_merge = OpLabel 2546 OpBranch %loop_merge 2547 %cont = OpLabel 2548 OpBranch %loop_header 2549 %loop_merge = OpLabel 2550 OpReturn 2551 OpFunctionEnd 2552 )"; 2553 2554 SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true); 2555 } 2556 2557 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue3) { 2558 // Checks that if a selection merge construct contains a conditional branch 2559 // to the merge of a surrounding loop, the selection merge, and another block 2560 // inside the selection merge, then we must keep the OpSelectionMerge 2561 // instruction on that branch. 2562 const std::string predefs = R"( 2563 OpCapability Shader 2564 %1 = OpExtInstImport "GLSL.std.450" 2565 OpMemoryModel Logical GLSL450 2566 OpEntryPoint Fragment %main "main" 2567 OpExecutionMode %main OriginUpperLeft 2568 OpSource GLSL 140 2569 %void = OpTypeVoid 2570 %func_type = OpTypeFunction %void 2571 %bool = OpTypeBool 2572 %true = OpConstantTrue %bool 2573 %uint = OpTypeInt 32 0 2574 %undef_int = OpUndef %uint 2575 )"; 2576 2577 const std::string body = 2578 R"( 2579 ; CHECK: OpLabel 2580 ; CHECK: [[loop_header:%\w+]] = OpLabel 2581 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_continue:%\w+]] 2582 ; CHECK-NEXT: OpBranch [[bb1:%\w+]] 2583 ; CHECK: [[bb1]] = OpLabel 2584 ; CHECK-NEXT: OpBranch [[bb2:%\w+]] 2585 ; CHECK: [[bb2]] = OpLabel 2586 ; CHECK-NEXT: OpSelectionMerge [[sel_merge:%\w+]] None 2587 ; CHECK-NEXT: OpSwitch {{%\w+}} [[sel_merge]] 0 [[loop_continue]] 1 [[bb3:%\w+]] 2588 ; CHECK: [[bb3]] = OpLabel 2589 ; CHECK-NEXT: OpBranch [[sel_merge]] 2590 ; CHECK: [[sel_merge]] = OpLabel 2591 ; CHECK-NEXT: OpBranch [[loop_merge]] 2592 ; CHECK: [[loop_continue]] = OpLabel 2593 ; CHECK-NEXT: OpBranch [[loop_header]] 2594 ; CHECK: [[loop_merge]] = OpLabel 2595 ; CHECK-NEXT: OpReturn 2596 %main = OpFunction %void None %func_type 2597 %entry_bb = OpLabel 2598 OpBranch %loop_header 2599 %loop_header = OpLabel 2600 OpLoopMerge %loop_merge %cont None 2601 OpBranch %bb1 2602 %bb1 = OpLabel 2603 OpSelectionMerge %sel_merge None 2604 OpBranchConditional %true %bb2 %bb4 2605 %bb2 = OpLabel 2606 OpSwitch %undef_int %sel_merge 0 %cont 1 %bb3 2607 %bb3 = OpLabel 2608 OpBranch %sel_merge 2609 %bb4 = OpLabel 2610 OpBranch %sel_merge 2611 %sel_merge = OpLabel 2612 OpBranch %loop_merge 2613 %cont = OpLabel 2614 OpBranch %loop_header 2615 %loop_merge = OpLabel 2616 OpReturn 2617 OpFunctionEnd 2618 )"; 2619 2620 SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true); 2621 } 2622 2623 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoop4) { 2624 // Same as |SelectionMergeWithExitToLoop|, except the branch in the selection 2625 // construct is an |OpSwitch| instead of an |OpConditionalBranch|. The 2626 // OpSelectionMerge instruction is not needed in this case either. 2627 const std::string predefs = R"( 2628 OpCapability Shader 2629 %1 = OpExtInstImport "GLSL.std.450" 2630 OpMemoryModel Logical GLSL450 2631 OpEntryPoint Fragment %main "main" 2632 OpExecutionMode %main OriginUpperLeft 2633 OpSource GLSL 140 2634 %void = OpTypeVoid 2635 %func_type = OpTypeFunction %void 2636 %bool = OpTypeBool 2637 %true = OpConstantTrue %bool 2638 %uint = OpTypeInt 32 0 2639 %undef_int = OpUndef %uint 2640 )"; 2641 2642 const std::string body = 2643 R"( 2644 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] 2645 ; CHECK-NEXT: OpBranch [[bb1:%\w+]] 2646 ; CHECK: [[bb1]] = OpLabel 2647 ; CHECK-NEXT: OpBranch [[bb2:%\w+]] 2648 ; CHECK: [[bb2]] = OpLabel 2649 ; CHECK-NEXT: OpSwitch {{%\w+}} [[bb3:%\w+]] 0 [[loop_merge]] 1 [[bb3:%\w+]] 2650 ; CHECK: [[bb3]] = OpLabel 2651 ; CHECK-NEXT: OpBranch [[sel_merge:%\w+]] 2652 ; CHECK: [[sel_merge]] = OpLabel 2653 ; CHECK-NEXT: OpBranch [[loop_merge]] 2654 ; CHECK: [[loop_merge]] = OpLabel 2655 ; CHECK-NEXT: OpReturn 2656 %main = OpFunction %void None %func_type 2657 %entry_bb = OpLabel 2658 OpBranch %loop_header 2659 %loop_header = OpLabel 2660 OpLoopMerge %loop_merge %cont None 2661 OpBranch %bb1 2662 %bb1 = OpLabel 2663 OpSelectionMerge %sel_merge None 2664 OpBranchConditional %true %bb2 %bb4 2665 %bb2 = OpLabel 2666 OpSwitch %undef_int %bb3 0 %loop_merge 1 %bb3 2667 %bb3 = OpLabel 2668 OpBranch %sel_merge 2669 %bb4 = OpLabel 2670 OpBranch %sel_merge 2671 %sel_merge = OpLabel 2672 OpBranch %loop_merge 2673 %cont = OpLabel 2674 OpBranch %loop_header 2675 %loop_merge = OpLabel 2676 OpReturn 2677 OpFunctionEnd 2678 )"; 2679 2680 SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true); 2681 } 2682 2683 TEST_F(DeadBranchElimTest, SelectionMergeWithExitToLoopContinue4) { 2684 // Same as |SelectionMergeWithExitToLoopContinue|, except the branch in the 2685 // selection construct is an |OpSwitch| instead of an |OpConditionalBranch|. 2686 // The OpSelectionMerge instruction is not needed in this case either. 2687 const std::string predefs = R"( 2688 OpCapability Shader 2689 %1 = OpExtInstImport "GLSL.std.450" 2690 OpMemoryModel Logical GLSL450 2691 OpEntryPoint Fragment %main "main" 2692 OpExecutionMode %main OriginUpperLeft 2693 OpSource GLSL 140 2694 %void = OpTypeVoid 2695 %func_type = OpTypeFunction %void 2696 %bool = OpTypeBool 2697 %true = OpConstantTrue %bool 2698 %uint = OpTypeInt 32 0 2699 %undef_int = OpUndef %uint 2700 )"; 2701 2702 const std::string body = 2703 R"( 2704 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]] 2705 ; CHECK-NEXT: OpBranch [[bb1:%\w+]] 2706 ; CHECK: [[bb1]] = OpLabel 2707 ; CHECK-NEXT: OpBranch [[bb2:%\w+]] 2708 ; CHECK: [[bb2]] = OpLabel 2709 ; CHECK-NEXT: OpSwitch {{%\w+}} [[bb3:%\w+]] 0 [[loop_cont]] 1 [[bb3:%\w+]] 2710 ; CHECK: [[bb3]] = OpLabel 2711 ; CHECK-NEXT: OpBranch [[sel_merge:%\w+]] 2712 ; CHECK: [[sel_merge]] = OpLabel 2713 ; CHECK-NEXT: OpBranch [[loop_merge]] 2714 ; CHECK: [[loop_merge]] = OpLabel 2715 ; CHECK-NEXT: OpReturn 2716 %main = OpFunction %void None %func_type 2717 %entry_bb = OpLabel 2718 OpBranch %loop_header 2719 %loop_header = OpLabel 2720 OpLoopMerge %loop_merge %cont None 2721 OpBranch %bb1 2722 %bb1 = OpLabel 2723 OpSelectionMerge %sel_merge None 2724 OpBranchConditional %true %bb2 %bb4 2725 %bb2 = OpLabel 2726 OpSwitch %undef_int %bb3 0 %cont 1 %bb3 2727 %bb3 = OpLabel 2728 OpBranch %sel_merge 2729 %bb4 = OpLabel 2730 OpBranch %sel_merge 2731 %sel_merge = OpLabel 2732 OpBranch %loop_merge 2733 %cont = OpLabel 2734 OpBranch %loop_header 2735 %loop_merge = OpLabel 2736 OpReturn 2737 OpFunctionEnd 2738 )"; 2739 2740 SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true); 2741 } 2742 2743 TEST_F(DeadBranchElimTest, SelectionMergeSameAsLoopContinue) { 2744 // Same as |SelectionMergeWithExitToLoopContinue|, except the branch in the 2745 // selection construct is an |OpSwitch| instead of an |OpConditionalBranch|. 2746 // The OpSelectionMerge instruction is not needed in this case either. 2747 const std::string predefs = R"( 2748 OpCapability Shader 2749 %1 = OpExtInstImport "GLSL.std.450" 2750 OpMemoryModel Logical GLSL450 2751 OpEntryPoint Fragment %main "main" 2752 OpExecutionMode %main OriginUpperLeft 2753 OpSource GLSL 140 2754 %void = OpTypeVoid 2755 %func_type = OpTypeFunction %void 2756 %bool = OpTypeBool 2757 %true = OpConstantTrue %bool 2758 %uint = OpTypeInt 32 0 2759 %undef_bool = OpUndef %bool 2760 )"; 2761 2762 const std::string body = 2763 R"( 2764 ; CHECK: OpLabel 2765 ; CHECK: [[loop_header:%\w+]] = OpLabel 2766 ; CHECK: OpLoopMerge [[loop_merge:%\w+]] [[loop_cont:%\w+]] 2767 ; CHECK-NEXT: OpBranch [[bb1:%\w+]] 2768 ; CHECK: [[bb1]] = OpLabel 2769 ; CHECK-NEXT: OpBranch [[bb2:%\w+]] 2770 ; CHECK: [[bb2]] = OpLabel 2771 ; CHECK-NEXT: OpSelectionMerge [[loop_cont]] 2772 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[bb3:%\w+]] [[loop_cont]] 2773 ; CHECK: [[bb3]] = OpLabel 2774 ; CHECK-NEXT: OpBranch [[loop_cont]] 2775 ; CHECK: [[loop_cont]] = OpLabel 2776 ; CHECK-NEXT: OpBranchConditional {{%\w+}} [[loop_header]] [[loop_merge]] 2777 ; CHECK: [[loop_merge]] = OpLabel 2778 ; CHECK-NEXT: OpReturn 2779 %main = OpFunction %void None %func_type 2780 %entry_bb = OpLabel 2781 OpBranch %loop_header 2782 %loop_header = OpLabel 2783 OpLoopMerge %loop_merge %cont None 2784 OpBranch %bb1 2785 %bb1 = OpLabel 2786 OpSelectionMerge %cont None 2787 OpBranchConditional %true %bb2 %bb4 2788 %bb2 = OpLabel 2789 OpBranchConditional %undef_bool %bb3 %cont 2790 %bb3 = OpLabel 2791 OpBranch %cont 2792 %bb4 = OpLabel 2793 OpBranch %cont 2794 %cont = OpLabel 2795 OpBranchConditional %undef_bool %loop_header %loop_merge 2796 %loop_merge = OpLabel 2797 OpReturn 2798 OpFunctionEnd 2799 )"; 2800 2801 SinglePassRunAndMatch<DeadBranchElimPass>(predefs + body, true); 2802 } 2803 2804 TEST_F(DeadBranchElimTest, SelectionMergeWithNestedLoop) { 2805 const std::string body = 2806 R"( 2807 ; CHECK: OpSelectionMerge [[merge1:%\w+]] 2808 ; CHECK: [[merge1]] = OpLabel 2809 ; CHECK-NEXT: OpBranch [[preheader:%\w+]] 2810 ; CHECK: [[preheader]] = OpLabel 2811 ; CHECK-NOT: OpLabel 2812 ; CHECK: OpBranch [[header:%\w+]] 2813 ; CHECK: [[header]] = OpLabel 2814 ; CHECK-NOT: OpLabel 2815 ; CHECK: OpLoopMerge [[merge2:%\w+]] 2816 ; CHECK: [[merge2]] = OpLabel 2817 ; CHECK-NEXT: OpUnreachable 2818 OpCapability Shader 2819 %1 = OpExtInstImport "GLSL.std.450" 2820 OpMemoryModel Logical GLSL450 2821 OpEntryPoint Fragment %main "main" 2822 OpExecutionMode %main OriginUpperLeft 2823 OpSource ESSL 310 2824 OpName %main "main" 2825 OpName %h "h" 2826 OpName %i "i" 2827 %void = OpTypeVoid 2828 %3 = OpTypeFunction %void 2829 %bool = OpTypeBool 2830 %_ptr_Function_bool = OpTypePointer Function %bool 2831 %true = OpConstantTrue %bool 2832 %int = OpTypeInt 32 1 2833 %_ptr_Function_int = OpTypePointer Function %int 2834 %int_1 = OpConstant %int 1 2835 %int_0 = OpConstant %int 0 2836 %27 = OpUndef %bool 2837 %main = OpFunction %void None %3 2838 %5 = OpLabel 2839 %h = OpVariable %_ptr_Function_bool Function 2840 %i = OpVariable %_ptr_Function_int Function 2841 OpSelectionMerge %11 None 2842 OpBranchConditional %27 %10 %11 2843 %10 = OpLabel 2844 OpBranch %11 2845 %11 = OpLabel 2846 OpSelectionMerge %14 None 2847 OpBranchConditional %true %13 %14 2848 %13 = OpLabel 2849 OpStore %i %int_1 2850 OpBranch %19 2851 %19 = OpLabel 2852 OpLoopMerge %21 %22 None 2853 OpBranch %23 2854 %23 = OpLabel 2855 %26 = OpSGreaterThan %bool %int_1 %int_0 2856 OpBranchConditional %true %20 %21 2857 %20 = OpLabel 2858 OpBranch %22 2859 %22 = OpLabel 2860 OpBranch %19 2861 %21 = OpLabel 2862 OpBranch %14 2863 %14 = OpLabel 2864 OpReturn 2865 OpFunctionEnd 2866 )"; 2867 2868 SinglePassRunAndMatch<DeadBranchElimPass>(body, true); 2869 } 2870 2871 // TODO(greg-lunarg): Add tests to verify handling of these cases: 2872 // 2873 // More complex control flow 2874 // Others? 2875 2876 } // namespace 2877 } // namespace opt 2878 } // namespace spvtools 2879