1 // Copyright (c) 2018 Google LLC. 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 <memory> 16 #include <string> 17 #include <vector> 18 19 #include "gmock/gmock.h" 20 #include "source/opt/loop_fission.h" 21 #include "source/opt/loop_unroller.h" 22 #include "source/opt/loop_utils.h" 23 #include "source/opt/pass.h" 24 #include "test/opt/assembly_builder.h" 25 #include "test/opt/function_utils.h" 26 #include "test/opt/pass_fixture.h" 27 #include "test/opt/pass_utils.h" 28 29 namespace spvtools { 30 namespace opt { 31 namespace { 32 33 using ::testing::UnorderedElementsAre; 34 using FissionClassTest = PassTest<::testing::Test>; 35 36 /* 37 Generated from the following GLSL 38 39 #version 430 40 41 void main(void) { 42 float A[10]; 43 float B[10]; 44 for (int i = 0; i < 10; i++) { 45 A[i] = B[i]; 46 B[i] = A[i]; 47 } 48 } 49 50 Result should be equivalent to: 51 52 void main(void) { 53 float A[10]; 54 float B[10]; 55 for (int i = 0; i < 10; i++) { 56 A[i] = B[i]; 57 } 58 59 for (int i = 0; i < 10; i++) { 60 B[i] = A[i]; 61 } 62 } 63 */ 64 TEST_F(FissionClassTest, SimpleFission) { 65 // clang-format off 66 // With LocalMultiStoreElimPass 67 const std::string source = R"(OpCapability Shader 68 %1 = OpExtInstImport "GLSL.std.450" 69 OpMemoryModel Logical GLSL450 70 OpEntryPoint Fragment %2 "main" 71 OpExecutionMode %2 OriginUpperLeft 72 OpSource GLSL 430 73 OpName %2 "main" 74 OpName %3 "i" 75 OpName %4 "A" 76 OpName %5 "B" 77 %6 = OpTypeVoid 78 %7 = OpTypeFunction %6 79 %8 = OpTypeInt 32 1 80 %9 = OpTypePointer Function %8 81 %10 = OpConstant %8 0 82 %11 = OpConstant %8 10 83 %12 = OpTypeBool 84 %13 = OpTypeFloat 32 85 %14 = OpTypeInt 32 0 86 %15 = OpConstant %14 10 87 %16 = OpTypeArray %13 %15 88 %17 = OpTypePointer Function %16 89 %18 = OpTypePointer Function %13 90 %19 = OpConstant %8 1 91 %2 = OpFunction %6 None %7 92 %20 = OpLabel 93 %3 = OpVariable %9 Function 94 %4 = OpVariable %17 Function 95 %5 = OpVariable %17 Function 96 OpBranch %21 97 %21 = OpLabel 98 %22 = OpPhi %8 %10 %20 %23 %24 99 OpLoopMerge %25 %24 None 100 OpBranch %26 101 %26 = OpLabel 102 %27 = OpSLessThan %12 %22 %11 103 OpBranchConditional %27 %28 %25 104 %28 = OpLabel 105 %29 = OpAccessChain %18 %5 %22 106 %30 = OpLoad %13 %29 107 %31 = OpAccessChain %18 %4 %22 108 OpStore %31 %30 109 %32 = OpAccessChain %18 %4 %22 110 %33 = OpLoad %13 %32 111 %34 = OpAccessChain %18 %5 %22 112 OpStore %34 %33 113 OpBranch %24 114 %24 = OpLabel 115 %23 = OpIAdd %8 %22 %19 116 OpBranch %21 117 %25 = OpLabel 118 OpReturn 119 OpFunctionEnd 120 )"; 121 122 const std::string expected = R"(OpCapability Shader 123 %1 = OpExtInstImport "GLSL.std.450" 124 OpMemoryModel Logical GLSL450 125 OpEntryPoint Fragment %2 "main" 126 OpExecutionMode %2 OriginUpperLeft 127 OpSource GLSL 430 128 OpName %2 "main" 129 OpName %3 "i" 130 OpName %4 "A" 131 OpName %5 "B" 132 %6 = OpTypeVoid 133 %7 = OpTypeFunction %6 134 %8 = OpTypeInt 32 1 135 %9 = OpTypePointer Function %8 136 %10 = OpConstant %8 0 137 %11 = OpConstant %8 10 138 %12 = OpTypeBool 139 %13 = OpTypeFloat 32 140 %14 = OpTypeInt 32 0 141 %15 = OpConstant %14 10 142 %16 = OpTypeArray %13 %15 143 %17 = OpTypePointer Function %16 144 %18 = OpTypePointer Function %13 145 %19 = OpConstant %8 1 146 %2 = OpFunction %6 None %7 147 %20 = OpLabel 148 %3 = OpVariable %9 Function 149 %4 = OpVariable %17 Function 150 %5 = OpVariable %17 Function 151 OpBranch %35 152 %35 = OpLabel 153 %36 = OpPhi %8 %10 %20 %47 %46 154 OpLoopMerge %48 %46 None 155 OpBranch %37 156 %37 = OpLabel 157 %38 = OpSLessThan %12 %36 %11 158 OpBranchConditional %38 %39 %48 159 %39 = OpLabel 160 %40 = OpAccessChain %18 %5 %36 161 %41 = OpLoad %13 %40 162 %42 = OpAccessChain %18 %4 %36 163 OpStore %42 %41 164 OpBranch %46 165 %46 = OpLabel 166 %47 = OpIAdd %8 %36 %19 167 OpBranch %35 168 %48 = OpLabel 169 OpBranch %21 170 %21 = OpLabel 171 %22 = OpPhi %8 %10 %48 %23 %24 172 OpLoopMerge %25 %24 None 173 OpBranch %26 174 %26 = OpLabel 175 %27 = OpSLessThan %12 %22 %11 176 OpBranchConditional %27 %28 %25 177 %28 = OpLabel 178 %32 = OpAccessChain %18 %4 %22 179 %33 = OpLoad %13 %32 180 %34 = OpAccessChain %18 %5 %22 181 OpStore %34 %33 182 OpBranch %24 183 %24 = OpLabel 184 %23 = OpIAdd %8 %22 %19 185 OpBranch %21 186 %25 = OpLabel 187 OpReturn 188 OpFunctionEnd 189 )"; 190 // clang-format on 191 std::unique_ptr<IRContext> context = 192 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 193 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 194 Module* module = context->module(); 195 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 196 << source << std::endl; 197 198 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 199 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true); 200 201 // Check that the loop will NOT be split when provided with a pass-through 202 // register pressure functor which just returns false. 203 SinglePassRunAndCheck<LoopFissionPass>( 204 source, source, true, 205 [](const RegisterLiveness::RegionRegisterLiveness&) { return false; }); 206 } 207 208 /* 209 Generated from the following GLSL 210 211 #version 430 212 213 void main(void) { 214 float A[10]; 215 float B[10]; 216 for (int i = 0; i < 10; i++) { 217 A[i] = B[i]; 218 B[i] = A[i+1]; 219 } 220 } 221 222 This loop should not be split, as the i+1 dependence would be broken by 223 splitting the loop. 224 */ 225 226 TEST_F(FissionClassTest, FissionInterdependency) { 227 // clang-format off 228 // With LocalMultiStoreElimPass 229 const std::string source = R"(OpCapability Shader 230 %1 = OpExtInstImport "GLSL.std.450" 231 OpMemoryModel Logical GLSL450 232 OpEntryPoint Fragment %2 "main" 233 OpExecutionMode %2 OriginUpperLeft 234 OpSource GLSL 430 235 OpName %2 "main" 236 OpName %3 "i" 237 OpName %4 "A" 238 OpName %5 "B" 239 %6 = OpTypeVoid 240 %7 = OpTypeFunction %6 241 %8 = OpTypeInt 32 1 242 %9 = OpTypePointer Function %8 243 %10 = OpConstant %8 0 244 %11 = OpConstant %8 10 245 %12 = OpTypeBool 246 %13 = OpTypeFloat 32 247 %14 = OpTypeInt 32 0 248 %15 = OpConstant %14 10 249 %16 = OpTypeArray %13 %15 250 %17 = OpTypePointer Function %16 251 %18 = OpTypePointer Function %13 252 %19 = OpConstant %8 1 253 %2 = OpFunction %6 None %7 254 %20 = OpLabel 255 %3 = OpVariable %9 Function 256 %4 = OpVariable %17 Function 257 %5 = OpVariable %17 Function 258 OpBranch %21 259 %21 = OpLabel 260 %22 = OpPhi %8 %10 %20 %23 %24 261 OpLoopMerge %25 %24 None 262 OpBranch %26 263 %26 = OpLabel 264 %27 = OpSLessThan %12 %22 %11 265 OpBranchConditional %27 %28 %25 266 %28 = OpLabel 267 %29 = OpAccessChain %18 %5 %22 268 %30 = OpLoad %13 %29 269 %31 = OpAccessChain %18 %4 %22 270 OpStore %31 %30 271 %32 = OpIAdd %8 %22 %19 272 %33 = OpAccessChain %18 %4 %32 273 %34 = OpLoad %13 %33 274 %35 = OpAccessChain %18 %5 %22 275 OpStore %35 %34 276 OpBranch %24 277 %24 = OpLabel 278 %23 = OpIAdd %8 %22 %19 279 OpBranch %21 280 %25 = OpLabel 281 OpReturn 282 OpFunctionEnd 283 )"; 284 // clang-format on 285 std::unique_ptr<IRContext> context = 286 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 287 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 288 Module* module = context->module(); 289 EXPECT_NE(nullptr, module) << "Assembling failed for ushader:\n" 290 << source << std::endl; 291 292 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 293 SinglePassRunAndCheck<LoopFissionPass>(source, source, true); 294 } 295 296 /* 297 Generated from the following GLSL 298 299 #version 430 300 301 void main(void) { 302 float A[10]; 303 float B[10]; 304 for (int i = 0; i < 10; i++) { 305 A[i] = B[i]; 306 B[i+1] = A[i]; 307 } 308 } 309 310 311 This should not be split as the load B[i] is dependent on the store B[i+1] 312 */ 313 TEST_F(FissionClassTest, FissionInterdependency2) { 314 // clang-format off 315 // With LocalMultiStoreElimPass 316 const std::string source = R"(OpCapability Shader 317 %1 = OpExtInstImport "GLSL.std.450" 318 OpMemoryModel Logical GLSL450 319 OpEntryPoint Fragment %2 "main" 320 OpExecutionMode %2 OriginUpperLeft 321 OpSource GLSL 430 322 OpName %2 "main" 323 OpName %3 "i" 324 OpName %4 "A" 325 OpName %5 "B" 326 %6 = OpTypeVoid 327 %7 = OpTypeFunction %6 328 %8 = OpTypeInt 32 1 329 %9 = OpTypePointer Function %8 330 %10 = OpConstant %8 0 331 %11 = OpConstant %8 10 332 %12 = OpTypeBool 333 %13 = OpTypeFloat 32 334 %14 = OpTypeInt 32 0 335 %15 = OpConstant %14 10 336 %16 = OpTypeArray %13 %15 337 %17 = OpTypePointer Function %16 338 %18 = OpTypePointer Function %13 339 %19 = OpConstant %8 1 340 %2 = OpFunction %6 None %7 341 %20 = OpLabel 342 %3 = OpVariable %9 Function 343 %4 = OpVariable %17 Function 344 %5 = OpVariable %17 Function 345 OpBranch %21 346 %21 = OpLabel 347 %22 = OpPhi %8 %10 %20 %23 %24 348 OpLoopMerge %25 %24 None 349 OpBranch %26 350 %26 = OpLabel 351 %27 = OpSLessThan %12 %22 %11 352 OpBranchConditional %27 %28 %25 353 %28 = OpLabel 354 %29 = OpAccessChain %18 %5 %22 355 %30 = OpLoad %13 %29 356 %31 = OpAccessChain %18 %4 %22 357 OpStore %31 %30 358 %32 = OpIAdd %8 %22 %19 359 %33 = OpAccessChain %18 %4 %22 360 %34 = OpLoad %13 %33 361 %35 = OpAccessChain %18 %5 %32 362 OpStore %35 %34 363 OpBranch %24 364 %24 = OpLabel 365 %23 = OpIAdd %8 %22 %19 366 OpBranch %21 367 %25 = OpLabel 368 OpReturn 369 OpFunctionEnd 370 )"; 371 // clang-format on 372 std::unique_ptr<IRContext> context = 373 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 374 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 375 Module* module = context->module(); 376 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 377 << source << std::endl; 378 379 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 380 SinglePassRunAndCheck<LoopFissionPass>(source, source, true); 381 } 382 383 /* 384 #version 430 385 void main(void) { 386 float A[10]; 387 float B[10]; 388 float C[10] 389 float D[10] 390 for (int i = 0; i < 10; i++) { 391 A[i] = B[i]; 392 B[i] = A[i]; 393 C[i] = D[i]; 394 D[i] = C[i]; 395 } 396 } 397 398 This should be split into the equivalent of: 399 400 for (int i = 0; i < 10; i++) { 401 A[i] = B[i]; 402 B[i] = A[i]; 403 } 404 for (int i = 0; i < 10; i++) { 405 C[i] = D[i]; 406 D[i] = C[i]; 407 } 408 409 We then check that the loop is broken into four for loops like so, if the pass 410 is run twice: 411 for (int i = 0; i < 10; i++) 412 A[i] = B[i]; 413 for (int i = 0; i < 10; i++) 414 B[i] = A[i]; 415 for (int i = 0; i < 10; i++) 416 C[i] = D[i]; 417 for (int i = 0; i < 10; i++) 418 D[i] = C[i]; 419 420 */ 421 422 TEST_F(FissionClassTest, FissionMultipleLoadStores) { 423 // clang-format off 424 // With LocalMultiStoreElimPass 425 const std::string source = R"( 426 OpCapability Shader 427 %1 = OpExtInstImport "GLSL.std.450" 428 OpMemoryModel Logical GLSL450 429 OpEntryPoint Fragment %2 "main" 430 OpExecutionMode %2 OriginUpperLeft 431 OpSource GLSL 430 432 OpName %2 "main" 433 OpName %3 "i" 434 OpName %4 "A" 435 OpName %5 "B" 436 OpName %6 "C" 437 OpName %7 "D" 438 %8 = OpTypeVoid 439 %9 = OpTypeFunction %8 440 %10 = OpTypeInt 32 1 441 %11 = OpTypePointer Function %10 442 %12 = OpConstant %10 0 443 %13 = OpConstant %10 10 444 %14 = OpTypeBool 445 %15 = OpTypeFloat 32 446 %16 = OpTypeInt 32 0 447 %17 = OpConstant %16 10 448 %18 = OpTypeArray %15 %17 449 %19 = OpTypePointer Function %18 450 %20 = OpTypePointer Function %15 451 %21 = OpConstant %10 1 452 %2 = OpFunction %8 None %9 453 %22 = OpLabel 454 %3 = OpVariable %11 Function 455 %4 = OpVariable %19 Function 456 %5 = OpVariable %19 Function 457 %6 = OpVariable %19 Function 458 %7 = OpVariable %19 Function 459 OpBranch %23 460 %23 = OpLabel 461 %24 = OpPhi %10 %12 %22 %25 %26 462 OpLoopMerge %27 %26 None 463 OpBranch %28 464 %28 = OpLabel 465 %29 = OpSLessThan %14 %24 %13 466 OpBranchConditional %29 %30 %27 467 %30 = OpLabel 468 %31 = OpAccessChain %20 %5 %24 469 %32 = OpLoad %15 %31 470 %33 = OpAccessChain %20 %4 %24 471 OpStore %33 %32 472 %34 = OpAccessChain %20 %4 %24 473 %35 = OpLoad %15 %34 474 %36 = OpAccessChain %20 %5 %24 475 OpStore %36 %35 476 %37 = OpAccessChain %20 %7 %24 477 %38 = OpLoad %15 %37 478 %39 = OpAccessChain %20 %6 %24 479 OpStore %39 %38 480 %40 = OpAccessChain %20 %6 %24 481 %41 = OpLoad %15 %40 482 %42 = OpAccessChain %20 %7 %24 483 OpStore %42 %41 484 OpBranch %26 485 %26 = OpLabel 486 %25 = OpIAdd %10 %24 %21 487 OpBranch %23 488 %27 = OpLabel 489 OpReturn 490 OpFunctionEnd 491 )"; 492 493 const std::string expected = R"(OpCapability Shader 494 %1 = OpExtInstImport "GLSL.std.450" 495 OpMemoryModel Logical GLSL450 496 OpEntryPoint Fragment %2 "main" 497 OpExecutionMode %2 OriginUpperLeft 498 OpSource GLSL 430 499 OpName %2 "main" 500 OpName %3 "i" 501 OpName %4 "A" 502 OpName %5 "B" 503 OpName %6 "C" 504 OpName %7 "D" 505 %8 = OpTypeVoid 506 %9 = OpTypeFunction %8 507 %10 = OpTypeInt 32 1 508 %11 = OpTypePointer Function %10 509 %12 = OpConstant %10 0 510 %13 = OpConstant %10 10 511 %14 = OpTypeBool 512 %15 = OpTypeFloat 32 513 %16 = OpTypeInt 32 0 514 %17 = OpConstant %16 10 515 %18 = OpTypeArray %15 %17 516 %19 = OpTypePointer Function %18 517 %20 = OpTypePointer Function %15 518 %21 = OpConstant %10 1 519 %2 = OpFunction %8 None %9 520 %22 = OpLabel 521 %3 = OpVariable %11 Function 522 %4 = OpVariable %19 Function 523 %5 = OpVariable %19 Function 524 %6 = OpVariable %19 Function 525 %7 = OpVariable %19 Function 526 OpBranch %43 527 %43 = OpLabel 528 %44 = OpPhi %10 %12 %22 %61 %60 529 OpLoopMerge %62 %60 None 530 OpBranch %45 531 %45 = OpLabel 532 %46 = OpSLessThan %14 %44 %13 533 OpBranchConditional %46 %47 %62 534 %47 = OpLabel 535 %48 = OpAccessChain %20 %5 %44 536 %49 = OpLoad %15 %48 537 %50 = OpAccessChain %20 %4 %44 538 OpStore %50 %49 539 %51 = OpAccessChain %20 %4 %44 540 %52 = OpLoad %15 %51 541 %53 = OpAccessChain %20 %5 %44 542 OpStore %53 %52 543 OpBranch %60 544 %60 = OpLabel 545 %61 = OpIAdd %10 %44 %21 546 OpBranch %43 547 %62 = OpLabel 548 OpBranch %23 549 %23 = OpLabel 550 %24 = OpPhi %10 %12 %62 %25 %26 551 OpLoopMerge %27 %26 None 552 OpBranch %28 553 %28 = OpLabel 554 %29 = OpSLessThan %14 %24 %13 555 OpBranchConditional %29 %30 %27 556 %30 = OpLabel 557 %37 = OpAccessChain %20 %7 %24 558 %38 = OpLoad %15 %37 559 %39 = OpAccessChain %20 %6 %24 560 OpStore %39 %38 561 %40 = OpAccessChain %20 %6 %24 562 %41 = OpLoad %15 %40 563 %42 = OpAccessChain %20 %7 %24 564 OpStore %42 %41 565 OpBranch %26 566 %26 = OpLabel 567 %25 = OpIAdd %10 %24 %21 568 OpBranch %23 569 %27 = OpLabel 570 OpReturn 571 OpFunctionEnd 572 )"; 573 574 575 const std::string expected_multiple_passes = R"(OpCapability Shader 576 %1 = OpExtInstImport "GLSL.std.450" 577 OpMemoryModel Logical GLSL450 578 OpEntryPoint Fragment %2 "main" 579 OpExecutionMode %2 OriginUpperLeft 580 OpSource GLSL 430 581 OpName %2 "main" 582 OpName %3 "i" 583 OpName %4 "A" 584 OpName %5 "B" 585 OpName %6 "C" 586 OpName %7 "D" 587 %8 = OpTypeVoid 588 %9 = OpTypeFunction %8 589 %10 = OpTypeInt 32 1 590 %11 = OpTypePointer Function %10 591 %12 = OpConstant %10 0 592 %13 = OpConstant %10 10 593 %14 = OpTypeBool 594 %15 = OpTypeFloat 32 595 %16 = OpTypeInt 32 0 596 %17 = OpConstant %16 10 597 %18 = OpTypeArray %15 %17 598 %19 = OpTypePointer Function %18 599 %20 = OpTypePointer Function %15 600 %21 = OpConstant %10 1 601 %2 = OpFunction %8 None %9 602 %22 = OpLabel 603 %3 = OpVariable %11 Function 604 %4 = OpVariable %19 Function 605 %5 = OpVariable %19 Function 606 %6 = OpVariable %19 Function 607 %7 = OpVariable %19 Function 608 OpBranch %63 609 %63 = OpLabel 610 %64 = OpPhi %10 %12 %22 %75 %74 611 OpLoopMerge %76 %74 None 612 OpBranch %65 613 %65 = OpLabel 614 %66 = OpSLessThan %14 %64 %13 615 OpBranchConditional %66 %67 %76 616 %67 = OpLabel 617 %68 = OpAccessChain %20 %5 %64 618 %69 = OpLoad %15 %68 619 %70 = OpAccessChain %20 %4 %64 620 OpStore %70 %69 621 OpBranch %74 622 %74 = OpLabel 623 %75 = OpIAdd %10 %64 %21 624 OpBranch %63 625 %76 = OpLabel 626 OpBranch %43 627 %43 = OpLabel 628 %44 = OpPhi %10 %12 %76 %61 %60 629 OpLoopMerge %62 %60 None 630 OpBranch %45 631 %45 = OpLabel 632 %46 = OpSLessThan %14 %44 %13 633 OpBranchConditional %46 %47 %62 634 %47 = OpLabel 635 %51 = OpAccessChain %20 %4 %44 636 %52 = OpLoad %15 %51 637 %53 = OpAccessChain %20 %5 %44 638 OpStore %53 %52 639 OpBranch %60 640 %60 = OpLabel 641 %61 = OpIAdd %10 %44 %21 642 OpBranch %43 643 %62 = OpLabel 644 OpBranch %77 645 %77 = OpLabel 646 %78 = OpPhi %10 %12 %62 %89 %88 647 OpLoopMerge %90 %88 None 648 OpBranch %79 649 %79 = OpLabel 650 %80 = OpSLessThan %14 %78 %13 651 OpBranchConditional %80 %81 %90 652 %81 = OpLabel 653 %82 = OpAccessChain %20 %7 %78 654 %83 = OpLoad %15 %82 655 %84 = OpAccessChain %20 %6 %78 656 OpStore %84 %83 657 OpBranch %88 658 %88 = OpLabel 659 %89 = OpIAdd %10 %78 %21 660 OpBranch %77 661 %90 = OpLabel 662 OpBranch %23 663 %23 = OpLabel 664 %24 = OpPhi %10 %12 %90 %25 %26 665 OpLoopMerge %27 %26 None 666 OpBranch %28 667 %28 = OpLabel 668 %29 = OpSLessThan %14 %24 %13 669 OpBranchConditional %29 %30 %27 670 %30 = OpLabel 671 %40 = OpAccessChain %20 %6 %24 672 %41 = OpLoad %15 %40 673 %42 = OpAccessChain %20 %7 %24 674 OpStore %42 %41 675 OpBranch %26 676 %26 = OpLabel 677 %25 = OpIAdd %10 %24 %21 678 OpBranch %23 679 %27 = OpLabel 680 OpReturn 681 OpFunctionEnd 682 )"; 683 // clang-format on 684 std::unique_ptr<IRContext> context = 685 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 686 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 687 Module* module = context->module(); 688 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 689 << source << std::endl; 690 691 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 692 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true); 693 694 // By passing 1 as argument we are using the constructor which makes the 695 // critera to split the loop be if the registers in the loop exceede 1. By 696 // using this constructor we are also enabling multiple passes (disabled by 697 // default). 698 SinglePassRunAndCheck<LoopFissionPass>(source, expected_multiple_passes, true, 699 1); 700 } 701 702 /* 703 #version 430 704 void main(void) { 705 int accumulator = 0; 706 float X[10]; 707 float Y[10]; 708 709 for (int i = 0; i < 10; i++) { 710 X[i] = Y[i]; 711 Y[i] = X[i]; 712 accumulator += i; 713 } 714 } 715 716 This should be split into the equivalent of: 717 718 #version 430 719 void main(void) { 720 int accumulator = 0; 721 float X[10]; 722 float Y[10]; 723 724 for (int i = 0; i < 10; i++) { 725 X[i] = Y[i]; 726 } 727 for (int i = 0; i < 10; i++) { 728 Y[i] = X[i]; 729 accumulator += i; 730 } 731 } 732 */ 733 TEST_F(FissionClassTest, FissionWithAccumulator) { 734 // clang-format off 735 // With LocalMultiStoreElimPass 736 const std::string source = R"(OpCapability Shader 737 %1 = OpExtInstImport "GLSL.std.450" 738 OpMemoryModel Logical GLSL450 739 OpEntryPoint Fragment %2 "main" 740 OpExecutionMode %2 OriginUpperLeft 741 OpSource GLSL 430 742 OpName %2 "main" 743 OpName %3 "accumulator" 744 OpName %4 "i" 745 OpName %5 "X" 746 OpName %6 "Y" 747 %7 = OpTypeVoid 748 %8 = OpTypeFunction %7 749 %9 = OpTypeInt 32 1 750 %10 = OpTypePointer Function %9 751 %11 = OpConstant %9 0 752 %12 = OpConstant %9 10 753 %13 = OpTypeBool 754 %14 = OpTypeFloat 32 755 %15 = OpTypeInt 32 0 756 %16 = OpConstant %15 10 757 %17 = OpTypeArray %14 %16 758 %18 = OpTypePointer Function %17 759 %19 = OpTypePointer Function %14 760 %20 = OpConstant %9 1 761 %2 = OpFunction %7 None %8 762 %21 = OpLabel 763 %3 = OpVariable %10 Function 764 %4 = OpVariable %10 Function 765 %5 = OpVariable %18 Function 766 %6 = OpVariable %18 Function 767 OpBranch %22 768 %22 = OpLabel 769 %23 = OpPhi %9 %11 %21 %24 %25 770 %26 = OpPhi %9 %11 %21 %27 %25 771 OpLoopMerge %28 %25 None 772 OpBranch %29 773 %29 = OpLabel 774 %30 = OpSLessThan %13 %26 %12 775 OpBranchConditional %30 %31 %28 776 %31 = OpLabel 777 %32 = OpAccessChain %19 %6 %26 778 %33 = OpLoad %14 %32 779 %34 = OpAccessChain %19 %5 %26 780 OpStore %34 %33 781 %35 = OpAccessChain %19 %5 %26 782 %36 = OpLoad %14 %35 783 %37 = OpAccessChain %19 %6 %26 784 OpStore %37 %36 785 %24 = OpIAdd %9 %23 %26 786 OpBranch %25 787 %25 = OpLabel 788 %27 = OpIAdd %9 %26 %20 789 OpBranch %22 790 %28 = OpLabel 791 OpReturn 792 OpFunctionEnd 793 )"; 794 795 const std::string expected = R"(OpCapability Shader 796 %1 = OpExtInstImport "GLSL.std.450" 797 OpMemoryModel Logical GLSL450 798 OpEntryPoint Fragment %2 "main" 799 OpExecutionMode %2 OriginUpperLeft 800 OpSource GLSL 430 801 OpName %2 "main" 802 OpName %3 "accumulator" 803 OpName %4 "i" 804 OpName %5 "X" 805 OpName %6 "Y" 806 %7 = OpTypeVoid 807 %8 = OpTypeFunction %7 808 %9 = OpTypeInt 32 1 809 %10 = OpTypePointer Function %9 810 %11 = OpConstant %9 0 811 %12 = OpConstant %9 10 812 %13 = OpTypeBool 813 %14 = OpTypeFloat 32 814 %15 = OpTypeInt 32 0 815 %16 = OpConstant %15 10 816 %17 = OpTypeArray %14 %16 817 %18 = OpTypePointer Function %17 818 %19 = OpTypePointer Function %14 819 %20 = OpConstant %9 1 820 %2 = OpFunction %7 None %8 821 %21 = OpLabel 822 %3 = OpVariable %10 Function 823 %4 = OpVariable %10 Function 824 %5 = OpVariable %18 Function 825 %6 = OpVariable %18 Function 826 OpBranch %38 827 %38 = OpLabel 828 %40 = OpPhi %9 %11 %21 %52 %51 829 OpLoopMerge %53 %51 None 830 OpBranch %41 831 %41 = OpLabel 832 %42 = OpSLessThan %13 %40 %12 833 OpBranchConditional %42 %43 %53 834 %43 = OpLabel 835 %44 = OpAccessChain %19 %6 %40 836 %45 = OpLoad %14 %44 837 %46 = OpAccessChain %19 %5 %40 838 OpStore %46 %45 839 OpBranch %51 840 %51 = OpLabel 841 %52 = OpIAdd %9 %40 %20 842 OpBranch %38 843 %53 = OpLabel 844 OpBranch %22 845 %22 = OpLabel 846 %23 = OpPhi %9 %11 %53 %24 %25 847 %26 = OpPhi %9 %11 %53 %27 %25 848 OpLoopMerge %28 %25 None 849 OpBranch %29 850 %29 = OpLabel 851 %30 = OpSLessThan %13 %26 %12 852 OpBranchConditional %30 %31 %28 853 %31 = OpLabel 854 %35 = OpAccessChain %19 %5 %26 855 %36 = OpLoad %14 %35 856 %37 = OpAccessChain %19 %6 %26 857 OpStore %37 %36 858 %24 = OpIAdd %9 %23 %26 859 OpBranch %25 860 %25 = OpLabel 861 %27 = OpIAdd %9 %26 %20 862 OpBranch %22 863 %28 = OpLabel 864 OpReturn 865 OpFunctionEnd 866 )"; 867 // clang-format on 868 std::unique_ptr<IRContext> context = 869 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 870 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 871 Module* module = context->module(); 872 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 873 << source << std::endl; 874 875 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 876 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true); 877 } 878 879 /* 880 Generated from the following glsl: 881 882 #version 430 883 layout(location=0) out float x; 884 layout(location=1) out float y; 885 886 void main(void) { 887 float accumulator_1 = 0; 888 float accumulator_2 = 0; 889 for (int i = 0; i < 10; i++) { 890 accumulator_1 += i; 891 accumulator_2 += i; 892 } 893 894 x = accumulator_1; 895 y = accumulator_2; 896 } 897 898 Should be split into equivalent of: 899 900 void main(void) { 901 float accumulator_1 = 0; 902 float accumulator_2 = 0; 903 for (int i = 0; i < 10; i++) { 904 accumulator_1 += i; 905 } 906 907 for (int i = 0; i < 10; i++) { 908 accumulator_2 += i; 909 } 910 x = accumulator_1; 911 y = accumulator_2; 912 } 913 914 */ 915 TEST_F(FissionClassTest, FissionWithPhisUsedOutwithLoop) { 916 // clang-format off 917 // With LocalMultiStoreElimPass 918 const std::string source = R"(OpCapability Shader 919 %1 = OpExtInstImport "GLSL.std.450" 920 OpMemoryModel Logical GLSL450 921 OpEntryPoint Fragment %2 "main" %3 %4 922 OpExecutionMode %2 OriginUpperLeft 923 OpSource GLSL 430 924 OpName %2 "main" 925 OpName %5 "accumulator_1" 926 OpName %6 "accumulator_2" 927 OpName %7 "i" 928 OpName %3 "x" 929 OpName %4 "y" 930 OpDecorate %3 Location 0 931 OpDecorate %4 Location 1 932 %8 = OpTypeVoid 933 %9 = OpTypeFunction %8 934 %10 = OpTypeFloat 32 935 %11 = OpTypePointer Function %10 936 %12 = OpConstant %10 0 937 %13 = OpTypeInt 32 1 938 %14 = OpTypePointer Function %13 939 %15 = OpConstant %13 0 940 %16 = OpConstant %13 10 941 %17 = OpTypeBool 942 %18 = OpConstant %13 1 943 %19 = OpTypePointer Output %10 944 %3 = OpVariable %19 Output 945 %4 = OpVariable %19 Output 946 %2 = OpFunction %8 None %9 947 %20 = OpLabel 948 %5 = OpVariable %11 Function 949 %6 = OpVariable %11 Function 950 %7 = OpVariable %14 Function 951 OpBranch %21 952 %21 = OpLabel 953 %22 = OpPhi %10 %12 %20 %23 %24 954 %25 = OpPhi %10 %12 %20 %26 %24 955 %27 = OpPhi %13 %15 %20 %28 %24 956 OpLoopMerge %29 %24 None 957 OpBranch %30 958 %30 = OpLabel 959 %31 = OpSLessThan %17 %27 %16 960 OpBranchConditional %31 %32 %29 961 %32 = OpLabel 962 %33 = OpConvertSToF %10 %27 963 %26 = OpFAdd %10 %25 %33 964 %34 = OpConvertSToF %10 %27 965 %23 = OpFAdd %10 %22 %34 966 OpBranch %24 967 %24 = OpLabel 968 %28 = OpIAdd %13 %27 %18 969 OpStore %7 %28 970 OpBranch %21 971 %29 = OpLabel 972 OpStore %3 %25 973 OpStore %4 %22 974 OpReturn 975 OpFunctionEnd 976 )"; 977 978 const std::string expected = R"(OpCapability Shader 979 %1 = OpExtInstImport "GLSL.std.450" 980 OpMemoryModel Logical GLSL450 981 OpEntryPoint Fragment %2 "main" %3 %4 982 OpExecutionMode %2 OriginUpperLeft 983 OpSource GLSL 430 984 OpName %2 "main" 985 OpName %5 "accumulator_1" 986 OpName %6 "accumulator_2" 987 OpName %7 "i" 988 OpName %3 "x" 989 OpName %4 "y" 990 OpDecorate %3 Location 0 991 OpDecorate %4 Location 1 992 %8 = OpTypeVoid 993 %9 = OpTypeFunction %8 994 %10 = OpTypeFloat 32 995 %11 = OpTypePointer Function %10 996 %12 = OpConstant %10 0 997 %13 = OpTypeInt 32 1 998 %14 = OpTypePointer Function %13 999 %15 = OpConstant %13 0 1000 %16 = OpConstant %13 10 1001 %17 = OpTypeBool 1002 %18 = OpConstant %13 1 1003 %19 = OpTypePointer Output %10 1004 %3 = OpVariable %19 Output 1005 %4 = OpVariable %19 Output 1006 %2 = OpFunction %8 None %9 1007 %20 = OpLabel 1008 %5 = OpVariable %11 Function 1009 %6 = OpVariable %11 Function 1010 %7 = OpVariable %14 Function 1011 OpBranch %35 1012 %35 = OpLabel 1013 %37 = OpPhi %10 %12 %20 %43 %46 1014 %38 = OpPhi %13 %15 %20 %47 %46 1015 OpLoopMerge %48 %46 None 1016 OpBranch %39 1017 %39 = OpLabel 1018 %40 = OpSLessThan %17 %38 %16 1019 OpBranchConditional %40 %41 %48 1020 %41 = OpLabel 1021 %42 = OpConvertSToF %10 %38 1022 %43 = OpFAdd %10 %37 %42 1023 OpBranch %46 1024 %46 = OpLabel 1025 %47 = OpIAdd %13 %38 %18 1026 OpStore %7 %47 1027 OpBranch %35 1028 %48 = OpLabel 1029 OpBranch %21 1030 %21 = OpLabel 1031 %22 = OpPhi %10 %12 %48 %23 %24 1032 %27 = OpPhi %13 %15 %48 %28 %24 1033 OpLoopMerge %29 %24 None 1034 OpBranch %30 1035 %30 = OpLabel 1036 %31 = OpSLessThan %17 %27 %16 1037 OpBranchConditional %31 %32 %29 1038 %32 = OpLabel 1039 %34 = OpConvertSToF %10 %27 1040 %23 = OpFAdd %10 %22 %34 1041 OpBranch %24 1042 %24 = OpLabel 1043 %28 = OpIAdd %13 %27 %18 1044 OpStore %7 %28 1045 OpBranch %21 1046 %29 = OpLabel 1047 OpStore %3 %37 1048 OpStore %4 %22 1049 OpReturn 1050 OpFunctionEnd 1051 )"; 1052 1053 // clang-format on 1054 std::unique_ptr<IRContext> context = 1055 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 1056 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1057 Module* module = context->module(); 1058 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 1059 << source << std::endl; 1060 1061 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 1062 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true); 1063 } 1064 1065 /* 1066 #version 430 1067 void main(void) { 1068 float A[10][10]; 1069 float B[10][10]; 1070 for (int i = 0; i < 10; i++) { 1071 for (int j = 0; j < 10; j++) { 1072 A[i][j] = B[i][j]; 1073 B[i][j] = A[i][j]; 1074 } 1075 } 1076 } 1077 1078 Should be split into equivalent of: 1079 1080 #version 430 1081 void main(void) { 1082 float A[10][10]; 1083 float B[10][10]; 1084 for (int i = 0; i < 10; i++) { 1085 for (int j = 0; j < 10; j++) { 1086 A[i][j] = B[i][j]; 1087 } 1088 for (int j = 0; j < 10; j++) { 1089 B[i][j] = A[i][j]; 1090 } 1091 } 1092 } 1093 1094 1095 */ 1096 TEST_F(FissionClassTest, FissionNested) { 1097 // clang-format off 1098 // With LocalMultiStoreElimPass 1099 const std::string source = R"( 1100 OpCapability Shader 1101 %1 = OpExtInstImport "GLSL.std.450" 1102 OpMemoryModel Logical GLSL450 1103 OpEntryPoint Fragment %2 "main" 1104 OpExecutionMode %2 OriginUpperLeft 1105 OpSource GLSL 430 1106 OpName %2 "main" 1107 OpName %3 "i" 1108 OpName %4 "j" 1109 OpName %5 "A" 1110 OpName %6 "B" 1111 %7 = OpTypeVoid 1112 %8 = OpTypeFunction %7 1113 %9 = OpTypeInt 32 1 1114 %10 = OpTypePointer Function %9 1115 %11 = OpConstant %9 0 1116 %12 = OpConstant %9 10 1117 %13 = OpTypeBool 1118 %14 = OpTypeFloat 32 1119 %15 = OpTypeInt 32 0 1120 %16 = OpConstant %15 10 1121 %17 = OpTypeArray %14 %16 1122 %18 = OpTypeArray %17 %16 1123 %19 = OpTypePointer Function %18 1124 %20 = OpTypePointer Function %14 1125 %21 = OpConstant %9 1 1126 %2 = OpFunction %7 None %8 1127 %22 = OpLabel 1128 %3 = OpVariable %10 Function 1129 %4 = OpVariable %10 Function 1130 %5 = OpVariable %19 Function 1131 %6 = OpVariable %19 Function 1132 OpStore %3 %11 1133 OpBranch %23 1134 %23 = OpLabel 1135 %24 = OpPhi %9 %11 %22 %25 %26 1136 OpLoopMerge %27 %26 None 1137 OpBranch %28 1138 %28 = OpLabel 1139 %29 = OpSLessThan %13 %24 %12 1140 OpBranchConditional %29 %30 %27 1141 %30 = OpLabel 1142 OpStore %4 %11 1143 OpBranch %31 1144 %31 = OpLabel 1145 %32 = OpPhi %9 %11 %30 %33 %34 1146 OpLoopMerge %35 %34 None 1147 OpBranch %36 1148 %36 = OpLabel 1149 %37 = OpSLessThan %13 %32 %12 1150 OpBranchConditional %37 %38 %35 1151 %38 = OpLabel 1152 %39 = OpAccessChain %20 %6 %24 %32 1153 %40 = OpLoad %14 %39 1154 %41 = OpAccessChain %20 %5 %24 %32 1155 OpStore %41 %40 1156 %42 = OpAccessChain %20 %5 %24 %32 1157 %43 = OpLoad %14 %42 1158 %44 = OpAccessChain %20 %6 %24 %32 1159 OpStore %44 %43 1160 OpBranch %34 1161 %34 = OpLabel 1162 %33 = OpIAdd %9 %32 %21 1163 OpStore %4 %33 1164 OpBranch %31 1165 %35 = OpLabel 1166 OpBranch %26 1167 %26 = OpLabel 1168 %25 = OpIAdd %9 %24 %21 1169 OpStore %3 %25 1170 OpBranch %23 1171 %27 = OpLabel 1172 OpReturn 1173 OpFunctionEnd 1174 )"; 1175 1176 const std::string expected = R"(OpCapability Shader 1177 %1 = OpExtInstImport "GLSL.std.450" 1178 OpMemoryModel Logical GLSL450 1179 OpEntryPoint Fragment %2 "main" 1180 OpExecutionMode %2 OriginUpperLeft 1181 OpSource GLSL 430 1182 OpName %2 "main" 1183 OpName %3 "i" 1184 OpName %4 "j" 1185 OpName %5 "A" 1186 OpName %6 "B" 1187 %7 = OpTypeVoid 1188 %8 = OpTypeFunction %7 1189 %9 = OpTypeInt 32 1 1190 %10 = OpTypePointer Function %9 1191 %11 = OpConstant %9 0 1192 %12 = OpConstant %9 10 1193 %13 = OpTypeBool 1194 %14 = OpTypeFloat 32 1195 %15 = OpTypeInt 32 0 1196 %16 = OpConstant %15 10 1197 %17 = OpTypeArray %14 %16 1198 %18 = OpTypeArray %17 %16 1199 %19 = OpTypePointer Function %18 1200 %20 = OpTypePointer Function %14 1201 %21 = OpConstant %9 1 1202 %2 = OpFunction %7 None %8 1203 %22 = OpLabel 1204 %3 = OpVariable %10 Function 1205 %4 = OpVariable %10 Function 1206 %5 = OpVariable %19 Function 1207 %6 = OpVariable %19 Function 1208 OpStore %3 %11 1209 OpBranch %23 1210 %23 = OpLabel 1211 %24 = OpPhi %9 %11 %22 %25 %26 1212 OpLoopMerge %27 %26 None 1213 OpBranch %28 1214 %28 = OpLabel 1215 %29 = OpSLessThan %13 %24 %12 1216 OpBranchConditional %29 %30 %27 1217 %30 = OpLabel 1218 OpStore %4 %11 1219 OpBranch %45 1220 %45 = OpLabel 1221 %46 = OpPhi %9 %11 %30 %57 %56 1222 OpLoopMerge %58 %56 None 1223 OpBranch %47 1224 %47 = OpLabel 1225 %48 = OpSLessThan %13 %46 %12 1226 OpBranchConditional %48 %49 %58 1227 %49 = OpLabel 1228 %50 = OpAccessChain %20 %6 %24 %46 1229 %51 = OpLoad %14 %50 1230 %52 = OpAccessChain %20 %5 %24 %46 1231 OpStore %52 %51 1232 OpBranch %56 1233 %56 = OpLabel 1234 %57 = OpIAdd %9 %46 %21 1235 OpStore %4 %57 1236 OpBranch %45 1237 %58 = OpLabel 1238 OpBranch %31 1239 %31 = OpLabel 1240 %32 = OpPhi %9 %11 %58 %33 %34 1241 OpLoopMerge %35 %34 None 1242 OpBranch %36 1243 %36 = OpLabel 1244 %37 = OpSLessThan %13 %32 %12 1245 OpBranchConditional %37 %38 %35 1246 %38 = OpLabel 1247 %42 = OpAccessChain %20 %5 %24 %32 1248 %43 = OpLoad %14 %42 1249 %44 = OpAccessChain %20 %6 %24 %32 1250 OpStore %44 %43 1251 OpBranch %34 1252 %34 = OpLabel 1253 %33 = OpIAdd %9 %32 %21 1254 OpStore %4 %33 1255 OpBranch %31 1256 %35 = OpLabel 1257 OpBranch %26 1258 %26 = OpLabel 1259 %25 = OpIAdd %9 %24 %21 1260 OpStore %3 %25 1261 OpBranch %23 1262 %27 = OpLabel 1263 OpReturn 1264 OpFunctionEnd 1265 )"; 1266 1267 // clang-format on 1268 std::unique_ptr<IRContext> context = 1269 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 1270 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1271 Module* module = context->module(); 1272 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 1273 << source << std::endl; 1274 1275 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 1276 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true); 1277 } 1278 1279 /* 1280 #version 430 1281 void main(void) { 1282 int accumulator = 0; 1283 float A[10]; 1284 float B[10]; 1285 float C[10]; 1286 1287 for (int i = 0; i < 10; i++) { 1288 int c = C[i]; 1289 A[i] = B[i]; 1290 B[i] = A[i] + c; 1291 } 1292 } 1293 1294 This loop should not be split as we would have to break the order of the loads 1295 to do so. It would be grouped into two sets: 1296 1297 1 1298 int c = C[i]; 1299 B[i] = A[i] + c; 1300 1301 2 1302 A[i] = B[i]; 1303 1304 To keep the load C[i] in the same order we would need to put B[i] ahead of that 1305 */ 1306 TEST_F(FissionClassTest, FissionLoad) { 1307 // clang-format off 1308 // With LocalMultiStoreElimPass 1309 const std::string source = R"(OpCapability Shader 1310 %1 = OpExtInstImport "GLSL.std.450" 1311 OpMemoryModel Logical GLSL450 1312 OpEntryPoint Fragment %2 "main" 1313 OpExecutionMode %2 OriginUpperLeft 1314 OpSource GLSL 430 1315 OpName %2 "main" 1316 OpName %3 "i" 1317 OpName %4 "c" 1318 OpName %5 "C" 1319 OpName %6 "A" 1320 OpName %7 "B" 1321 %8 = OpTypeVoid 1322 %9 = OpTypeFunction %8 1323 %10 = OpTypeInt 32 1 1324 %11 = OpTypePointer Function %10 1325 %12 = OpConstant %10 0 1326 %13 = OpConstant %10 10 1327 %14 = OpTypeBool 1328 %15 = OpTypeFloat 32 1329 %16 = OpTypePointer Function %15 1330 %17 = OpTypeInt 32 0 1331 %18 = OpConstant %17 10 1332 %19 = OpTypeArray %15 %18 1333 %20 = OpTypePointer Function %19 1334 %21 = OpConstant %10 1 1335 %2 = OpFunction %8 None %9 1336 %22 = OpLabel 1337 %3 = OpVariable %11 Function 1338 %4 = OpVariable %16 Function 1339 %5 = OpVariable %20 Function 1340 %6 = OpVariable %20 Function 1341 %7 = OpVariable %20 Function 1342 OpBranch %23 1343 %23 = OpLabel 1344 %24 = OpPhi %10 %12 %22 %25 %26 1345 OpLoopMerge %27 %26 None 1346 OpBranch %28 1347 %28 = OpLabel 1348 %29 = OpSLessThan %14 %24 %13 1349 OpBranchConditional %29 %30 %27 1350 %30 = OpLabel 1351 %31 = OpAccessChain %16 %5 %24 1352 %32 = OpLoad %15 %31 1353 OpStore %4 %32 1354 %33 = OpAccessChain %16 %7 %24 1355 %34 = OpLoad %15 %33 1356 %35 = OpAccessChain %16 %6 %24 1357 OpStore %35 %34 1358 %36 = OpAccessChain %16 %6 %24 1359 %37 = OpLoad %15 %36 1360 %38 = OpFAdd %15 %37 %32 1361 %39 = OpAccessChain %16 %7 %24 1362 OpStore %39 %38 1363 OpBranch %26 1364 %26 = OpLabel 1365 %25 = OpIAdd %10 %24 %21 1366 OpBranch %23 1367 %27 = OpLabel 1368 OpReturn 1369 OpFunctionEnd 1370 )"; 1371 // clang-format on 1372 std::unique_ptr<IRContext> context = 1373 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 1374 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1375 Module* module = context->module(); 1376 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 1377 << source << std::endl; 1378 1379 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 1380 SinglePassRunAndCheck<LoopFissionPass>(source, source, true); 1381 } 1382 1383 /* 1384 #version 430 1385 layout(location=0) flat in int condition; 1386 void main(void) { 1387 float A[10]; 1388 float B[10]; 1389 1390 for (int i = 0; i < 10; i++) { 1391 if (condition == 1) 1392 A[i] = B[i]; 1393 else 1394 B[i] = A[i]; 1395 } 1396 } 1397 1398 1399 When this is split we leave the condition check and control flow inplace and 1400 leave its removal for dead code elimination. 1401 1402 #version 430 1403 layout(location=0) flat in int condition; 1404 void main(void) { 1405 float A[10]; 1406 float B[10]; 1407 1408 for (int i = 0; i < 10; i++) { 1409 if (condition == 1) 1410 A[i] = B[i]; 1411 else 1412 ; 1413 } 1414 for (int i = 0; i < 10; i++) { 1415 if (condition == 1) 1416 ; 1417 else 1418 B[i] = A[i]; 1419 } 1420 } 1421 1422 1423 */ 1424 TEST_F(FissionClassTest, FissionControlFlow) { 1425 // clang-format off 1426 // With LocalMultiStoreElimPass 1427 const std::string source = R"( 1428 OpCapability Shader 1429 %1 = OpExtInstImport "GLSL.std.450" 1430 OpMemoryModel Logical GLSL450 1431 OpEntryPoint Fragment %2 "main" %3 1432 OpExecutionMode %2 OriginUpperLeft 1433 OpSource GLSL 430 1434 OpName %2 "main" 1435 OpName %4 "i" 1436 OpName %3 "condition" 1437 OpName %5 "A" 1438 OpName %6 "B" 1439 OpDecorate %3 Flat 1440 OpDecorate %3 Location 0 1441 %7 = OpTypeVoid 1442 %8 = OpTypeFunction %7 1443 %9 = OpTypeInt 32 1 1444 %10 = OpTypePointer Function %9 1445 %11 = OpConstant %9 0 1446 %12 = OpConstant %9 10 1447 %13 = OpTypeBool 1448 %14 = OpTypePointer Input %9 1449 %3 = OpVariable %14 Input 1450 %15 = OpConstant %9 1 1451 %16 = OpTypeFloat 32 1452 %17 = OpTypeInt 32 0 1453 %18 = OpConstant %17 10 1454 %19 = OpTypeArray %16 %18 1455 %20 = OpTypePointer Function %19 1456 %21 = OpTypePointer Function %16 1457 %2 = OpFunction %7 None %8 1458 %22 = OpLabel 1459 %4 = OpVariable %10 Function 1460 %5 = OpVariable %20 Function 1461 %6 = OpVariable %20 Function 1462 %31 = OpLoad %9 %3 1463 OpStore %4 %11 1464 OpBranch %23 1465 %23 = OpLabel 1466 %24 = OpPhi %9 %11 %22 %25 %26 1467 OpLoopMerge %27 %26 None 1468 OpBranch %28 1469 %28 = OpLabel 1470 %29 = OpSLessThan %13 %24 %12 1471 OpBranchConditional %29 %30 %27 1472 %30 = OpLabel 1473 %32 = OpIEqual %13 %31 %15 1474 OpSelectionMerge %33 None 1475 OpBranchConditional %32 %34 %35 1476 %34 = OpLabel 1477 %36 = OpAccessChain %21 %6 %24 1478 %37 = OpLoad %16 %36 1479 %38 = OpAccessChain %21 %5 %24 1480 OpStore %38 %37 1481 OpBranch %33 1482 %35 = OpLabel 1483 %39 = OpAccessChain %21 %5 %24 1484 %40 = OpLoad %16 %39 1485 %41 = OpAccessChain %21 %6 %24 1486 OpStore %41 %40 1487 OpBranch %33 1488 %33 = OpLabel 1489 OpBranch %26 1490 %26 = OpLabel 1491 %25 = OpIAdd %9 %24 %15 1492 OpStore %4 %25 1493 OpBranch %23 1494 %27 = OpLabel 1495 OpReturn 1496 OpFunctionEnd 1497 )"; 1498 1499 const std::string expected = R"(OpCapability Shader 1500 %1 = OpExtInstImport "GLSL.std.450" 1501 OpMemoryModel Logical GLSL450 1502 OpEntryPoint Fragment %2 "main" %3 1503 OpExecutionMode %2 OriginUpperLeft 1504 OpSource GLSL 430 1505 OpName %2 "main" 1506 OpName %4 "i" 1507 OpName %3 "condition" 1508 OpName %5 "A" 1509 OpName %6 "B" 1510 OpDecorate %3 Flat 1511 OpDecorate %3 Location 0 1512 %7 = OpTypeVoid 1513 %8 = OpTypeFunction %7 1514 %9 = OpTypeInt 32 1 1515 %10 = OpTypePointer Function %9 1516 %11 = OpConstant %9 0 1517 %12 = OpConstant %9 10 1518 %13 = OpTypeBool 1519 %14 = OpTypePointer Input %9 1520 %3 = OpVariable %14 Input 1521 %15 = OpConstant %9 1 1522 %16 = OpTypeFloat 32 1523 %17 = OpTypeInt 32 0 1524 %18 = OpConstant %17 10 1525 %19 = OpTypeArray %16 %18 1526 %20 = OpTypePointer Function %19 1527 %21 = OpTypePointer Function %16 1528 %2 = OpFunction %7 None %8 1529 %22 = OpLabel 1530 %4 = OpVariable %10 Function 1531 %5 = OpVariable %20 Function 1532 %6 = OpVariable %20 Function 1533 %23 = OpLoad %9 %3 1534 OpStore %4 %11 1535 OpBranch %42 1536 %42 = OpLabel 1537 %43 = OpPhi %9 %11 %22 %58 %57 1538 OpLoopMerge %59 %57 None 1539 OpBranch %44 1540 %44 = OpLabel 1541 %45 = OpSLessThan %13 %43 %12 1542 OpBranchConditional %45 %46 %59 1543 %46 = OpLabel 1544 %47 = OpIEqual %13 %23 %15 1545 OpSelectionMerge %56 None 1546 OpBranchConditional %47 %52 %48 1547 %48 = OpLabel 1548 OpBranch %56 1549 %52 = OpLabel 1550 %53 = OpAccessChain %21 %6 %43 1551 %54 = OpLoad %16 %53 1552 %55 = OpAccessChain %21 %5 %43 1553 OpStore %55 %54 1554 OpBranch %56 1555 %56 = OpLabel 1556 OpBranch %57 1557 %57 = OpLabel 1558 %58 = OpIAdd %9 %43 %15 1559 OpStore %4 %58 1560 OpBranch %42 1561 %59 = OpLabel 1562 OpBranch %24 1563 %24 = OpLabel 1564 %25 = OpPhi %9 %11 %59 %26 %27 1565 OpLoopMerge %28 %27 None 1566 OpBranch %29 1567 %29 = OpLabel 1568 %30 = OpSLessThan %13 %25 %12 1569 OpBranchConditional %30 %31 %28 1570 %31 = OpLabel 1571 %32 = OpIEqual %13 %23 %15 1572 OpSelectionMerge %33 None 1573 OpBranchConditional %32 %34 %35 1574 %34 = OpLabel 1575 OpBranch %33 1576 %35 = OpLabel 1577 %39 = OpAccessChain %21 %5 %25 1578 %40 = OpLoad %16 %39 1579 %41 = OpAccessChain %21 %6 %25 1580 OpStore %41 %40 1581 OpBranch %33 1582 %33 = OpLabel 1583 OpBranch %27 1584 %27 = OpLabel 1585 %26 = OpIAdd %9 %25 %15 1586 OpStore %4 %26 1587 OpBranch %24 1588 %28 = OpLabel 1589 OpReturn 1590 OpFunctionEnd 1591 )"; 1592 1593 // clang-format on 1594 std::unique_ptr<IRContext> context = 1595 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 1596 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1597 Module* module = context->module(); 1598 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 1599 << source << std::endl; 1600 1601 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 1602 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true); 1603 } 1604 1605 /* 1606 #version 430 1607 void main(void) { 1608 float A[10]; 1609 float B[10]; 1610 for (int i = 0; i < 10; i++) { 1611 if (i == 1) 1612 B[i] = A[i]; 1613 else if (i == 2) 1614 A[i] = B[i]; 1615 else 1616 A[i] = 0; 1617 } 1618 } 1619 1620 After running the pass with multiple splits enabled (via register threshold of 1621 1) we expect the equivalent of: 1622 1623 #version 430 1624 void main(void) { 1625 float A[10]; 1626 float B[10]; 1627 for (int i = 0; i < 10; i++) { 1628 if (i == 1) 1629 B[i] = A[i]; 1630 else if (i == 2) 1631 else 1632 } 1633 for (int i = 0; i < 10; i++) { 1634 if (i == 1) 1635 else if (i == 2) 1636 A[i] = B[i]; 1637 else 1638 } 1639 for (int i = 0; i < 10; i++) { 1640 if (i == 1) 1641 else if (i == 2) 1642 else 1643 A[i] = 0; 1644 } 1645 1646 } 1647 1648 */ 1649 TEST_F(FissionClassTest, FissionControlFlow2) { 1650 // clang-format off 1651 // With LocalMultiStoreElimPass 1652 const std::string source = R"(OpCapability Shader 1653 %1 = OpExtInstImport "GLSL.std.450" 1654 OpMemoryModel Logical GLSL450 1655 OpEntryPoint Fragment %2 "main" 1656 OpExecutionMode %2 OriginUpperLeft 1657 OpSource GLSL 430 1658 OpName %2 "main" 1659 OpName %3 "i" 1660 OpName %4 "B" 1661 OpName %5 "A" 1662 %6 = OpTypeVoid 1663 %7 = OpTypeFunction %6 1664 %8 = OpTypeInt 32 1 1665 %9 = OpTypePointer Function %8 1666 %10 = OpConstant %8 0 1667 %11 = OpConstant %8 10 1668 %12 = OpTypeBool 1669 %13 = OpConstant %8 1 1670 %14 = OpTypeFloat 32 1671 %15 = OpTypeInt 32 0 1672 %16 = OpConstant %15 10 1673 %17 = OpTypeArray %14 %16 1674 %18 = OpTypePointer Function %17 1675 %19 = OpTypePointer Function %14 1676 %20 = OpConstant %8 2 1677 %21 = OpConstant %14 0 1678 %2 = OpFunction %6 None %7 1679 %22 = OpLabel 1680 %3 = OpVariable %9 Function 1681 %4 = OpVariable %18 Function 1682 %5 = OpVariable %18 Function 1683 OpStore %3 %10 1684 OpBranch %23 1685 %23 = OpLabel 1686 %24 = OpPhi %8 %10 %22 %25 %26 1687 OpLoopMerge %27 %26 None 1688 OpBranch %28 1689 %28 = OpLabel 1690 %29 = OpSLessThan %12 %24 %11 1691 OpBranchConditional %29 %30 %27 1692 %30 = OpLabel 1693 %31 = OpIEqual %12 %24 %13 1694 OpSelectionMerge %32 None 1695 OpBranchConditional %31 %33 %34 1696 %33 = OpLabel 1697 %35 = OpAccessChain %19 %5 %24 1698 %36 = OpLoad %14 %35 1699 %37 = OpAccessChain %19 %4 %24 1700 OpStore %37 %36 1701 OpBranch %32 1702 %34 = OpLabel 1703 %38 = OpIEqual %12 %24 %20 1704 OpSelectionMerge %39 None 1705 OpBranchConditional %38 %40 %41 1706 %40 = OpLabel 1707 %42 = OpAccessChain %19 %4 %24 1708 %43 = OpLoad %14 %42 1709 %44 = OpAccessChain %19 %5 %24 1710 OpStore %44 %43 1711 OpBranch %39 1712 %41 = OpLabel 1713 %45 = OpAccessChain %19 %5 %24 1714 OpStore %45 %21 1715 OpBranch %39 1716 %39 = OpLabel 1717 OpBranch %32 1718 %32 = OpLabel 1719 OpBranch %26 1720 %26 = OpLabel 1721 %25 = OpIAdd %8 %24 %13 1722 OpStore %3 %25 1723 OpBranch %23 1724 %27 = OpLabel 1725 OpReturn 1726 OpFunctionEnd 1727 )"; 1728 1729 const std::string expected = R"(OpCapability Shader 1730 %1 = OpExtInstImport "GLSL.std.450" 1731 OpMemoryModel Logical GLSL450 1732 OpEntryPoint Fragment %2 "main" 1733 OpExecutionMode %2 OriginUpperLeft 1734 OpSource GLSL 430 1735 OpName %2 "main" 1736 OpName %3 "i" 1737 OpName %4 "B" 1738 OpName %5 "A" 1739 %6 = OpTypeVoid 1740 %7 = OpTypeFunction %6 1741 %8 = OpTypeInt 32 1 1742 %9 = OpTypePointer Function %8 1743 %10 = OpConstant %8 0 1744 %11 = OpConstant %8 10 1745 %12 = OpTypeBool 1746 %13 = OpConstant %8 1 1747 %14 = OpTypeFloat 32 1748 %15 = OpTypeInt 32 0 1749 %16 = OpConstant %15 10 1750 %17 = OpTypeArray %14 %16 1751 %18 = OpTypePointer Function %17 1752 %19 = OpTypePointer Function %14 1753 %20 = OpConstant %8 2 1754 %21 = OpConstant %14 0 1755 %2 = OpFunction %6 None %7 1756 %22 = OpLabel 1757 %3 = OpVariable %9 Function 1758 %4 = OpVariable %18 Function 1759 %5 = OpVariable %18 Function 1760 OpStore %3 %10 1761 OpBranch %46 1762 %46 = OpLabel 1763 %47 = OpPhi %8 %10 %22 %67 %66 1764 OpLoopMerge %68 %66 None 1765 OpBranch %48 1766 %48 = OpLabel 1767 %49 = OpSLessThan %12 %47 %11 1768 OpBranchConditional %49 %50 %68 1769 %50 = OpLabel 1770 %51 = OpIEqual %12 %47 %13 1771 OpSelectionMerge %65 None 1772 OpBranchConditional %51 %61 %52 1773 %52 = OpLabel 1774 %53 = OpIEqual %12 %47 %20 1775 OpSelectionMerge %60 None 1776 OpBranchConditional %53 %56 %54 1777 %54 = OpLabel 1778 OpBranch %60 1779 %56 = OpLabel 1780 OpBranch %60 1781 %60 = OpLabel 1782 OpBranch %65 1783 %61 = OpLabel 1784 %62 = OpAccessChain %19 %5 %47 1785 %63 = OpLoad %14 %62 1786 %64 = OpAccessChain %19 %4 %47 1787 OpStore %64 %63 1788 OpBranch %65 1789 %65 = OpLabel 1790 OpBranch %66 1791 %66 = OpLabel 1792 %67 = OpIAdd %8 %47 %13 1793 OpStore %3 %67 1794 OpBranch %46 1795 %68 = OpLabel 1796 OpBranch %69 1797 %69 = OpLabel 1798 %70 = OpPhi %8 %10 %68 %87 %86 1799 OpLoopMerge %88 %86 None 1800 OpBranch %71 1801 %71 = OpLabel 1802 %72 = OpSLessThan %12 %70 %11 1803 OpBranchConditional %72 %73 %88 1804 %73 = OpLabel 1805 %74 = OpIEqual %12 %70 %13 1806 OpSelectionMerge %85 None 1807 OpBranchConditional %74 %84 %75 1808 %75 = OpLabel 1809 %76 = OpIEqual %12 %70 %20 1810 OpSelectionMerge %83 None 1811 OpBranchConditional %76 %79 %77 1812 %77 = OpLabel 1813 OpBranch %83 1814 %79 = OpLabel 1815 %80 = OpAccessChain %19 %4 %70 1816 %81 = OpLoad %14 %80 1817 %82 = OpAccessChain %19 %5 %70 1818 OpStore %82 %81 1819 OpBranch %83 1820 %83 = OpLabel 1821 OpBranch %85 1822 %84 = OpLabel 1823 OpBranch %85 1824 %85 = OpLabel 1825 OpBranch %86 1826 %86 = OpLabel 1827 %87 = OpIAdd %8 %70 %13 1828 OpStore %3 %87 1829 OpBranch %69 1830 %88 = OpLabel 1831 OpBranch %23 1832 %23 = OpLabel 1833 %24 = OpPhi %8 %10 %88 %25 %26 1834 OpLoopMerge %27 %26 None 1835 OpBranch %28 1836 %28 = OpLabel 1837 %29 = OpSLessThan %12 %24 %11 1838 OpBranchConditional %29 %30 %27 1839 %30 = OpLabel 1840 %31 = OpIEqual %12 %24 %13 1841 OpSelectionMerge %32 None 1842 OpBranchConditional %31 %33 %34 1843 %33 = OpLabel 1844 OpBranch %32 1845 %34 = OpLabel 1846 %38 = OpIEqual %12 %24 %20 1847 OpSelectionMerge %39 None 1848 OpBranchConditional %38 %40 %41 1849 %40 = OpLabel 1850 OpBranch %39 1851 %41 = OpLabel 1852 %45 = OpAccessChain %19 %5 %24 1853 OpStore %45 %21 1854 OpBranch %39 1855 %39 = OpLabel 1856 OpBranch %32 1857 %32 = OpLabel 1858 OpBranch %26 1859 %26 = OpLabel 1860 %25 = OpIAdd %8 %24 %13 1861 OpStore %3 %25 1862 OpBranch %23 1863 %27 = OpLabel 1864 OpReturn 1865 OpFunctionEnd 1866 )"; 1867 1868 // clang-format on 1869 std::unique_ptr<IRContext> context = 1870 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 1871 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1872 Module* module = context->module(); 1873 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 1874 << source << std::endl; 1875 1876 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 1877 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true, 1); 1878 } 1879 1880 /* 1881 #version 430 1882 layout(location=0) flat in int condition; 1883 void main(void) { 1884 float A[10]; 1885 float B[10]; 1886 for (int i = 0; i < 10; i++) { 1887 B[i] = A[i]; 1888 memoryBarrier(); 1889 A[i] = B[i]; 1890 } 1891 } 1892 1893 This should not be split due to the memory barrier. 1894 */ 1895 TEST_F(FissionClassTest, FissionBarrier) { 1896 // clang-format off 1897 // With LocalMultiStoreElimPass 1898 const std::string source = R"(OpCapability Shader 1899 %1 = OpExtInstImport "GLSL.std.450" 1900 OpMemoryModel Logical GLSL450 1901 OpEntryPoint Fragment %2 "main" %3 1902 OpExecutionMode %2 OriginUpperLeft 1903 OpSource GLSL 430 1904 OpName %2 "main" 1905 OpName %4 "i" 1906 OpName %5 "B" 1907 OpName %6 "A" 1908 OpName %3 "condition" 1909 OpDecorate %3 Flat 1910 OpDecorate %3 Location 0 1911 %7 = OpTypeVoid 1912 %8 = OpTypeFunction %7 1913 %9 = OpTypeInt 32 1 1914 %10 = OpTypePointer Function %9 1915 %11 = OpConstant %9 0 1916 %12 = OpConstant %9 10 1917 %13 = OpTypeBool 1918 %14 = OpTypeFloat 32 1919 %15 = OpTypeInt 32 0 1920 %16 = OpConstant %15 10 1921 %17 = OpTypeArray %14 %16 1922 %18 = OpTypePointer Function %17 1923 %19 = OpTypePointer Function %14 1924 %20 = OpConstant %15 1 1925 %21 = OpConstant %15 4048 1926 %22 = OpConstant %9 1 1927 %23 = OpTypePointer Input %9 1928 %3 = OpVariable %23 Input 1929 %2 = OpFunction %7 None %8 1930 %24 = OpLabel 1931 %4 = OpVariable %10 Function 1932 %5 = OpVariable %18 Function 1933 %6 = OpVariable %18 Function 1934 OpStore %4 %11 1935 OpBranch %25 1936 %25 = OpLabel 1937 %26 = OpPhi %9 %11 %24 %27 %28 1938 OpLoopMerge %29 %28 None 1939 OpBranch %30 1940 %30 = OpLabel 1941 %31 = OpSLessThan %13 %26 %12 1942 OpBranchConditional %31 %32 %29 1943 %32 = OpLabel 1944 %33 = OpAccessChain %19 %6 %26 1945 %34 = OpLoad %14 %33 1946 %35 = OpAccessChain %19 %5 %26 1947 OpStore %35 %34 1948 OpMemoryBarrier %20 %21 1949 %36 = OpAccessChain %19 %5 %26 1950 %37 = OpLoad %14 %36 1951 %38 = OpAccessChain %19 %6 %26 1952 OpStore %38 %37 1953 OpBranch %28 1954 %28 = OpLabel 1955 %27 = OpIAdd %9 %26 %22 1956 OpStore %4 %27 1957 OpBranch %25 1958 %29 = OpLabel 1959 OpReturn 1960 OpFunctionEnd 1961 )"; 1962 // clang-format on 1963 std::unique_ptr<IRContext> context = 1964 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 1965 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1966 Module* module = context->module(); 1967 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 1968 << source << std::endl; 1969 1970 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 1971 SinglePassRunAndCheck<LoopFissionPass>(source, source, true); 1972 } 1973 1974 /* 1975 #version 430 1976 void main(void) { 1977 float A[10]; 1978 float B[10]; 1979 for (int i = 0; i < 10; i++) { 1980 B[i] = A[i]; 1981 if ( i== 1) 1982 break; 1983 A[i] = B[i]; 1984 } 1985 } 1986 1987 This should not be split due to the break. 1988 */ 1989 TEST_F(FissionClassTest, FissionBreak) { 1990 // clang-format off 1991 // With LocalMultiStoreElimPass 1992 const std::string source = R"(OpCapability Shader 1993 %1 = OpExtInstImport "GLSL.std.450" 1994 OpMemoryModel Logical GLSL450 1995 OpEntryPoint Fragment %2 "main" 1996 OpExecutionMode %2 OriginUpperLeft 1997 OpSource GLSL 430 1998 OpName %2 "main" 1999 OpName %3 "i" 2000 OpName %4 "B" 2001 OpName %5 "A" 2002 %6 = OpTypeVoid 2003 %7 = OpTypeFunction %6 2004 %8 = OpTypeInt 32 1 2005 %9 = OpTypePointer Function %8 2006 %10 = OpConstant %8 0 2007 %11 = OpConstant %8 10 2008 %12 = OpTypeBool 2009 %13 = OpTypeFloat 32 2010 %14 = OpTypeInt 32 0 2011 %15 = OpConstant %14 10 2012 %16 = OpTypeArray %13 %15 2013 %17 = OpTypePointer Function %16 2014 %18 = OpTypePointer Function %13 2015 %19 = OpConstant %8 1 2016 %2 = OpFunction %6 None %7 2017 %20 = OpLabel 2018 %3 = OpVariable %9 Function 2019 %4 = OpVariable %17 Function 2020 %5 = OpVariable %17 Function 2021 OpStore %3 %10 2022 OpBranch %21 2023 %21 = OpLabel 2024 %22 = OpPhi %8 %10 %20 %23 %24 2025 OpLoopMerge %25 %24 None 2026 OpBranch %26 2027 %26 = OpLabel 2028 %27 = OpSLessThan %12 %22 %11 2029 OpBranchConditional %27 %28 %25 2030 %28 = OpLabel 2031 %29 = OpAccessChain %18 %5 %22 2032 %30 = OpLoad %13 %29 2033 %31 = OpAccessChain %18 %4 %22 2034 OpStore %31 %30 2035 %32 = OpIEqual %12 %22 %19 2036 OpSelectionMerge %33 None 2037 OpBranchConditional %32 %34 %33 2038 %34 = OpLabel 2039 OpBranch %25 2040 %33 = OpLabel 2041 %35 = OpAccessChain %18 %4 %22 2042 %36 = OpLoad %13 %35 2043 %37 = OpAccessChain %18 %5 %22 2044 OpStore %37 %36 2045 OpBranch %24 2046 %24 = OpLabel 2047 %23 = OpIAdd %8 %22 %19 2048 OpStore %3 %23 2049 OpBranch %21 2050 %25 = OpLabel 2051 OpReturn 2052 OpFunctionEnd 2053 )"; 2054 // clang-format on 2055 std::unique_ptr<IRContext> context = 2056 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 2057 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 2058 Module* module = context->module(); 2059 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 2060 << source << std::endl; 2061 2062 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 2063 SinglePassRunAndCheck<LoopFissionPass>(source, source, true); 2064 } 2065 2066 /* 2067 #version 430 2068 void main(void) { 2069 float A[10]; 2070 float B[10]; 2071 for (int i = 0; i < 10; i++) { 2072 B[i] = A[i]; 2073 if ( i== 1) 2074 continue; 2075 A[i] = B[i]; 2076 } 2077 } 2078 2079 This loop should be split into: 2080 2081 for (int i = 0; i < 10; i++) { 2082 B[i] = A[i]; 2083 if ( i== 1) 2084 continue; 2085 } 2086 for (int i = 0; i < 10; i++) { 2087 if ( i== 1) 2088 continue; 2089 A[i] = B[i]; 2090 } 2091 The continue block in the first loop is left to DCE. 2092 } 2093 2094 2095 */ 2096 TEST_F(FissionClassTest, FissionContinue) { 2097 // clang-format off 2098 // With LocalMultiStoreElimPass 2099 const std::string source = R"(OpCapability Shader 2100 %1 = OpExtInstImport "GLSL.std.450" 2101 OpMemoryModel Logical GLSL450 2102 OpEntryPoint Fragment %2 "main" 2103 OpExecutionMode %2 OriginUpperLeft 2104 OpSource GLSL 430 2105 OpName %2 "main" 2106 OpName %3 "i" 2107 OpName %4 "B" 2108 OpName %5 "A" 2109 %6 = OpTypeVoid 2110 %7 = OpTypeFunction %6 2111 %8 = OpTypeInt 32 1 2112 %9 = OpTypePointer Function %8 2113 %10 = OpConstant %8 0 2114 %11 = OpConstant %8 10 2115 %12 = OpTypeBool 2116 %13 = OpTypeFloat 32 2117 %14 = OpTypeInt 32 0 2118 %15 = OpConstant %14 10 2119 %16 = OpTypeArray %13 %15 2120 %17 = OpTypePointer Function %16 2121 %18 = OpTypePointer Function %13 2122 %19 = OpConstant %8 1 2123 %2 = OpFunction %6 None %7 2124 %20 = OpLabel 2125 %3 = OpVariable %9 Function 2126 %4 = OpVariable %17 Function 2127 %5 = OpVariable %17 Function 2128 OpStore %3 %10 2129 OpBranch %21 2130 %21 = OpLabel 2131 %22 = OpPhi %8 %10 %20 %23 %24 2132 OpLoopMerge %25 %24 None 2133 OpBranch %26 2134 %26 = OpLabel 2135 %27 = OpSLessThan %12 %22 %11 2136 OpBranchConditional %27 %28 %25 2137 %28 = OpLabel 2138 %29 = OpAccessChain %18 %5 %22 2139 %30 = OpLoad %13 %29 2140 %31 = OpAccessChain %18 %4 %22 2141 OpStore %31 %30 2142 %32 = OpIEqual %12 %22 %19 2143 OpSelectionMerge %33 None 2144 OpBranchConditional %32 %34 %33 2145 %34 = OpLabel 2146 OpBranch %24 2147 %33 = OpLabel 2148 %35 = OpAccessChain %18 %4 %22 2149 %36 = OpLoad %13 %35 2150 %37 = OpAccessChain %18 %5 %22 2151 OpStore %37 %36 2152 OpBranch %24 2153 %24 = OpLabel 2154 %23 = OpIAdd %8 %22 %19 2155 OpStore %3 %23 2156 OpBranch %21 2157 %25 = OpLabel 2158 OpReturn 2159 OpFunctionEnd 2160 )"; 2161 2162 const std::string expected = R"(OpCapability Shader 2163 %1 = OpExtInstImport "GLSL.std.450" 2164 OpMemoryModel Logical GLSL450 2165 OpEntryPoint Fragment %2 "main" 2166 OpExecutionMode %2 OriginUpperLeft 2167 OpSource GLSL 430 2168 OpName %2 "main" 2169 OpName %3 "i" 2170 OpName %4 "B" 2171 OpName %5 "A" 2172 %6 = OpTypeVoid 2173 %7 = OpTypeFunction %6 2174 %8 = OpTypeInt 32 1 2175 %9 = OpTypePointer Function %8 2176 %10 = OpConstant %8 0 2177 %11 = OpConstant %8 10 2178 %12 = OpTypeBool 2179 %13 = OpTypeFloat 32 2180 %14 = OpTypeInt 32 0 2181 %15 = OpConstant %14 10 2182 %16 = OpTypeArray %13 %15 2183 %17 = OpTypePointer Function %16 2184 %18 = OpTypePointer Function %13 2185 %19 = OpConstant %8 1 2186 %2 = OpFunction %6 None %7 2187 %20 = OpLabel 2188 %3 = OpVariable %9 Function 2189 %4 = OpVariable %17 Function 2190 %5 = OpVariable %17 Function 2191 OpStore %3 %10 2192 OpBranch %38 2193 %38 = OpLabel 2194 %39 = OpPhi %8 %10 %20 %53 %52 2195 OpLoopMerge %54 %52 None 2196 OpBranch %40 2197 %40 = OpLabel 2198 %41 = OpSLessThan %12 %39 %11 2199 OpBranchConditional %41 %42 %54 2200 %42 = OpLabel 2201 %43 = OpAccessChain %18 %5 %39 2202 %44 = OpLoad %13 %43 2203 %45 = OpAccessChain %18 %4 %39 2204 OpStore %45 %44 2205 %46 = OpIEqual %12 %39 %19 2206 OpSelectionMerge %47 None 2207 OpBranchConditional %46 %51 %47 2208 %47 = OpLabel 2209 OpBranch %52 2210 %51 = OpLabel 2211 OpBranch %52 2212 %52 = OpLabel 2213 %53 = OpIAdd %8 %39 %19 2214 OpStore %3 %53 2215 OpBranch %38 2216 %54 = OpLabel 2217 OpBranch %21 2218 %21 = OpLabel 2219 %22 = OpPhi %8 %10 %54 %23 %24 2220 OpLoopMerge %25 %24 None 2221 OpBranch %26 2222 %26 = OpLabel 2223 %27 = OpSLessThan %12 %22 %11 2224 OpBranchConditional %27 %28 %25 2225 %28 = OpLabel 2226 %32 = OpIEqual %12 %22 %19 2227 OpSelectionMerge %33 None 2228 OpBranchConditional %32 %34 %33 2229 %34 = OpLabel 2230 OpBranch %24 2231 %33 = OpLabel 2232 %35 = OpAccessChain %18 %4 %22 2233 %36 = OpLoad %13 %35 2234 %37 = OpAccessChain %18 %5 %22 2235 OpStore %37 %36 2236 OpBranch %24 2237 %24 = OpLabel 2238 %23 = OpIAdd %8 %22 %19 2239 OpStore %3 %23 2240 OpBranch %21 2241 %25 = OpLabel 2242 OpReturn 2243 OpFunctionEnd 2244 )"; 2245 // clang-format on 2246 std::unique_ptr<IRContext> context = 2247 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 2248 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 2249 Module* module = context->module(); 2250 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 2251 << source << std::endl; 2252 2253 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 2254 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true); 2255 } 2256 2257 /* 2258 #version 430 2259 void main(void) { 2260 float A[10]; 2261 float B[10]; 2262 int i = 0; 2263 do { 2264 B[i] = A[i]; 2265 A[i] = B[i]; 2266 ++i; 2267 } while (i < 10); 2268 } 2269 2270 2271 Check that this is split into: 2272 int i = 0; 2273 do { 2274 B[i] = A[i]; 2275 ++i; 2276 } while (i < 10); 2277 2278 i = 0; 2279 do { 2280 A[i] = B[i]; 2281 ++i; 2282 } while (i < 10); 2283 2284 2285 */ 2286 TEST_F(FissionClassTest, FissionDoWhile) { 2287 // clang-format off 2288 // With LocalMultiStoreElimPass 2289 const std::string source = R"(OpCapability Shader 2290 %1 = OpExtInstImport "GLSL.std.450" 2291 OpMemoryModel Logical GLSL450 2292 OpEntryPoint Fragment %2 "main" 2293 OpExecutionMode %2 OriginUpperLeft 2294 OpSource GLSL 430 2295 OpName %2 "main" 2296 OpName %3 "i" 2297 OpName %4 "B" 2298 OpName %5 "A" 2299 %6 = OpTypeVoid 2300 %7 = OpTypeFunction %6 2301 %8 = OpTypeInt 32 1 2302 %9 = OpTypePointer Function %8 2303 %10 = OpConstant %8 0 2304 %11 = OpTypeFloat 32 2305 %12 = OpTypeInt 32 0 2306 %13 = OpConstant %12 10 2307 %14 = OpTypeArray %11 %13 2308 %15 = OpTypePointer Function %14 2309 %16 = OpTypePointer Function %11 2310 %17 = OpConstant %8 1 2311 %18 = OpConstant %8 10 2312 %19 = OpTypeBool 2313 %2 = OpFunction %6 None %7 2314 %20 = OpLabel 2315 %3 = OpVariable %9 Function 2316 %4 = OpVariable %15 Function 2317 %5 = OpVariable %15 Function 2318 OpStore %3 %10 2319 OpBranch %21 2320 %21 = OpLabel 2321 %22 = OpPhi %8 %10 %20 %23 %24 2322 OpLoopMerge %25 %24 None 2323 OpBranch %26 2324 %26 = OpLabel 2325 %27 = OpAccessChain %16 %5 %22 2326 %28 = OpLoad %11 %27 2327 %29 = OpAccessChain %16 %4 %22 2328 OpStore %29 %28 2329 %30 = OpAccessChain %16 %4 %22 2330 %31 = OpLoad %11 %30 2331 %32 = OpAccessChain %16 %5 %22 2332 OpStore %32 %31 2333 %23 = OpIAdd %8 %22 %17 2334 OpStore %3 %23 2335 OpBranch %24 2336 %24 = OpLabel 2337 %33 = OpSLessThan %19 %23 %18 2338 OpBranchConditional %33 %21 %25 2339 %25 = OpLabel 2340 OpReturn 2341 OpFunctionEnd 2342 )"; 2343 2344 const std::string expected = R"(OpCapability Shader 2345 %1 = OpExtInstImport "GLSL.std.450" 2346 OpMemoryModel Logical GLSL450 2347 OpEntryPoint Fragment %2 "main" 2348 OpExecutionMode %2 OriginUpperLeft 2349 OpSource GLSL 430 2350 OpName %2 "main" 2351 OpName %3 "i" 2352 OpName %4 "B" 2353 OpName %5 "A" 2354 %6 = OpTypeVoid 2355 %7 = OpTypeFunction %6 2356 %8 = OpTypeInt 32 1 2357 %9 = OpTypePointer Function %8 2358 %10 = OpConstant %8 0 2359 %11 = OpTypeFloat 32 2360 %12 = OpTypeInt 32 0 2361 %13 = OpConstant %12 10 2362 %14 = OpTypeArray %11 %13 2363 %15 = OpTypePointer Function %14 2364 %16 = OpTypePointer Function %11 2365 %17 = OpConstant %8 1 2366 %18 = OpConstant %8 10 2367 %19 = OpTypeBool 2368 %2 = OpFunction %6 None %7 2369 %20 = OpLabel 2370 %3 = OpVariable %9 Function 2371 %4 = OpVariable %15 Function 2372 %5 = OpVariable %15 Function 2373 OpStore %3 %10 2374 OpBranch %34 2375 %34 = OpLabel 2376 %35 = OpPhi %8 %10 %20 %43 %44 2377 OpLoopMerge %46 %44 None 2378 OpBranch %36 2379 %36 = OpLabel 2380 %37 = OpAccessChain %16 %5 %35 2381 %38 = OpLoad %11 %37 2382 %39 = OpAccessChain %16 %4 %35 2383 OpStore %39 %38 2384 %43 = OpIAdd %8 %35 %17 2385 OpStore %3 %43 2386 OpBranch %44 2387 %44 = OpLabel 2388 %45 = OpSLessThan %19 %43 %18 2389 OpBranchConditional %45 %34 %46 2390 %46 = OpLabel 2391 OpBranch %21 2392 %21 = OpLabel 2393 %22 = OpPhi %8 %10 %46 %23 %24 2394 OpLoopMerge %25 %24 None 2395 OpBranch %26 2396 %26 = OpLabel 2397 %30 = OpAccessChain %16 %4 %22 2398 %31 = OpLoad %11 %30 2399 %32 = OpAccessChain %16 %5 %22 2400 OpStore %32 %31 2401 %23 = OpIAdd %8 %22 %17 2402 OpStore %3 %23 2403 OpBranch %24 2404 %24 = OpLabel 2405 %33 = OpSLessThan %19 %23 %18 2406 OpBranchConditional %33 %21 %25 2407 %25 = OpLabel 2408 OpReturn 2409 OpFunctionEnd 2410 )"; 2411 // clang-format on 2412 std::unique_ptr<IRContext> context = 2413 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 2414 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 2415 Module* module = context->module(); 2416 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 2417 << source << std::endl; 2418 2419 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 2420 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true); 2421 } 2422 2423 /* 2424 2425 #version 430 2426 void main(void) { 2427 float A[10][10]; 2428 float B[10][10]; 2429 for (int j = 0; j < 10; ++j) { 2430 for (int i = 0; i < 10; ++i) { 2431 B[i][j] = A[i][i]; 2432 A[i][i] = B[i][j + 1]; 2433 } 2434 } 2435 } 2436 2437 2438 This loop can't be split because the load B[i][j + 1] is dependent on the store 2439 B[i][j]. 2440 2441 */ 2442 TEST_F(FissionClassTest, FissionNestedDependency) { 2443 // clang-format off 2444 // With LocalMultiStoreElimPass 2445 const std::string source = R"(OpCapability Shader 2446 %1 = OpExtInstImport "GLSL.std.450" 2447 OpMemoryModel Logical GLSL450 2448 OpEntryPoint Fragment %2 "main" 2449 OpExecutionMode %2 OriginUpperLeft 2450 OpSource GLSL 430 2451 OpName %2 "main" 2452 OpName %3 "j" 2453 OpName %4 "i" 2454 OpName %5 "B" 2455 OpName %6 "A" 2456 %7 = OpTypeVoid 2457 %8 = OpTypeFunction %7 2458 %9 = OpTypeInt 32 1 2459 %10 = OpTypePointer Function %9 2460 %11 = OpConstant %9 0 2461 %12 = OpConstant %9 10 2462 %13 = OpTypeBool 2463 %14 = OpTypeFloat 32 2464 %15 = OpTypeInt 32 0 2465 %16 = OpConstant %15 10 2466 %17 = OpTypeArray %14 %16 2467 %18 = OpTypeArray %17 %16 2468 %19 = OpTypePointer Function %18 2469 %20 = OpTypePointer Function %14 2470 %21 = OpConstant %9 1 2471 %2 = OpFunction %7 None %8 2472 %22 = OpLabel 2473 %3 = OpVariable %10 Function 2474 %4 = OpVariable %10 Function 2475 %5 = OpVariable %19 Function 2476 %6 = OpVariable %19 Function 2477 OpBranch %23 2478 %23 = OpLabel 2479 %24 = OpPhi %9 %11 %22 %25 %26 2480 OpLoopMerge %27 %26 None 2481 OpBranch %28 2482 %28 = OpLabel 2483 %29 = OpSLessThan %13 %24 %12 2484 OpBranchConditional %29 %30 %27 2485 %30 = OpLabel 2486 OpBranch %31 2487 %31 = OpLabel 2488 %32 = OpPhi %9 %11 %30 %33 %34 2489 OpLoopMerge %35 %34 None 2490 OpBranch %36 2491 %36 = OpLabel 2492 %37 = OpSLessThan %13 %32 %12 2493 OpBranchConditional %37 %38 %35 2494 %38 = OpLabel 2495 %39 = OpAccessChain %20 %6 %32 %32 2496 %40 = OpLoad %14 %39 2497 %41 = OpAccessChain %20 %5 %32 %24 2498 OpStore %41 %40 2499 %42 = OpIAdd %9 %24 %21 2500 %43 = OpAccessChain %20 %5 %32 %42 2501 %44 = OpLoad %14 %43 2502 %45 = OpAccessChain %20 %6 %32 %32 2503 OpStore %45 %44 2504 OpBranch %34 2505 %34 = OpLabel 2506 %33 = OpIAdd %9 %32 %21 2507 OpBranch %31 2508 %35 = OpLabel 2509 OpBranch %26 2510 %26 = OpLabel 2511 %25 = OpIAdd %9 %24 %21 2512 OpBranch %23 2513 %27 = OpLabel 2514 OpReturn 2515 OpFunctionEnd 2516 )"; 2517 2518 // clang-format on 2519 std::unique_ptr<IRContext> context = 2520 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 2521 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 2522 Module* module = context->module(); 2523 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 2524 << source << std::endl; 2525 2526 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 2527 SinglePassRunAndCheck<LoopFissionPass>(source, source, true); 2528 } 2529 2530 /* 2531 #version 430 2532 void main(void) { 2533 float A[10][10]; 2534 float B[10][10]; 2535 for (int j = 0; j < 10; ++j) { 2536 for (int i = 0; i < 10; ++i) { 2537 B[i][i] = A[i][j]; 2538 A[i][j+1] = B[i][i]; 2539 } 2540 } 2541 } 2542 2543 This loop should not be split as the load A[i][j+1] would be reading a value 2544 written in the store A[i][j] which would be hit before A[i][j+1] if the loops 2545 where split but would not get hit before the read currently. 2546 2547 */ 2548 TEST_F(FissionClassTest, FissionNestedDependency2) { 2549 // clang-format off 2550 // With LocalMultiStoreElimPass 2551 const std::string source = R"(OpCapability Shader 2552 %1 = OpExtInstImport "GLSL.std.450" 2553 OpMemoryModel Logical GLSL450 2554 OpEntryPoint Fragment %2 "main" 2555 OpExecutionMode %2 OriginUpperLeft 2556 OpSource GLSL 430 2557 OpName %2 "main" 2558 OpName %3 "j" 2559 OpName %4 "i" 2560 OpName %5 "B" 2561 OpName %6 "A" 2562 %7 = OpTypeVoid 2563 %8 = OpTypeFunction %7 2564 %9 = OpTypeInt 32 1 2565 %10 = OpTypePointer Function %9 2566 %11 = OpConstant %9 0 2567 %12 = OpConstant %9 10 2568 %13 = OpTypeBool 2569 %14 = OpTypeFloat 32 2570 %15 = OpTypeInt 32 0 2571 %16 = OpConstant %15 10 2572 %17 = OpTypeArray %14 %16 2573 %18 = OpTypeArray %17 %16 2574 %19 = OpTypePointer Function %18 2575 %20 = OpTypePointer Function %14 2576 %21 = OpConstant %9 1 2577 %2 = OpFunction %7 None %8 2578 %22 = OpLabel 2579 %3 = OpVariable %10 Function 2580 %4 = OpVariable %10 Function 2581 %5 = OpVariable %19 Function 2582 %6 = OpVariable %19 Function 2583 OpStore %3 %11 2584 OpBranch %23 2585 %23 = OpLabel 2586 %24 = OpPhi %9 %11 %22 %25 %26 2587 OpLoopMerge %27 %26 None 2588 OpBranch %28 2589 %28 = OpLabel 2590 %29 = OpSLessThan %13 %24 %12 2591 OpBranchConditional %29 %30 %27 2592 %30 = OpLabel 2593 OpStore %4 %11 2594 OpBranch %31 2595 %31 = OpLabel 2596 %32 = OpPhi %9 %11 %30 %33 %34 2597 OpLoopMerge %35 %34 None 2598 OpBranch %36 2599 %36 = OpLabel 2600 %37 = OpSLessThan %13 %32 %12 2601 OpBranchConditional %37 %38 %35 2602 %38 = OpLabel 2603 %39 = OpAccessChain %20 %6 %32 %24 2604 %40 = OpLoad %14 %39 2605 %41 = OpAccessChain %20 %5 %32 %32 2606 OpStore %41 %40 2607 %42 = OpIAdd %9 %24 %21 2608 %43 = OpAccessChain %20 %5 %32 %32 2609 %44 = OpLoad %14 %43 2610 %45 = OpAccessChain %20 %6 %32 %42 2611 OpStore %45 %44 2612 OpBranch %34 2613 %34 = OpLabel 2614 %33 = OpIAdd %9 %32 %21 2615 OpStore %4 %33 2616 OpBranch %31 2617 %35 = OpLabel 2618 OpBranch %26 2619 %26 = OpLabel 2620 %25 = OpIAdd %9 %24 %21 2621 OpStore %3 %25 2622 OpBranch %23 2623 %27 = OpLabel 2624 OpReturn 2625 OpFunctionEnd 2626 )"; 2627 2628 // clang-format on 2629 std::unique_ptr<IRContext> context = 2630 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 2631 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 2632 Module* module = context->module(); 2633 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 2634 << source << std::endl; 2635 2636 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 2637 SinglePassRunAndCheck<LoopFissionPass>(source, source, true); 2638 } 2639 2640 /* 2641 #version 430 2642 void main(void) { 2643 float A[10][10]; 2644 float B[10][10]; 2645 for (int j = 0; j < 10; ++j) { 2646 for (int i = 0; i < 10; ++i) { 2647 B[i][j] = A[i][j]; 2648 A[i][j] = B[i][j]; 2649 } 2650 for (int i = 0; i < 10; ++i) { 2651 B[i][j] = A[i][j]; 2652 A[i][j] = B[i][j]; 2653 } 2654 } 2655 } 2656 2657 2658 2659 Should be split into: 2660 2661 for (int j = 0; j < 10; ++j) { 2662 for (int i = 0; i < 10; ++i) 2663 B[i][j] = A[i][j]; 2664 for (int i = 0; i < 10; ++i) 2665 A[i][j] = B[i][j]; 2666 for (int i = 0; i < 10; ++i) 2667 B[i][j] = A[i][j]; 2668 for (int i = 0; i < 10; ++i) 2669 A[i][j] = B[i][j]; 2670 */ 2671 TEST_F(FissionClassTest, FissionMultipleLoopsNested) { 2672 // clang-format off 2673 // With LocalMultiStoreElimPass 2674 const std::string source = R"(OpCapability Shader 2675 %1 = OpExtInstImport "GLSL.std.450" 2676 OpMemoryModel Logical GLSL450 2677 OpEntryPoint Fragment %2 "main" 2678 OpExecutionMode %2 OriginUpperLeft 2679 OpSource GLSL 430 2680 OpName %2 "main" 2681 OpName %3 "j" 2682 OpName %4 "i" 2683 OpName %5 "B" 2684 OpName %6 "A" 2685 OpName %7 "i" 2686 %8 = OpTypeVoid 2687 %9 = OpTypeFunction %8 2688 %10 = OpTypeInt 32 1 2689 %11 = OpTypePointer Function %10 2690 %12 = OpConstant %10 0 2691 %13 = OpConstant %10 10 2692 %14 = OpTypeBool 2693 %15 = OpTypeFloat 32 2694 %16 = OpTypeInt 32 0 2695 %17 = OpConstant %16 10 2696 %18 = OpTypeArray %15 %17 2697 %19 = OpTypeArray %18 %17 2698 %20 = OpTypePointer Function %19 2699 %21 = OpTypePointer Function %15 2700 %22 = OpConstant %10 1 2701 %2 = OpFunction %8 None %9 2702 %23 = OpLabel 2703 %3 = OpVariable %11 Function 2704 %4 = OpVariable %11 Function 2705 %5 = OpVariable %20 Function 2706 %6 = OpVariable %20 Function 2707 %7 = OpVariable %11 Function 2708 OpStore %3 %12 2709 OpBranch %24 2710 %24 = OpLabel 2711 %25 = OpPhi %10 %12 %23 %26 %27 2712 OpLoopMerge %28 %27 None 2713 OpBranch %29 2714 %29 = OpLabel 2715 %30 = OpSLessThan %14 %25 %13 2716 OpBranchConditional %30 %31 %28 2717 %31 = OpLabel 2718 OpStore %4 %12 2719 OpBranch %32 2720 %32 = OpLabel 2721 %33 = OpPhi %10 %12 %31 %34 %35 2722 OpLoopMerge %36 %35 None 2723 OpBranch %37 2724 %37 = OpLabel 2725 %38 = OpSLessThan %14 %33 %13 2726 OpBranchConditional %38 %39 %36 2727 %39 = OpLabel 2728 %40 = OpAccessChain %21 %6 %33 %25 2729 %41 = OpLoad %15 %40 2730 %42 = OpAccessChain %21 %5 %33 %25 2731 OpStore %42 %41 2732 %43 = OpAccessChain %21 %5 %33 %25 2733 %44 = OpLoad %15 %43 2734 %45 = OpAccessChain %21 %6 %33 %25 2735 OpStore %45 %44 2736 OpBranch %35 2737 %35 = OpLabel 2738 %34 = OpIAdd %10 %33 %22 2739 OpStore %4 %34 2740 OpBranch %32 2741 %36 = OpLabel 2742 OpStore %7 %12 2743 OpBranch %46 2744 %46 = OpLabel 2745 %47 = OpPhi %10 %12 %36 %48 %49 2746 OpLoopMerge %50 %49 None 2747 OpBranch %51 2748 %51 = OpLabel 2749 %52 = OpSLessThan %14 %47 %13 2750 OpBranchConditional %52 %53 %50 2751 %53 = OpLabel 2752 %54 = OpAccessChain %21 %6 %47 %25 2753 %55 = OpLoad %15 %54 2754 %56 = OpAccessChain %21 %5 %47 %25 2755 OpStore %56 %55 2756 %57 = OpAccessChain %21 %5 %47 %25 2757 %58 = OpLoad %15 %57 2758 %59 = OpAccessChain %21 %6 %47 %25 2759 OpStore %59 %58 2760 OpBranch %49 2761 %49 = OpLabel 2762 %48 = OpIAdd %10 %47 %22 2763 OpStore %7 %48 2764 OpBranch %46 2765 %50 = OpLabel 2766 OpBranch %27 2767 %27 = OpLabel 2768 %26 = OpIAdd %10 %25 %22 2769 OpStore %3 %26 2770 OpBranch %24 2771 %28 = OpLabel 2772 OpReturn 2773 OpFunctionEnd 2774 )"; 2775 2776 const std::string expected = R"(OpCapability Shader 2777 %1 = OpExtInstImport "GLSL.std.450" 2778 OpMemoryModel Logical GLSL450 2779 OpEntryPoint Fragment %2 "main" 2780 OpExecutionMode %2 OriginUpperLeft 2781 OpSource GLSL 430 2782 OpName %2 "main" 2783 OpName %3 "j" 2784 OpName %4 "i" 2785 OpName %5 "B" 2786 OpName %6 "A" 2787 OpName %7 "i" 2788 %8 = OpTypeVoid 2789 %9 = OpTypeFunction %8 2790 %10 = OpTypeInt 32 1 2791 %11 = OpTypePointer Function %10 2792 %12 = OpConstant %10 0 2793 %13 = OpConstant %10 10 2794 %14 = OpTypeBool 2795 %15 = OpTypeFloat 32 2796 %16 = OpTypeInt 32 0 2797 %17 = OpConstant %16 10 2798 %18 = OpTypeArray %15 %17 2799 %19 = OpTypeArray %18 %17 2800 %20 = OpTypePointer Function %19 2801 %21 = OpTypePointer Function %15 2802 %22 = OpConstant %10 1 2803 %2 = OpFunction %8 None %9 2804 %23 = OpLabel 2805 %3 = OpVariable %11 Function 2806 %4 = OpVariable %11 Function 2807 %5 = OpVariable %20 Function 2808 %6 = OpVariable %20 Function 2809 %7 = OpVariable %11 Function 2810 OpStore %3 %12 2811 OpBranch %24 2812 %24 = OpLabel 2813 %25 = OpPhi %10 %12 %23 %26 %27 2814 OpLoopMerge %28 %27 None 2815 OpBranch %29 2816 %29 = OpLabel 2817 %30 = OpSLessThan %14 %25 %13 2818 OpBranchConditional %30 %31 %28 2819 %31 = OpLabel 2820 OpStore %4 %12 2821 OpBranch %60 2822 %60 = OpLabel 2823 %61 = OpPhi %10 %12 %31 %72 %71 2824 OpLoopMerge %73 %71 None 2825 OpBranch %62 2826 %62 = OpLabel 2827 %63 = OpSLessThan %14 %61 %13 2828 OpBranchConditional %63 %64 %73 2829 %64 = OpLabel 2830 %65 = OpAccessChain %21 %6 %61 %25 2831 %66 = OpLoad %15 %65 2832 %67 = OpAccessChain %21 %5 %61 %25 2833 OpStore %67 %66 2834 OpBranch %71 2835 %71 = OpLabel 2836 %72 = OpIAdd %10 %61 %22 2837 OpStore %4 %72 2838 OpBranch %60 2839 %73 = OpLabel 2840 OpBranch %32 2841 %32 = OpLabel 2842 %33 = OpPhi %10 %12 %73 %34 %35 2843 OpLoopMerge %36 %35 None 2844 OpBranch %37 2845 %37 = OpLabel 2846 %38 = OpSLessThan %14 %33 %13 2847 OpBranchConditional %38 %39 %36 2848 %39 = OpLabel 2849 %43 = OpAccessChain %21 %5 %33 %25 2850 %44 = OpLoad %15 %43 2851 %45 = OpAccessChain %21 %6 %33 %25 2852 OpStore %45 %44 2853 OpBranch %35 2854 %35 = OpLabel 2855 %34 = OpIAdd %10 %33 %22 2856 OpStore %4 %34 2857 OpBranch %32 2858 %36 = OpLabel 2859 OpStore %7 %12 2860 OpBranch %74 2861 %74 = OpLabel 2862 %75 = OpPhi %10 %12 %36 %86 %85 2863 OpLoopMerge %87 %85 None 2864 OpBranch %76 2865 %76 = OpLabel 2866 %77 = OpSLessThan %14 %75 %13 2867 OpBranchConditional %77 %78 %87 2868 %78 = OpLabel 2869 %79 = OpAccessChain %21 %6 %75 %25 2870 %80 = OpLoad %15 %79 2871 %81 = OpAccessChain %21 %5 %75 %25 2872 OpStore %81 %80 2873 OpBranch %85 2874 %85 = OpLabel 2875 %86 = OpIAdd %10 %75 %22 2876 OpStore %7 %86 2877 OpBranch %74 2878 %87 = OpLabel 2879 OpBranch %46 2880 %46 = OpLabel 2881 %47 = OpPhi %10 %12 %87 %48 %49 2882 OpLoopMerge %50 %49 None 2883 OpBranch %51 2884 %51 = OpLabel 2885 %52 = OpSLessThan %14 %47 %13 2886 OpBranchConditional %52 %53 %50 2887 %53 = OpLabel 2888 %57 = OpAccessChain %21 %5 %47 %25 2889 %58 = OpLoad %15 %57 2890 %59 = OpAccessChain %21 %6 %47 %25 2891 OpStore %59 %58 2892 OpBranch %49 2893 %49 = OpLabel 2894 %48 = OpIAdd %10 %47 %22 2895 OpStore %7 %48 2896 OpBranch %46 2897 %50 = OpLabel 2898 OpBranch %27 2899 %27 = OpLabel 2900 %26 = OpIAdd %10 %25 %22 2901 OpStore %3 %26 2902 OpBranch %24 2903 %28 = OpLabel 2904 OpReturn 2905 OpFunctionEnd 2906 )"; 2907 // clang-format on 2908 std::unique_ptr<IRContext> context = 2909 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 2910 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 2911 Module* module = context->module(); 2912 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 2913 << source << std::endl; 2914 const Function* function = spvtest::GetFunction(module, 2); 2915 LoopDescriptor& pre_pass_descriptor = *context->GetLoopDescriptor(function); 2916 EXPECT_EQ(pre_pass_descriptor.NumLoops(), 3u); 2917 EXPECT_EQ(pre_pass_descriptor.pre_begin()->NumImmediateChildren(), 2u); 2918 2919 // Test that the pass transforms the ir into the expected output. 2920 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 2921 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true); 2922 2923 // Test that the loop descriptor is correctly maintained and updated by the 2924 // pass. 2925 LoopFissionPass loop_fission; 2926 loop_fission.SetContextForTesting(context.get()); 2927 loop_fission.Process(); 2928 2929 function = spvtest::GetFunction(module, 2); 2930 LoopDescriptor& post_pass_descriptor = *context->GetLoopDescriptor(function); 2931 EXPECT_EQ(post_pass_descriptor.NumLoops(), 5u); 2932 EXPECT_EQ(post_pass_descriptor.pre_begin()->NumImmediateChildren(), 4u); 2933 } 2934 2935 /* 2936 #version 430 2937 void main(void) { 2938 float A[10][10]; 2939 float B[10][10]; 2940 for (int i = 0; i < 10; ++i) { 2941 B[i][i] = A[i][i]; 2942 A[i][i] = B[i][i]; 2943 } 2944 for (int i = 0; i < 10; ++i) { 2945 B[i][i] = A[i][i]; 2946 A[i][i] = B[i][i] 2947 } 2948 } 2949 2950 2951 2952 Should be split into: 2953 2954 for (int i = 0; i < 10; ++i) 2955 B[i][i] = A[i][i]; 2956 for (int i = 0; i < 10; ++i) 2957 A[i][i] = B[i][i]; 2958 for (int i = 0; i < 10; ++i) 2959 B[i][i] = A[i][i]; 2960 for (int i = 0; i < 10; ++i) 2961 A[i][i] = B[i][i]; 2962 */ 2963 TEST_F(FissionClassTest, FissionMultipleLoops) { 2964 // clang-format off 2965 // With LocalMultiStoreElimPass 2966 const std::string source = R"(OpCapability Shader 2967 %1 = OpExtInstImport "GLSL.std.450" 2968 OpMemoryModel Logical GLSL450 2969 OpEntryPoint Fragment %2 "main" 2970 OpExecutionMode %2 OriginUpperLeft 2971 OpSource GLSL 430 2972 OpName %2 "main" 2973 OpName %3 "i" 2974 OpName %4 "B" 2975 OpName %5 "A" 2976 OpName %6 "i" 2977 %7 = OpTypeVoid 2978 %8 = OpTypeFunction %7 2979 %9 = OpTypeInt 32 1 2980 %10 = OpTypePointer Function %9 2981 %11 = OpConstant %9 0 2982 %12 = OpConstant %9 10 2983 %13 = OpTypeBool 2984 %14 = OpTypeFloat 32 2985 %15 = OpTypeInt 32 0 2986 %16 = OpConstant %15 10 2987 %17 = OpTypeArray %14 %16 2988 %18 = OpTypePointer Function %17 2989 %19 = OpTypePointer Function %14 2990 %20 = OpConstant %9 1 2991 %2 = OpFunction %7 None %8 2992 %21 = OpLabel 2993 %3 = OpVariable %10 Function 2994 %4 = OpVariable %18 Function 2995 %5 = OpVariable %18 Function 2996 %6 = OpVariable %10 Function 2997 OpStore %3 %11 2998 OpBranch %22 2999 %22 = OpLabel 3000 %23 = OpPhi %9 %11 %21 %24 %25 3001 OpLoopMerge %26 %25 None 3002 OpBranch %27 3003 %27 = OpLabel 3004 %28 = OpSLessThan %13 %23 %12 3005 OpBranchConditional %28 %29 %26 3006 %29 = OpLabel 3007 %30 = OpAccessChain %19 %5 %23 3008 %31 = OpLoad %14 %30 3009 %32 = OpAccessChain %19 %4 %23 3010 OpStore %32 %31 3011 %33 = OpAccessChain %19 %4 %23 3012 %34 = OpLoad %14 %33 3013 %35 = OpAccessChain %19 %5 %23 3014 OpStore %35 %34 3015 OpBranch %25 3016 %25 = OpLabel 3017 %24 = OpIAdd %9 %23 %20 3018 OpStore %3 %24 3019 OpBranch %22 3020 %26 = OpLabel 3021 OpStore %6 %11 3022 OpBranch %36 3023 %36 = OpLabel 3024 %37 = OpPhi %9 %11 %26 %38 %39 3025 OpLoopMerge %40 %39 None 3026 OpBranch %41 3027 %41 = OpLabel 3028 %42 = OpSLessThan %13 %37 %12 3029 OpBranchConditional %42 %43 %40 3030 %43 = OpLabel 3031 %44 = OpAccessChain %19 %5 %37 3032 %45 = OpLoad %14 %44 3033 %46 = OpAccessChain %19 %4 %37 3034 OpStore %46 %45 3035 %47 = OpAccessChain %19 %4 %37 3036 %48 = OpLoad %14 %47 3037 %49 = OpAccessChain %19 %5 %37 3038 OpStore %49 %48 3039 OpBranch %39 3040 %39 = OpLabel 3041 %38 = OpIAdd %9 %37 %20 3042 OpStore %6 %38 3043 OpBranch %36 3044 %40 = OpLabel 3045 OpReturn 3046 OpFunctionEnd 3047 )"; 3048 3049 const std::string expected = R"(OpCapability Shader 3050 %1 = OpExtInstImport "GLSL.std.450" 3051 OpMemoryModel Logical GLSL450 3052 OpEntryPoint Fragment %2 "main" 3053 OpExecutionMode %2 OriginUpperLeft 3054 OpSource GLSL 430 3055 OpName %2 "main" 3056 OpName %3 "i" 3057 OpName %4 "B" 3058 OpName %5 "A" 3059 OpName %6 "i" 3060 %7 = OpTypeVoid 3061 %8 = OpTypeFunction %7 3062 %9 = OpTypeInt 32 1 3063 %10 = OpTypePointer Function %9 3064 %11 = OpConstant %9 0 3065 %12 = OpConstant %9 10 3066 %13 = OpTypeBool 3067 %14 = OpTypeFloat 32 3068 %15 = OpTypeInt 32 0 3069 %16 = OpConstant %15 10 3070 %17 = OpTypeArray %14 %16 3071 %18 = OpTypePointer Function %17 3072 %19 = OpTypePointer Function %14 3073 %20 = OpConstant %9 1 3074 %2 = OpFunction %7 None %8 3075 %21 = OpLabel 3076 %3 = OpVariable %10 Function 3077 %4 = OpVariable %18 Function 3078 %5 = OpVariable %18 Function 3079 %6 = OpVariable %10 Function 3080 OpStore %3 %11 3081 OpBranch %64 3082 %64 = OpLabel 3083 %65 = OpPhi %9 %11 %21 %76 %75 3084 OpLoopMerge %77 %75 None 3085 OpBranch %66 3086 %66 = OpLabel 3087 %67 = OpSLessThan %13 %65 %12 3088 OpBranchConditional %67 %68 %77 3089 %68 = OpLabel 3090 %69 = OpAccessChain %19 %5 %65 3091 %70 = OpLoad %14 %69 3092 %71 = OpAccessChain %19 %4 %65 3093 OpStore %71 %70 3094 OpBranch %75 3095 %75 = OpLabel 3096 %76 = OpIAdd %9 %65 %20 3097 OpStore %3 %76 3098 OpBranch %64 3099 %77 = OpLabel 3100 OpBranch %22 3101 %22 = OpLabel 3102 %23 = OpPhi %9 %11 %77 %24 %25 3103 OpLoopMerge %26 %25 None 3104 OpBranch %27 3105 %27 = OpLabel 3106 %28 = OpSLessThan %13 %23 %12 3107 OpBranchConditional %28 %29 %26 3108 %29 = OpLabel 3109 %33 = OpAccessChain %19 %4 %23 3110 %34 = OpLoad %14 %33 3111 %35 = OpAccessChain %19 %5 %23 3112 OpStore %35 %34 3113 OpBranch %25 3114 %25 = OpLabel 3115 %24 = OpIAdd %9 %23 %20 3116 OpStore %3 %24 3117 OpBranch %22 3118 %26 = OpLabel 3119 OpStore %6 %11 3120 OpBranch %50 3121 %50 = OpLabel 3122 %51 = OpPhi %9 %11 %26 %62 %61 3123 OpLoopMerge %63 %61 None 3124 OpBranch %52 3125 %52 = OpLabel 3126 %53 = OpSLessThan %13 %51 %12 3127 OpBranchConditional %53 %54 %63 3128 %54 = OpLabel 3129 %55 = OpAccessChain %19 %5 %51 3130 %56 = OpLoad %14 %55 3131 %57 = OpAccessChain %19 %4 %51 3132 OpStore %57 %56 3133 OpBranch %61 3134 %61 = OpLabel 3135 %62 = OpIAdd %9 %51 %20 3136 OpStore %6 %62 3137 OpBranch %50 3138 %63 = OpLabel 3139 OpBranch %36 3140 %36 = OpLabel 3141 %37 = OpPhi %9 %11 %63 %38 %39 3142 OpLoopMerge %40 %39 None 3143 OpBranch %41 3144 %41 = OpLabel 3145 %42 = OpSLessThan %13 %37 %12 3146 OpBranchConditional %42 %43 %40 3147 %43 = OpLabel 3148 %47 = OpAccessChain %19 %4 %37 3149 %48 = OpLoad %14 %47 3150 %49 = OpAccessChain %19 %5 %37 3151 OpStore %49 %48 3152 OpBranch %39 3153 %39 = OpLabel 3154 %38 = OpIAdd %9 %37 %20 3155 OpStore %6 %38 3156 OpBranch %36 3157 %40 = OpLabel 3158 OpReturn 3159 OpFunctionEnd 3160 )"; 3161 // clang-format on 3162 std::unique_ptr<IRContext> context = 3163 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 3164 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 3165 Module* module = context->module(); 3166 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 3167 << source << std::endl; 3168 3169 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 3170 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true); 3171 3172 const Function* function = spvtest::GetFunction(module, 2); 3173 LoopDescriptor& pre_pass_descriptor = *context->GetLoopDescriptor(function); 3174 EXPECT_EQ(pre_pass_descriptor.NumLoops(), 2u); 3175 EXPECT_EQ(pre_pass_descriptor.pre_begin()->NumImmediateChildren(), 0u); 3176 3177 // Test that the pass transforms the ir into the expected output. 3178 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 3179 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true); 3180 3181 // Test that the loop descriptor is correctly maintained and updated by the 3182 // pass. 3183 LoopFissionPass loop_fission; 3184 loop_fission.SetContextForTesting(context.get()); 3185 loop_fission.Process(); 3186 3187 function = spvtest::GetFunction(module, 2); 3188 LoopDescriptor& post_pass_descriptor = *context->GetLoopDescriptor(function); 3189 EXPECT_EQ(post_pass_descriptor.NumLoops(), 4u); 3190 EXPECT_EQ(post_pass_descriptor.pre_begin()->NumImmediateChildren(), 0u); 3191 } 3192 3193 /* 3194 #version 430 3195 int foo() { return 1; } 3196 void main(void) { 3197 float A[10]; 3198 float B[10]; 3199 for (int i = 0; i < 10; ++i) { 3200 B[i] = A[i]; 3201 foo(); 3202 A[i] = B[i]; 3203 } 3204 } 3205 3206 This should not be split as it has a function call in it so we can't determine 3207 if it has side effects. 3208 */ 3209 TEST_F(FissionClassTest, FissionFunctionCall) { 3210 // clang-format off 3211 // With LocalMultiStoreElimPass 3212 const std::string source = R"(OpCapability Shader 3213 %1 = OpExtInstImport "GLSL.std.450" 3214 OpMemoryModel Logical GLSL450 3215 OpEntryPoint Fragment %2 "main" 3216 OpExecutionMode %2 OriginUpperLeft 3217 OpSource GLSL 430 3218 OpName %2 "main" 3219 OpName %3 "foo(" 3220 OpName %4 "i" 3221 OpName %5 "B" 3222 OpName %6 "A" 3223 %7 = OpTypeVoid 3224 %8 = OpTypeFunction %7 3225 %9 = OpTypeInt 32 1 3226 %10 = OpTypeFunction %9 3227 %11 = OpConstant %9 1 3228 %12 = OpTypePointer Function %9 3229 %13 = OpConstant %9 0 3230 %14 = OpConstant %9 10 3231 %15 = OpTypeBool 3232 %16 = OpTypeFloat 32 3233 %17 = OpTypeInt 32 0 3234 %18 = OpConstant %17 10 3235 %19 = OpTypeArray %16 %18 3236 %20 = OpTypePointer Function %19 3237 %21 = OpTypePointer Function %16 3238 %2 = OpFunction %7 None %8 3239 %22 = OpLabel 3240 %4 = OpVariable %12 Function 3241 %5 = OpVariable %20 Function 3242 %6 = OpVariable %20 Function 3243 OpStore %4 %13 3244 OpBranch %23 3245 %23 = OpLabel 3246 %24 = OpPhi %9 %13 %22 %25 %26 3247 OpLoopMerge %27 %26 None 3248 OpBranch %28 3249 %28 = OpLabel 3250 %29 = OpSLessThan %15 %24 %14 3251 OpBranchConditional %29 %30 %27 3252 %30 = OpLabel 3253 %31 = OpAccessChain %21 %6 %24 3254 %32 = OpLoad %16 %31 3255 %33 = OpAccessChain %21 %5 %24 3256 OpStore %33 %32 3257 %34 = OpFunctionCall %9 %3 3258 %35 = OpAccessChain %21 %5 %24 3259 %36 = OpLoad %16 %35 3260 %37 = OpAccessChain %21 %6 %24 3261 OpStore %37 %36 3262 OpBranch %26 3263 %26 = OpLabel 3264 %25 = OpIAdd %9 %24 %11 3265 OpStore %4 %25 3266 OpBranch %23 3267 %27 = OpLabel 3268 OpReturn 3269 OpFunctionEnd 3270 %3 = OpFunction %9 None %10 3271 %38 = OpLabel 3272 OpReturnValue %11 3273 OpFunctionEnd 3274 )"; 3275 3276 // clang-format on 3277 std::unique_ptr<IRContext> context = 3278 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 3279 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 3280 Module* module = context->module(); 3281 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 3282 << source << std::endl; 3283 3284 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 3285 SinglePassRunAndCheck<LoopFissionPass>(source, source, true); 3286 } 3287 3288 /* 3289 #version 430 3290 void main(void) { 3291 float A[10]; 3292 float B[10]; 3293 for (int i = 0; i < 10; ++i) { 3294 switch (i) { 3295 case 1: 3296 B[i] = A[i]; 3297 break; 3298 default: 3299 A[i] = B[i]; 3300 } 3301 } 3302 } 3303 3304 This should be split into: 3305 for (int i = 0; i < 10; ++i) { 3306 switch (i) { 3307 case 1: 3308 break; 3309 default: 3310 A[i] = B[i]; 3311 } 3312 } 3313 3314 for (int i = 0; i < 10; ++i) { 3315 switch (i) { 3316 case 1: 3317 B[i] = A[i]; 3318 break; 3319 default: 3320 break; 3321 } 3322 } 3323 3324 */ 3325 TEST_F(FissionClassTest, FissionSwitchStatement) { 3326 // clang-format off 3327 // With LocalMultiStoreElimPass 3328 const std::string source = R"(OpCapability Shader 3329 %1 = OpExtInstImport "GLSL.std.450" 3330 OpMemoryModel Logical GLSL450 3331 OpEntryPoint Fragment %2 "main" 3332 OpExecutionMode %2 OriginUpperLeft 3333 OpSource GLSL 430 3334 OpName %2 "main" 3335 OpName %3 "i" 3336 OpName %4 "B" 3337 OpName %5 "A" 3338 %6 = OpTypeVoid 3339 %7 = OpTypeFunction %6 3340 %8 = OpTypeInt 32 1 3341 %9 = OpTypePointer Function %8 3342 %10 = OpConstant %8 0 3343 %11 = OpConstant %8 10 3344 %12 = OpTypeBool 3345 %13 = OpTypeFloat 32 3346 %14 = OpTypeInt 32 0 3347 %15 = OpConstant %14 10 3348 %16 = OpTypeArray %13 %15 3349 %17 = OpTypePointer Function %16 3350 %18 = OpTypePointer Function %13 3351 %19 = OpConstant %8 1 3352 %2 = OpFunction %6 None %7 3353 %20 = OpLabel 3354 %3 = OpVariable %9 Function 3355 %4 = OpVariable %17 Function 3356 %5 = OpVariable %17 Function 3357 OpStore %3 %10 3358 OpBranch %21 3359 %21 = OpLabel 3360 %22 = OpPhi %8 %10 %20 %23 %24 3361 OpLoopMerge %25 %24 None 3362 OpBranch %26 3363 %26 = OpLabel 3364 %27 = OpSLessThan %12 %22 %11 3365 OpBranchConditional %27 %28 %25 3366 %28 = OpLabel 3367 OpSelectionMerge %29 None 3368 OpSwitch %22 %30 1 %31 3369 %30 = OpLabel 3370 %32 = OpAccessChain %18 %4 %22 3371 %33 = OpLoad %13 %32 3372 %34 = OpAccessChain %18 %5 %22 3373 OpStore %34 %33 3374 OpBranch %29 3375 %31 = OpLabel 3376 %35 = OpAccessChain %18 %5 %22 3377 %36 = OpLoad %13 %35 3378 %37 = OpAccessChain %18 %4 %22 3379 OpStore %37 %36 3380 OpBranch %29 3381 %29 = OpLabel 3382 OpBranch %24 3383 %24 = OpLabel 3384 %23 = OpIAdd %8 %22 %19 3385 OpStore %3 %23 3386 OpBranch %21 3387 %25 = OpLabel 3388 OpReturn 3389 OpFunctionEnd 3390 )"; 3391 3392 const std::string expected = R"(OpCapability Shader 3393 %1 = OpExtInstImport "GLSL.std.450" 3394 OpMemoryModel Logical GLSL450 3395 OpEntryPoint Fragment %2 "main" 3396 OpExecutionMode %2 OriginUpperLeft 3397 OpSource GLSL 430 3398 OpName %2 "main" 3399 OpName %3 "i" 3400 OpName %4 "B" 3401 OpName %5 "A" 3402 %6 = OpTypeVoid 3403 %7 = OpTypeFunction %6 3404 %8 = OpTypeInt 32 1 3405 %9 = OpTypePointer Function %8 3406 %10 = OpConstant %8 0 3407 %11 = OpConstant %8 10 3408 %12 = OpTypeBool 3409 %13 = OpTypeFloat 32 3410 %14 = OpTypeInt 32 0 3411 %15 = OpConstant %14 10 3412 %16 = OpTypeArray %13 %15 3413 %17 = OpTypePointer Function %16 3414 %18 = OpTypePointer Function %13 3415 %19 = OpConstant %8 1 3416 %2 = OpFunction %6 None %7 3417 %20 = OpLabel 3418 %3 = OpVariable %9 Function 3419 %4 = OpVariable %17 Function 3420 %5 = OpVariable %17 Function 3421 OpStore %3 %10 3422 OpBranch %38 3423 %38 = OpLabel 3424 %39 = OpPhi %8 %10 %20 %53 %52 3425 OpLoopMerge %54 %52 None 3426 OpBranch %40 3427 %40 = OpLabel 3428 %41 = OpSLessThan %12 %39 %11 3429 OpBranchConditional %41 %42 %54 3430 %42 = OpLabel 3431 OpSelectionMerge %51 None 3432 OpSwitch %39 %47 1 %43 3433 %43 = OpLabel 3434 OpBranch %51 3435 %47 = OpLabel 3436 %48 = OpAccessChain %18 %4 %39 3437 %49 = OpLoad %13 %48 3438 %50 = OpAccessChain %18 %5 %39 3439 OpStore %50 %49 3440 OpBranch %51 3441 %51 = OpLabel 3442 OpBranch %52 3443 %52 = OpLabel 3444 %53 = OpIAdd %8 %39 %19 3445 OpStore %3 %53 3446 OpBranch %38 3447 %54 = OpLabel 3448 OpBranch %21 3449 %21 = OpLabel 3450 %22 = OpPhi %8 %10 %54 %23 %24 3451 OpLoopMerge %25 %24 None 3452 OpBranch %26 3453 %26 = OpLabel 3454 %27 = OpSLessThan %12 %22 %11 3455 OpBranchConditional %27 %28 %25 3456 %28 = OpLabel 3457 OpSelectionMerge %29 None 3458 OpSwitch %22 %30 1 %31 3459 %30 = OpLabel 3460 OpBranch %29 3461 %31 = OpLabel 3462 %35 = OpAccessChain %18 %5 %22 3463 %36 = OpLoad %13 %35 3464 %37 = OpAccessChain %18 %4 %22 3465 OpStore %37 %36 3466 OpBranch %29 3467 %29 = OpLabel 3468 OpBranch %24 3469 %24 = OpLabel 3470 %23 = OpIAdd %8 %22 %19 3471 OpStore %3 %23 3472 OpBranch %21 3473 %25 = OpLabel 3474 OpReturn 3475 OpFunctionEnd 3476 )"; 3477 // clang-format on 3478 std::unique_ptr<IRContext> context = 3479 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, source, 3480 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 3481 Module* module = context->module(); 3482 EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n" 3483 << source << std::endl; 3484 3485 SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER); 3486 SinglePassRunAndCheck<LoopFissionPass>(source, expected, true); 3487 } 3488 3489 } // namespace 3490 } // namespace opt 3491 } // namespace spvtools 3492