1 // Copyright (c) 2017 Valve Corporation 2 // Copyright (c) 2017 LunarG Inc. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 #include <memory> 17 #include <string> 18 19 #include "test/opt/pass_fixture.h" 20 #include "test/opt/pass_utils.h" 21 22 namespace spvtools { 23 namespace opt { 24 namespace { 25 26 using LocalSSAElimTest = PassTest<::testing::Test>; 27 28 TEST_F(LocalSSAElimTest, ForLoop) { 29 // #version 140 30 // 31 // in vec4 BC; 32 // out float fo; 33 // 34 // void main() 35 // { 36 // float f = 0.0; 37 // for (int i=0; i<4; i++) { 38 // f = f + BC[i]; 39 // } 40 // fo = f; 41 // } 42 43 const std::string predefs = 44 R"(OpCapability Shader 45 %1 = OpExtInstImport "GLSL.std.450" 46 OpMemoryModel Logical GLSL450 47 OpEntryPoint Fragment %main "main" %BC %fo 48 OpExecutionMode %main OriginUpperLeft 49 OpSource GLSL 140 50 OpName %main "main" 51 OpName %f "f" 52 OpName %i "i" 53 OpName %BC "BC" 54 OpName %fo "fo" 55 %void = OpTypeVoid 56 %8 = OpTypeFunction %void 57 %float = OpTypeFloat 32 58 %_ptr_Function_float = OpTypePointer Function %float 59 %float_0 = OpConstant %float 0 60 %int = OpTypeInt 32 1 61 %_ptr_Function_int = OpTypePointer Function %int 62 %int_0 = OpConstant %int 0 63 %int_4 = OpConstant %int 4 64 %bool = OpTypeBool 65 %v4float = OpTypeVector %float 4 66 %_ptr_Input_v4float = OpTypePointer Input %v4float 67 %BC = OpVariable %_ptr_Input_v4float Input 68 %_ptr_Input_float = OpTypePointer Input %float 69 %int_1 = OpConstant %int 1 70 %_ptr_Output_float = OpTypePointer Output %float 71 %fo = OpVariable %_ptr_Output_float Output 72 )"; 73 74 const std::string before = 75 R"(%main = OpFunction %void None %8 76 %22 = OpLabel 77 %f = OpVariable %_ptr_Function_float Function 78 %i = OpVariable %_ptr_Function_int Function 79 OpStore %f %float_0 80 OpStore %i %int_0 81 OpBranch %23 82 %23 = OpLabel 83 OpLoopMerge %24 %25 None 84 OpBranch %26 85 %26 = OpLabel 86 %27 = OpLoad %int %i 87 %28 = OpSLessThan %bool %27 %int_4 88 OpBranchConditional %28 %29 %24 89 %29 = OpLabel 90 %30 = OpLoad %float %f 91 %31 = OpLoad %int %i 92 %32 = OpAccessChain %_ptr_Input_float %BC %31 93 %33 = OpLoad %float %32 94 %34 = OpFAdd %float %30 %33 95 OpStore %f %34 96 OpBranch %25 97 %25 = OpLabel 98 %35 = OpLoad %int %i 99 %36 = OpIAdd %int %35 %int_1 100 OpStore %i %36 101 OpBranch %23 102 %24 = OpLabel 103 %37 = OpLoad %float %f 104 OpStore %fo %37 105 OpReturn 106 OpFunctionEnd 107 )"; 108 109 const std::string after = 110 R"(%main = OpFunction %void None %8 111 %22 = OpLabel 112 %f = OpVariable %_ptr_Function_float Function 113 %i = OpVariable %_ptr_Function_int Function 114 OpStore %f %float_0 115 OpStore %i %int_0 116 OpBranch %23 117 %23 = OpLabel 118 %39 = OpPhi %float %float_0 %22 %34 %25 119 %38 = OpPhi %int %int_0 %22 %36 %25 120 OpLoopMerge %24 %25 None 121 OpBranch %26 122 %26 = OpLabel 123 %28 = OpSLessThan %bool %38 %int_4 124 OpBranchConditional %28 %29 %24 125 %29 = OpLabel 126 %32 = OpAccessChain %_ptr_Input_float %BC %38 127 %33 = OpLoad %float %32 128 %34 = OpFAdd %float %39 %33 129 OpStore %f %34 130 OpBranch %25 131 %25 = OpLabel 132 %36 = OpIAdd %int %38 %int_1 133 OpStore %i %36 134 OpBranch %23 135 %24 = OpLabel 136 OpStore %fo %39 137 OpReturn 138 OpFunctionEnd 139 )"; 140 141 SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before, 142 predefs + after, true, true); 143 } 144 145 TEST_F(LocalSSAElimTest, NestedForLoop) { 146 // #version 450 147 // 148 // layout (location=0) in mat4 BC; 149 // layout (location=0) out float fo; 150 // 151 // void main() 152 // { 153 // float f = 0.0; 154 // for (int i=0; i<4; i++) 155 // for (int j=0; j<4; j++) 156 // f = f + BC[i][j]; 157 // fo = f; 158 // } 159 160 const std::string predefs = 161 R"(OpCapability Shader 162 %1 = OpExtInstImport "GLSL.std.450" 163 OpMemoryModel Logical GLSL450 164 OpEntryPoint Fragment %main "main" %BC %fo 165 OpExecutionMode %main OriginUpperLeft 166 OpSource GLSL 450 167 OpName %main "main" 168 OpName %f "f" 169 OpName %i "i" 170 OpName %j "j" 171 OpName %BC "BC" 172 OpName %fo "fo" 173 OpDecorate %BC Location 0 174 OpDecorate %fo Location 0 175 %void = OpTypeVoid 176 %9 = OpTypeFunction %void 177 %float = OpTypeFloat 32 178 %_ptr_Function_float = OpTypePointer Function %float 179 %float_0 = OpConstant %float 0 180 %int = OpTypeInt 32 1 181 %_ptr_Function_int = OpTypePointer Function %int 182 %int_0 = OpConstant %int 0 183 %int_4 = OpConstant %int 4 184 %bool = OpTypeBool 185 %v4float = OpTypeVector %float 4 186 %mat4v4float = OpTypeMatrix %v4float 4 187 %_ptr_Input_mat4v4float = OpTypePointer Input %mat4v4float 188 %BC = OpVariable %_ptr_Input_mat4v4float Input 189 %_ptr_Input_float = OpTypePointer Input %float 190 %int_1 = OpConstant %int 1 191 %_ptr_Output_float = OpTypePointer Output %float 192 %fo = OpVariable %_ptr_Output_float Output 193 )"; 194 195 const std::string before = 196 R"(%main = OpFunction %void None %9 197 %24 = OpLabel 198 %f = OpVariable %_ptr_Function_float Function 199 %i = OpVariable %_ptr_Function_int Function 200 %j = OpVariable %_ptr_Function_int Function 201 OpStore %f %float_0 202 OpStore %i %int_0 203 OpBranch %25 204 %25 = OpLabel 205 %26 = OpLoad %int %i 206 %27 = OpSLessThan %bool %26 %int_4 207 OpLoopMerge %28 %29 None 208 OpBranchConditional %27 %30 %28 209 %30 = OpLabel 210 OpStore %j %int_0 211 OpBranch %31 212 %31 = OpLabel 213 %32 = OpLoad %int %j 214 %33 = OpSLessThan %bool %32 %int_4 215 OpLoopMerge %29 %34 None 216 OpBranchConditional %33 %34 %29 217 %34 = OpLabel 218 %35 = OpLoad %float %f 219 %36 = OpLoad %int %i 220 %37 = OpLoad %int %j 221 %38 = OpAccessChain %_ptr_Input_float %BC %36 %37 222 %39 = OpLoad %float %38 223 %40 = OpFAdd %float %35 %39 224 OpStore %f %40 225 %41 = OpLoad %int %j 226 %42 = OpIAdd %int %41 %int_1 227 OpStore %j %42 228 OpBranch %31 229 %29 = OpLabel 230 %43 = OpLoad %int %i 231 %44 = OpIAdd %int %43 %int_1 232 OpStore %i %44 233 OpBranch %25 234 %28 = OpLabel 235 %45 = OpLoad %float %f 236 OpStore %fo %45 237 OpReturn 238 OpFunctionEnd 239 )"; 240 241 const std::string after = 242 R"(%main = OpFunction %void None %9 243 %24 = OpLabel 244 %f = OpVariable %_ptr_Function_float Function 245 %i = OpVariable %_ptr_Function_int Function 246 %j = OpVariable %_ptr_Function_int Function 247 OpStore %f %float_0 248 OpStore %i %int_0 249 OpBranch %25 250 %25 = OpLabel 251 %47 = OpPhi %float %float_0 %24 %50 %29 252 %46 = OpPhi %int %int_0 %24 %44 %29 253 %27 = OpSLessThan %bool %46 %int_4 254 OpLoopMerge %28 %29 None 255 OpBranchConditional %27 %30 %28 256 %30 = OpLabel 257 OpStore %j %int_0 258 OpBranch %31 259 %31 = OpLabel 260 %50 = OpPhi %float %47 %30 %40 %34 261 %48 = OpPhi %int %int_0 %30 %42 %34 262 %33 = OpSLessThan %bool %48 %int_4 263 OpLoopMerge %29 %34 None 264 OpBranchConditional %33 %34 %29 265 %34 = OpLabel 266 %38 = OpAccessChain %_ptr_Input_float %BC %46 %48 267 %39 = OpLoad %float %38 268 %40 = OpFAdd %float %50 %39 269 OpStore %f %40 270 %42 = OpIAdd %int %48 %int_1 271 OpStore %j %42 272 OpBranch %31 273 %29 = OpLabel 274 %44 = OpIAdd %int %46 %int_1 275 OpStore %i %44 276 OpBranch %25 277 %28 = OpLabel 278 OpStore %fo %47 279 OpReturn 280 OpFunctionEnd 281 )"; 282 283 SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before, 284 predefs + after, true, true); 285 } 286 287 TEST_F(LocalSSAElimTest, ForLoopWithContinue) { 288 // #version 140 289 // 290 // in vec4 BC; 291 // out float fo; 292 // 293 // void main() 294 // { 295 // float f = 0.0; 296 // for (int i=0; i<4; i++) { 297 // float t = BC[i]; 298 // if (t < 0.0) 299 // continue; 300 // f = f + t; 301 // } 302 // fo = f; 303 // } 304 305 const std::string predefs = 306 R"(OpCapability Shader 307 %1 = OpExtInstImport "GLSL.std.450" 308 OpMemoryModel Logical GLSL450 309 OpEntryPoint Fragment %main "main" %BC %fo 310 OpExecutionMode %main OriginUpperLeft 311 OpSource GLSL 140 312 )"; 313 314 const std::string names = 315 R"(OpName %main "main" 316 OpName %f "f" 317 OpName %i "i" 318 OpName %t "t" 319 OpName %BC "BC" 320 OpName %fo "fo" 321 )"; 322 323 const std::string predefs2 = 324 R"(%void = OpTypeVoid 325 %9 = OpTypeFunction %void 326 %float = OpTypeFloat 32 327 %_ptr_Function_float = OpTypePointer Function %float 328 %float_0 = OpConstant %float 0 329 %int = OpTypeInt 32 1 330 %_ptr_Function_int = OpTypePointer Function %int 331 %int_0 = OpConstant %int 0 332 %int_4 = OpConstant %int 4 333 %bool = OpTypeBool 334 %v4float = OpTypeVector %float 4 335 %_ptr_Input_v4float = OpTypePointer Input %v4float 336 %BC = OpVariable %_ptr_Input_v4float Input 337 %_ptr_Input_float = OpTypePointer Input %float 338 %int_1 = OpConstant %int 1 339 %_ptr_Output_float = OpTypePointer Output %float 340 %fo = OpVariable %_ptr_Output_float Output 341 )"; 342 343 const std::string before = 344 R"(%main = OpFunction %void None %9 345 %23 = OpLabel 346 %f = OpVariable %_ptr_Function_float Function 347 %i = OpVariable %_ptr_Function_int Function 348 %t = OpVariable %_ptr_Function_float Function 349 OpStore %f %float_0 350 OpStore %i %int_0 351 OpBranch %24 352 %24 = OpLabel 353 OpLoopMerge %25 %26 None 354 OpBranch %27 355 %27 = OpLabel 356 %28 = OpLoad %int %i 357 %29 = OpSLessThan %bool %28 %int_4 358 OpBranchConditional %29 %30 %25 359 %30 = OpLabel 360 %31 = OpLoad %int %i 361 %32 = OpAccessChain %_ptr_Input_float %BC %31 362 %33 = OpLoad %float %32 363 OpStore %t %33 364 %34 = OpLoad %float %t 365 %35 = OpFOrdLessThan %bool %34 %float_0 366 OpSelectionMerge %36 None 367 OpBranchConditional %35 %37 %36 368 %37 = OpLabel 369 OpBranch %26 370 %36 = OpLabel 371 %38 = OpLoad %float %f 372 %39 = OpLoad %float %t 373 %40 = OpFAdd %float %38 %39 374 OpStore %f %40 375 OpBranch %26 376 %26 = OpLabel 377 %41 = OpLoad %int %i 378 %42 = OpIAdd %int %41 %int_1 379 OpStore %i %42 380 OpBranch %24 381 %25 = OpLabel 382 %43 = OpLoad %float %f 383 OpStore %fo %43 384 OpReturn 385 OpFunctionEnd 386 )"; 387 388 const std::string after = 389 R"(%main = OpFunction %void None %9 390 %23 = OpLabel 391 %f = OpVariable %_ptr_Function_float Function 392 %i = OpVariable %_ptr_Function_int Function 393 %t = OpVariable %_ptr_Function_float Function 394 OpStore %f %float_0 395 OpStore %i %int_0 396 OpBranch %24 397 %24 = OpLabel 398 %45 = OpPhi %float %float_0 %23 %47 %26 399 %44 = OpPhi %int %int_0 %23 %42 %26 400 OpLoopMerge %25 %26 None 401 OpBranch %27 402 %27 = OpLabel 403 %29 = OpSLessThan %bool %44 %int_4 404 OpBranchConditional %29 %30 %25 405 %30 = OpLabel 406 %32 = OpAccessChain %_ptr_Input_float %BC %44 407 %33 = OpLoad %float %32 408 OpStore %t %33 409 %35 = OpFOrdLessThan %bool %33 %float_0 410 OpSelectionMerge %36 None 411 OpBranchConditional %35 %37 %36 412 %37 = OpLabel 413 OpBranch %26 414 %36 = OpLabel 415 %40 = OpFAdd %float %45 %33 416 OpStore %f %40 417 OpBranch %26 418 %26 = OpLabel 419 %47 = OpPhi %float %45 %37 %40 %36 420 %42 = OpIAdd %int %44 %int_1 421 OpStore %i %42 422 OpBranch %24 423 %25 = OpLabel 424 OpStore %fo %45 425 OpReturn 426 OpFunctionEnd 427 )"; 428 429 SinglePassRunAndCheck<LocalMultiStoreElimPass>( 430 predefs + names + predefs2 + before, predefs + names + predefs2 + after, 431 true, true); 432 } 433 434 TEST_F(LocalSSAElimTest, ForLoopWithBreak) { 435 // #version 140 436 // 437 // in vec4 BC; 438 // out float fo; 439 // 440 // void main() 441 // { 442 // float f = 0.0; 443 // for (int i=0; i<4; i++) { 444 // float t = f + BC[i]; 445 // if (t > 1.0) 446 // break; 447 // f = t; 448 // } 449 // fo = f; 450 // } 451 452 const std::string predefs = 453 R"(OpCapability Shader 454 %1 = OpExtInstImport "GLSL.std.450" 455 OpMemoryModel Logical GLSL450 456 OpEntryPoint Fragment %main "main" %BC %fo 457 OpExecutionMode %main OriginUpperLeft 458 OpSource GLSL 140 459 OpName %main "main" 460 OpName %f "f" 461 OpName %i "i" 462 OpName %t "t" 463 OpName %BC "BC" 464 OpName %fo "fo" 465 %void = OpTypeVoid 466 %9 = OpTypeFunction %void 467 %float = OpTypeFloat 32 468 %_ptr_Function_float = OpTypePointer Function %float 469 %float_0 = OpConstant %float 0 470 %int = OpTypeInt 32 1 471 %_ptr_Function_int = OpTypePointer Function %int 472 %int_0 = OpConstant %int 0 473 %int_4 = OpConstant %int 4 474 %bool = OpTypeBool 475 %v4float = OpTypeVector %float 4 476 %_ptr_Input_v4float = OpTypePointer Input %v4float 477 %BC = OpVariable %_ptr_Input_v4float Input 478 %_ptr_Input_float = OpTypePointer Input %float 479 %float_1 = OpConstant %float 1 480 %int_1 = OpConstant %int 1 481 %_ptr_Output_float = OpTypePointer Output %float 482 %fo = OpVariable %_ptr_Output_float Output 483 )"; 484 485 const std::string before = 486 R"(%main = OpFunction %void None %9 487 %24 = OpLabel 488 %f = OpVariable %_ptr_Function_float Function 489 %i = OpVariable %_ptr_Function_int Function 490 %t = OpVariable %_ptr_Function_float Function 491 OpStore %f %float_0 492 OpStore %i %int_0 493 OpBranch %25 494 %25 = OpLabel 495 OpLoopMerge %26 %27 None 496 OpBranch %28 497 %28 = OpLabel 498 %29 = OpLoad %int %i 499 %30 = OpSLessThan %bool %29 %int_4 500 OpBranchConditional %30 %31 %26 501 %31 = OpLabel 502 %32 = OpLoad %float %f 503 %33 = OpLoad %int %i 504 %34 = OpAccessChain %_ptr_Input_float %BC %33 505 %35 = OpLoad %float %34 506 %36 = OpFAdd %float %32 %35 507 OpStore %t %36 508 %37 = OpLoad %float %t 509 %38 = OpFOrdGreaterThan %bool %37 %float_1 510 OpSelectionMerge %39 None 511 OpBranchConditional %38 %40 %39 512 %40 = OpLabel 513 OpBranch %26 514 %39 = OpLabel 515 %41 = OpLoad %float %t 516 OpStore %f %41 517 OpBranch %27 518 %27 = OpLabel 519 %42 = OpLoad %int %i 520 %43 = OpIAdd %int %42 %int_1 521 OpStore %i %43 522 OpBranch %25 523 %26 = OpLabel 524 %44 = OpLoad %float %f 525 OpStore %fo %44 526 OpReturn 527 OpFunctionEnd 528 )"; 529 530 const std::string after = 531 R"(%main = OpFunction %void None %9 532 %24 = OpLabel 533 %f = OpVariable %_ptr_Function_float Function 534 %i = OpVariable %_ptr_Function_int Function 535 %t = OpVariable %_ptr_Function_float Function 536 OpStore %f %float_0 537 OpStore %i %int_0 538 OpBranch %25 539 %25 = OpLabel 540 %46 = OpPhi %float %float_0 %24 %36 %27 541 %45 = OpPhi %int %int_0 %24 %43 %27 542 OpLoopMerge %26 %27 None 543 OpBranch %28 544 %28 = OpLabel 545 %30 = OpSLessThan %bool %45 %int_4 546 OpBranchConditional %30 %31 %26 547 %31 = OpLabel 548 %34 = OpAccessChain %_ptr_Input_float %BC %45 549 %35 = OpLoad %float %34 550 %36 = OpFAdd %float %46 %35 551 OpStore %t %36 552 %38 = OpFOrdGreaterThan %bool %36 %float_1 553 OpSelectionMerge %39 None 554 OpBranchConditional %38 %40 %39 555 %40 = OpLabel 556 OpBranch %26 557 %39 = OpLabel 558 OpStore %f %36 559 OpBranch %27 560 %27 = OpLabel 561 %43 = OpIAdd %int %45 %int_1 562 OpStore %i %43 563 OpBranch %25 564 %26 = OpLabel 565 OpStore %fo %46 566 OpReturn 567 OpFunctionEnd 568 )"; 569 570 SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before, 571 predefs + after, true, true); 572 } 573 574 TEST_F(LocalSSAElimTest, SwapProblem) { 575 // #version 140 576 // 577 // in float fe; 578 // out float fo; 579 // 580 // void main() 581 // { 582 // float f1 = 0.0; 583 // float f2 = 1.0; 584 // int ie = int(fe); 585 // for (int i=0; i<ie; i++) { 586 // float t = f1; 587 // f1 = f2; 588 // f2 = t; 589 // } 590 // fo = f1; 591 // } 592 593 const std::string predefs = 594 R"(OpCapability Shader 595 %1 = OpExtInstImport "GLSL.std.450" 596 OpMemoryModel Logical GLSL450 597 OpEntryPoint Fragment %main "main" %fe %fo 598 OpExecutionMode %main OriginUpperLeft 599 OpSource GLSL 140 600 OpName %main "main" 601 OpName %f1 "f1" 602 OpName %f2 "f2" 603 OpName %ie "ie" 604 OpName %fe "fe" 605 OpName %i "i" 606 OpName %t "t" 607 OpName %fo "fo" 608 %void = OpTypeVoid 609 %11 = OpTypeFunction %void 610 %float = OpTypeFloat 32 611 %_ptr_Function_float = OpTypePointer Function %float 612 %float_0 = OpConstant %float 0 613 %float_1 = OpConstant %float 1 614 %int = OpTypeInt 32 1 615 %_ptr_Function_int = OpTypePointer Function %int 616 %_ptr_Input_float = OpTypePointer Input %float 617 %fe = OpVariable %_ptr_Input_float Input 618 %int_0 = OpConstant %int 0 619 %bool = OpTypeBool 620 %int_1 = OpConstant %int 1 621 %_ptr_Output_float = OpTypePointer Output %float 622 %fo = OpVariable %_ptr_Output_float Output 623 )"; 624 625 const std::string before = 626 R"(%main = OpFunction %void None %11 627 %23 = OpLabel 628 %f1 = OpVariable %_ptr_Function_float Function 629 %f2 = OpVariable %_ptr_Function_float Function 630 %ie = OpVariable %_ptr_Function_int Function 631 %i = OpVariable %_ptr_Function_int Function 632 %t = OpVariable %_ptr_Function_float Function 633 OpStore %f1 %float_0 634 OpStore %f2 %float_1 635 %24 = OpLoad %float %fe 636 %25 = OpConvertFToS %int %24 637 OpStore %ie %25 638 OpStore %i %int_0 639 OpBranch %26 640 %26 = OpLabel 641 OpLoopMerge %27 %28 None 642 OpBranch %29 643 %29 = OpLabel 644 %30 = OpLoad %int %i 645 %31 = OpLoad %int %ie 646 %32 = OpSLessThan %bool %30 %31 647 OpBranchConditional %32 %33 %27 648 %33 = OpLabel 649 %34 = OpLoad %float %f1 650 OpStore %t %34 651 %35 = OpLoad %float %f2 652 OpStore %f1 %35 653 %36 = OpLoad %float %t 654 OpStore %f2 %36 655 OpBranch %28 656 %28 = OpLabel 657 %37 = OpLoad %int %i 658 %38 = OpIAdd %int %37 %int_1 659 OpStore %i %38 660 OpBranch %26 661 %27 = OpLabel 662 %39 = OpLoad %float %f1 663 OpStore %fo %39 664 OpReturn 665 OpFunctionEnd 666 )"; 667 668 const std::string after = 669 R"(%main = OpFunction %void None %11 670 %23 = OpLabel 671 %f1 = OpVariable %_ptr_Function_float Function 672 %f2 = OpVariable %_ptr_Function_float Function 673 %ie = OpVariable %_ptr_Function_int Function 674 %i = OpVariable %_ptr_Function_int Function 675 %t = OpVariable %_ptr_Function_float Function 676 OpStore %f1 %float_0 677 OpStore %f2 %float_1 678 %24 = OpLoad %float %fe 679 %25 = OpConvertFToS %int %24 680 OpStore %ie %25 681 OpStore %i %int_0 682 OpBranch %26 683 %26 = OpLabel 684 %43 = OpPhi %float %float_1 %23 %42 %28 685 %42 = OpPhi %float %float_0 %23 %43 %28 686 %40 = OpPhi %int %int_0 %23 %38 %28 687 OpLoopMerge %27 %28 None 688 OpBranch %29 689 %29 = OpLabel 690 %32 = OpSLessThan %bool %40 %25 691 OpBranchConditional %32 %33 %27 692 %33 = OpLabel 693 OpStore %t %42 694 OpStore %f1 %43 695 OpStore %f2 %42 696 OpBranch %28 697 %28 = OpLabel 698 %38 = OpIAdd %int %40 %int_1 699 OpStore %i %38 700 OpBranch %26 701 %27 = OpLabel 702 OpStore %fo %42 703 OpReturn 704 OpFunctionEnd 705 )"; 706 707 SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before, 708 predefs + after, true, true); 709 } 710 711 TEST_F(LocalSSAElimTest, LostCopyProblem) { 712 // #version 140 713 // 714 // in vec4 BC; 715 // out float fo; 716 // 717 // void main() 718 // { 719 // float f = 0.0; 720 // float t; 721 // for (int i=0; i<4; i++) { 722 // t = f; 723 // f = f + BC[i]; 724 // if (f > 1.0) 725 // break; 726 // } 727 // fo = t; 728 // } 729 730 const std::string predefs = 731 R"(OpCapability Shader 732 %1 = OpExtInstImport "GLSL.std.450" 733 OpMemoryModel Logical GLSL450 734 OpEntryPoint Fragment %main "main" %BC %fo 735 OpExecutionMode %main OriginUpperLeft 736 OpSource GLSL 140 737 OpName %main "main" 738 OpName %f "f" 739 OpName %i "i" 740 OpName %t "t" 741 OpName %BC "BC" 742 OpName %fo "fo" 743 %void = OpTypeVoid 744 %9 = OpTypeFunction %void 745 %float = OpTypeFloat 32 746 %_ptr_Function_float = OpTypePointer Function %float 747 %float_0 = OpConstant %float 0 748 %int = OpTypeInt 32 1 749 %_ptr_Function_int = OpTypePointer Function %int 750 %int_0 = OpConstant %int 0 751 %int_4 = OpConstant %int 4 752 %bool = OpTypeBool 753 %v4float = OpTypeVector %float 4 754 %_ptr_Input_v4float = OpTypePointer Input %v4float 755 %BC = OpVariable %_ptr_Input_v4float Input 756 %_ptr_Input_float = OpTypePointer Input %float 757 %float_1 = OpConstant %float 1 758 %int_1 = OpConstant %int 1 759 %_ptr_Output_float = OpTypePointer Output %float 760 %fo = OpVariable %_ptr_Output_float Output 761 )"; 762 763 const std::string before = 764 R"(%main = OpFunction %void None %9 765 %24 = OpLabel 766 %f = OpVariable %_ptr_Function_float Function 767 %i = OpVariable %_ptr_Function_int Function 768 %t = OpVariable %_ptr_Function_float Function 769 OpStore %f %float_0 770 OpStore %i %int_0 771 OpBranch %25 772 %25 = OpLabel 773 OpLoopMerge %26 %27 None 774 OpBranch %28 775 %28 = OpLabel 776 %29 = OpLoad %int %i 777 %30 = OpSLessThan %bool %29 %int_4 778 OpBranchConditional %30 %31 %26 779 %31 = OpLabel 780 %32 = OpLoad %float %f 781 OpStore %t %32 782 %33 = OpLoad %float %f 783 %34 = OpLoad %int %i 784 %35 = OpAccessChain %_ptr_Input_float %BC %34 785 %36 = OpLoad %float %35 786 %37 = OpFAdd %float %33 %36 787 OpStore %f %37 788 %38 = OpLoad %float %f 789 %39 = OpFOrdGreaterThan %bool %38 %float_1 790 OpSelectionMerge %40 None 791 OpBranchConditional %39 %41 %40 792 %41 = OpLabel 793 OpBranch %26 794 %40 = OpLabel 795 OpBranch %27 796 %27 = OpLabel 797 %42 = OpLoad %int %i 798 %43 = OpIAdd %int %42 %int_1 799 OpStore %i %43 800 OpBranch %25 801 %26 = OpLabel 802 %44 = OpLoad %float %t 803 OpStore %fo %44 804 OpReturn 805 OpFunctionEnd 806 )"; 807 808 const std::string after = 809 R"(%49 = OpUndef %float 810 %main = OpFunction %void None %9 811 %24 = OpLabel 812 %f = OpVariable %_ptr_Function_float Function 813 %i = OpVariable %_ptr_Function_int Function 814 %t = OpVariable %_ptr_Function_float Function 815 OpStore %f %float_0 816 OpStore %i %int_0 817 OpBranch %25 818 %25 = OpLabel 819 %46 = OpPhi %float %float_0 %24 %37 %27 820 %45 = OpPhi %int %int_0 %24 %43 %27 821 %48 = OpPhi %float %49 %24 %46 %27 822 OpLoopMerge %26 %27 None 823 OpBranch %28 824 %28 = OpLabel 825 %30 = OpSLessThan %bool %45 %int_4 826 OpBranchConditional %30 %31 %26 827 %31 = OpLabel 828 OpStore %t %46 829 %35 = OpAccessChain %_ptr_Input_float %BC %45 830 %36 = OpLoad %float %35 831 %37 = OpFAdd %float %46 %36 832 OpStore %f %37 833 %39 = OpFOrdGreaterThan %bool %37 %float_1 834 OpSelectionMerge %40 None 835 OpBranchConditional %39 %41 %40 836 %41 = OpLabel 837 OpBranch %26 838 %40 = OpLabel 839 OpBranch %27 840 %27 = OpLabel 841 %43 = OpIAdd %int %45 %int_1 842 OpStore %i %43 843 OpBranch %25 844 %26 = OpLabel 845 %47 = OpPhi %float %48 %28 %46 %41 846 OpStore %fo %47 847 OpReturn 848 OpFunctionEnd 849 )"; 850 851 SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before, 852 predefs + after, true, true); 853 } 854 855 TEST_F(LocalSSAElimTest, IfThenElse) { 856 // #version 140 857 // 858 // in vec4 BaseColor; 859 // in float f; 860 // 861 // void main() 862 // { 863 // vec4 v; 864 // if (f >= 0) 865 // v = BaseColor * 0.5; 866 // else 867 // v = BaseColor + vec4(1.0,1.0,1.0,1.0); 868 // gl_FragColor = v; 869 // } 870 871 const std::string predefs = 872 R"(OpCapability Shader 873 %1 = OpExtInstImport "GLSL.std.450" 874 OpMemoryModel Logical GLSL450 875 OpEntryPoint Fragment %main "main" %f %BaseColor %gl_FragColor 876 OpExecutionMode %main OriginUpperLeft 877 OpSource GLSL 140 878 OpName %main "main" 879 OpName %f "f" 880 OpName %v "v" 881 OpName %BaseColor "BaseColor" 882 OpName %gl_FragColor "gl_FragColor" 883 %void = OpTypeVoid 884 %8 = OpTypeFunction %void 885 %float = OpTypeFloat 32 886 %_ptr_Input_float = OpTypePointer Input %float 887 %f = OpVariable %_ptr_Input_float Input 888 %float_0 = OpConstant %float 0 889 %bool = OpTypeBool 890 %v4float = OpTypeVector %float 4 891 %_ptr_Function_v4float = OpTypePointer Function %v4float 892 %_ptr_Input_v4float = OpTypePointer Input %v4float 893 %BaseColor = OpVariable %_ptr_Input_v4float Input 894 %float_0_5 = OpConstant %float 0.5 895 %float_1 = OpConstant %float 1 896 %18 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1 897 %_ptr_Output_v4float = OpTypePointer Output %v4float 898 %gl_FragColor = OpVariable %_ptr_Output_v4float Output 899 )"; 900 901 const std::string before = 902 R"(%main = OpFunction %void None %8 903 %20 = OpLabel 904 %v = OpVariable %_ptr_Function_v4float Function 905 %21 = OpLoad %float %f 906 %22 = OpFOrdGreaterThanEqual %bool %21 %float_0 907 OpSelectionMerge %23 None 908 OpBranchConditional %22 %24 %25 909 %24 = OpLabel 910 %26 = OpLoad %v4float %BaseColor 911 %27 = OpVectorTimesScalar %v4float %26 %float_0_5 912 OpStore %v %27 913 OpBranch %23 914 %25 = OpLabel 915 %28 = OpLoad %v4float %BaseColor 916 %29 = OpFAdd %v4float %28 %18 917 OpStore %v %29 918 OpBranch %23 919 %23 = OpLabel 920 %30 = OpLoad %v4float %v 921 OpStore %gl_FragColor %30 922 OpReturn 923 OpFunctionEnd 924 )"; 925 926 const std::string after = 927 R"(%main = OpFunction %void None %8 928 %20 = OpLabel 929 %v = OpVariable %_ptr_Function_v4float Function 930 %21 = OpLoad %float %f 931 %22 = OpFOrdGreaterThanEqual %bool %21 %float_0 932 OpSelectionMerge %23 None 933 OpBranchConditional %22 %24 %25 934 %24 = OpLabel 935 %26 = OpLoad %v4float %BaseColor 936 %27 = OpVectorTimesScalar %v4float %26 %float_0_5 937 OpStore %v %27 938 OpBranch %23 939 %25 = OpLabel 940 %28 = OpLoad %v4float %BaseColor 941 %29 = OpFAdd %v4float %28 %18 942 OpStore %v %29 943 OpBranch %23 944 %23 = OpLabel 945 %31 = OpPhi %v4float %27 %24 %29 %25 946 OpStore %gl_FragColor %31 947 OpReturn 948 OpFunctionEnd 949 )"; 950 951 SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before, 952 predefs + after, true, true); 953 } 954 955 TEST_F(LocalSSAElimTest, IfThen) { 956 // #version 140 957 // 958 // in vec4 BaseColor; 959 // in float f; 960 // 961 // void main() 962 // { 963 // vec4 v = BaseColor; 964 // if (f <= 0) 965 // v = v * 0.5; 966 // gl_FragColor = v; 967 // } 968 969 const std::string predefs = 970 R"(OpCapability Shader 971 %1 = OpExtInstImport "GLSL.std.450" 972 OpMemoryModel Logical GLSL450 973 OpEntryPoint Fragment %main "main" %BaseColor %f %gl_FragColor 974 OpExecutionMode %main OriginUpperLeft 975 OpSource GLSL 140 976 OpName %main "main" 977 OpName %v "v" 978 OpName %BaseColor "BaseColor" 979 OpName %f "f" 980 OpName %gl_FragColor "gl_FragColor" 981 %void = OpTypeVoid 982 %8 = OpTypeFunction %void 983 %float = OpTypeFloat 32 984 %v4float = OpTypeVector %float 4 985 %_ptr_Function_v4float = OpTypePointer Function %v4float 986 %_ptr_Input_v4float = OpTypePointer Input %v4float 987 %BaseColor = OpVariable %_ptr_Input_v4float Input 988 %_ptr_Input_float = OpTypePointer Input %float 989 %f = OpVariable %_ptr_Input_float Input 990 %float_0 = OpConstant %float 0 991 %bool = OpTypeBool 992 %float_0_5 = OpConstant %float 0.5 993 %_ptr_Output_v4float = OpTypePointer Output %v4float 994 %gl_FragColor = OpVariable %_ptr_Output_v4float Output 995 )"; 996 997 const std::string before = 998 R"(%main = OpFunction %void None %8 999 %18 = OpLabel 1000 %v = OpVariable %_ptr_Function_v4float Function 1001 %19 = OpLoad %v4float %BaseColor 1002 OpStore %v %19 1003 %20 = OpLoad %float %f 1004 %21 = OpFOrdLessThanEqual %bool %20 %float_0 1005 OpSelectionMerge %22 None 1006 OpBranchConditional %21 %23 %22 1007 %23 = OpLabel 1008 %24 = OpLoad %v4float %v 1009 %25 = OpVectorTimesScalar %v4float %24 %float_0_5 1010 OpStore %v %25 1011 OpBranch %22 1012 %22 = OpLabel 1013 %26 = OpLoad %v4float %v 1014 OpStore %gl_FragColor %26 1015 OpReturn 1016 OpFunctionEnd 1017 )"; 1018 1019 const std::string after = 1020 R"(%main = OpFunction %void None %8 1021 %18 = OpLabel 1022 %v = OpVariable %_ptr_Function_v4float Function 1023 %19 = OpLoad %v4float %BaseColor 1024 OpStore %v %19 1025 %20 = OpLoad %float %f 1026 %21 = OpFOrdLessThanEqual %bool %20 %float_0 1027 OpSelectionMerge %22 None 1028 OpBranchConditional %21 %23 %22 1029 %23 = OpLabel 1030 %25 = OpVectorTimesScalar %v4float %19 %float_0_5 1031 OpStore %v %25 1032 OpBranch %22 1033 %22 = OpLabel 1034 %27 = OpPhi %v4float %19 %18 %25 %23 1035 OpStore %gl_FragColor %27 1036 OpReturn 1037 OpFunctionEnd 1038 )"; 1039 1040 SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before, 1041 predefs + after, true, true); 1042 } 1043 1044 TEST_F(LocalSSAElimTest, Switch) { 1045 // #version 140 1046 // 1047 // in vec4 BaseColor; 1048 // in float f; 1049 // 1050 // void main() 1051 // { 1052 // vec4 v = BaseColor; 1053 // int i = int(f); 1054 // switch (i) { 1055 // case 0: 1056 // v = v * 0.25; 1057 // break; 1058 // case 1: 1059 // v = v * 0.625; 1060 // break; 1061 // case 2: 1062 // v = v * 0.75; 1063 // break; 1064 // default: 1065 // break; 1066 // } 1067 // gl_FragColor = v; 1068 // } 1069 1070 const std::string predefs = 1071 R"(OpCapability Shader 1072 %1 = OpExtInstImport "GLSL.std.450" 1073 OpMemoryModel Logical GLSL450 1074 OpEntryPoint Fragment %main "main" %BaseColor %f %gl_FragColor 1075 OpExecutionMode %main OriginUpperLeft 1076 OpSource GLSL 140 1077 OpName %main "main" 1078 OpName %v "v" 1079 OpName %BaseColor "BaseColor" 1080 OpName %i "i" 1081 OpName %f "f" 1082 OpName %gl_FragColor "gl_FragColor" 1083 %void = OpTypeVoid 1084 %9 = OpTypeFunction %void 1085 %float = OpTypeFloat 32 1086 %v4float = OpTypeVector %float 4 1087 %_ptr_Function_v4float = OpTypePointer Function %v4float 1088 %_ptr_Input_v4float = OpTypePointer Input %v4float 1089 %BaseColor = OpVariable %_ptr_Input_v4float Input 1090 %int = OpTypeInt 32 1 1091 %_ptr_Function_int = OpTypePointer Function %int 1092 %_ptr_Input_float = OpTypePointer Input %float 1093 %f = OpVariable %_ptr_Input_float Input 1094 %float_0_25 = OpConstant %float 0.25 1095 %float_0_625 = OpConstant %float 0.625 1096 %float_0_75 = OpConstant %float 0.75 1097 %_ptr_Output_v4float = OpTypePointer Output %v4float 1098 %gl_FragColor = OpVariable %_ptr_Output_v4float Output 1099 )"; 1100 1101 const std::string before = 1102 R"(%main = OpFunction %void None %9 1103 %21 = OpLabel 1104 %v = OpVariable %_ptr_Function_v4float Function 1105 %i = OpVariable %_ptr_Function_int Function 1106 %22 = OpLoad %v4float %BaseColor 1107 OpStore %v %22 1108 %23 = OpLoad %float %f 1109 %24 = OpConvertFToS %int %23 1110 OpStore %i %24 1111 %25 = OpLoad %int %i 1112 OpSelectionMerge %26 None 1113 OpSwitch %25 %27 0 %28 1 %29 2 %30 1114 %27 = OpLabel 1115 OpBranch %26 1116 %28 = OpLabel 1117 %31 = OpLoad %v4float %v 1118 %32 = OpVectorTimesScalar %v4float %31 %float_0_25 1119 OpStore %v %32 1120 OpBranch %26 1121 %29 = OpLabel 1122 %33 = OpLoad %v4float %v 1123 %34 = OpVectorTimesScalar %v4float %33 %float_0_625 1124 OpStore %v %34 1125 OpBranch %26 1126 %30 = OpLabel 1127 %35 = OpLoad %v4float %v 1128 %36 = OpVectorTimesScalar %v4float %35 %float_0_75 1129 OpStore %v %36 1130 OpBranch %26 1131 %26 = OpLabel 1132 %37 = OpLoad %v4float %v 1133 OpStore %gl_FragColor %37 1134 OpReturn 1135 OpFunctionEnd 1136 )"; 1137 1138 const std::string after = 1139 R"(%main = OpFunction %void None %9 1140 %21 = OpLabel 1141 %v = OpVariable %_ptr_Function_v4float Function 1142 %i = OpVariable %_ptr_Function_int Function 1143 %22 = OpLoad %v4float %BaseColor 1144 OpStore %v %22 1145 %23 = OpLoad %float %f 1146 %24 = OpConvertFToS %int %23 1147 OpStore %i %24 1148 OpSelectionMerge %26 None 1149 OpSwitch %24 %27 0 %28 1 %29 2 %30 1150 %27 = OpLabel 1151 OpBranch %26 1152 %28 = OpLabel 1153 %32 = OpVectorTimesScalar %v4float %22 %float_0_25 1154 OpStore %v %32 1155 OpBranch %26 1156 %29 = OpLabel 1157 %34 = OpVectorTimesScalar %v4float %22 %float_0_625 1158 OpStore %v %34 1159 OpBranch %26 1160 %30 = OpLabel 1161 %36 = OpVectorTimesScalar %v4float %22 %float_0_75 1162 OpStore %v %36 1163 OpBranch %26 1164 %26 = OpLabel 1165 %38 = OpPhi %v4float %22 %27 %32 %28 %34 %29 %36 %30 1166 OpStore %gl_FragColor %38 1167 OpReturn 1168 OpFunctionEnd 1169 )"; 1170 1171 SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before, 1172 predefs + after, true, true); 1173 } 1174 1175 TEST_F(LocalSSAElimTest, SwitchWithFallThrough) { 1176 // #version 140 1177 // 1178 // in vec4 BaseColor; 1179 // in float f; 1180 // 1181 // void main() 1182 // { 1183 // vec4 v = BaseColor; 1184 // int i = int(f); 1185 // switch (i) { 1186 // case 0: 1187 // v = v * 0.25; 1188 // break; 1189 // case 1: 1190 // v = v + 0.25; 1191 // case 2: 1192 // v = v * 0.75; 1193 // break; 1194 // default: 1195 // break; 1196 // } 1197 // gl_FragColor = v; 1198 // } 1199 1200 const std::string predefs = 1201 R"(OpCapability Shader 1202 %1 = OpExtInstImport "GLSL.std.450" 1203 OpMemoryModel Logical GLSL450 1204 OpEntryPoint Fragment %main "main" %BaseColor %f %gl_FragColor 1205 OpExecutionMode %main OriginUpperLeft 1206 OpSource GLSL 140 1207 OpName %main "main" 1208 OpName %v "v" 1209 OpName %BaseColor "BaseColor" 1210 OpName %i "i" 1211 OpName %f "f" 1212 OpName %gl_FragColor "gl_FragColor" 1213 %void = OpTypeVoid 1214 %9 = OpTypeFunction %void 1215 %float = OpTypeFloat 32 1216 %v4float = OpTypeVector %float 4 1217 %_ptr_Function_v4float = OpTypePointer Function %v4float 1218 %_ptr_Input_v4float = OpTypePointer Input %v4float 1219 %BaseColor = OpVariable %_ptr_Input_v4float Input 1220 %int = OpTypeInt 32 1 1221 %_ptr_Function_int = OpTypePointer Function %int 1222 %_ptr_Input_float = OpTypePointer Input %float 1223 %f = OpVariable %_ptr_Input_float Input 1224 %float_0_25 = OpConstant %float 0.25 1225 %float_0_75 = OpConstant %float 0.75 1226 %_ptr_Output_v4float = OpTypePointer Output %v4float 1227 %gl_FragColor = OpVariable %_ptr_Output_v4float Output 1228 )"; 1229 1230 const std::string before = 1231 R"(%main = OpFunction %void None %9 1232 %20 = OpLabel 1233 %v = OpVariable %_ptr_Function_v4float Function 1234 %i = OpVariable %_ptr_Function_int Function 1235 %21 = OpLoad %v4float %BaseColor 1236 OpStore %v %21 1237 %22 = OpLoad %float %f 1238 %23 = OpConvertFToS %int %22 1239 OpStore %i %23 1240 %24 = OpLoad %int %i 1241 OpSelectionMerge %25 None 1242 OpSwitch %24 %26 0 %27 1 %28 2 %29 1243 %26 = OpLabel 1244 OpBranch %25 1245 %27 = OpLabel 1246 %30 = OpLoad %v4float %v 1247 %31 = OpVectorTimesScalar %v4float %30 %float_0_25 1248 OpStore %v %31 1249 OpBranch %25 1250 %28 = OpLabel 1251 %32 = OpLoad %v4float %v 1252 %33 = OpCompositeConstruct %v4float %float_0_25 %float_0_25 %float_0_25 %float_0_25 1253 %34 = OpFAdd %v4float %32 %33 1254 OpStore %v %34 1255 OpBranch %29 1256 %29 = OpLabel 1257 %35 = OpLoad %v4float %v 1258 %36 = OpVectorTimesScalar %v4float %35 %float_0_75 1259 OpStore %v %36 1260 OpBranch %25 1261 %25 = OpLabel 1262 %37 = OpLoad %v4float %v 1263 OpStore %gl_FragColor %37 1264 OpReturn 1265 OpFunctionEnd 1266 )"; 1267 1268 const std::string after = 1269 R"(%main = OpFunction %void None %9 1270 %20 = OpLabel 1271 %v = OpVariable %_ptr_Function_v4float Function 1272 %i = OpVariable %_ptr_Function_int Function 1273 %21 = OpLoad %v4float %BaseColor 1274 OpStore %v %21 1275 %22 = OpLoad %float %f 1276 %23 = OpConvertFToS %int %22 1277 OpStore %i %23 1278 OpSelectionMerge %25 None 1279 OpSwitch %23 %26 0 %27 1 %28 2 %29 1280 %26 = OpLabel 1281 OpBranch %25 1282 %27 = OpLabel 1283 %31 = OpVectorTimesScalar %v4float %21 %float_0_25 1284 OpStore %v %31 1285 OpBranch %25 1286 %28 = OpLabel 1287 %33 = OpCompositeConstruct %v4float %float_0_25 %float_0_25 %float_0_25 %float_0_25 1288 %34 = OpFAdd %v4float %21 %33 1289 OpStore %v %34 1290 OpBranch %29 1291 %29 = OpLabel 1292 %38 = OpPhi %v4float %21 %20 %34 %28 1293 %36 = OpVectorTimesScalar %v4float %38 %float_0_75 1294 OpStore %v %36 1295 OpBranch %25 1296 %25 = OpLabel 1297 %39 = OpPhi %v4float %21 %26 %31 %27 %36 %29 1298 OpStore %gl_FragColor %39 1299 OpReturn 1300 OpFunctionEnd 1301 )"; 1302 1303 SinglePassRunAndCheck<LocalMultiStoreElimPass>(predefs + before, 1304 predefs + after, true, true); 1305 } 1306 1307 TEST_F(LocalSSAElimTest, DontPatchPhiInLoopHeaderThatIsNotAVar) { 1308 // From https://github.com/KhronosGroup/SPIRV-Tools/issues/826 1309 // Don't try patching the (%16 %7) value/predecessor pair in the OpPhi. 1310 // That OpPhi is unrelated to this optimization: we did not set that up 1311 // in the SSA initialization for the loop header block. 1312 // The pass should be a no-op on this module. 1313 1314 const std::string before = R"(OpCapability Shader 1315 OpMemoryModel Logical GLSL450 1316 OpEntryPoint GLCompute %1 "main" 1317 %void = OpTypeVoid 1318 %3 = OpTypeFunction %void 1319 %float = OpTypeFloat 32 1320 %float_1 = OpConstant %float 1 1321 %1 = OpFunction %void None %3 1322 %6 = OpLabel 1323 OpBranch %7 1324 %7 = OpLabel 1325 %8 = OpPhi %float %float_1 %6 %9 %7 1326 %9 = OpFAdd %float %8 %float_1 1327 OpLoopMerge %10 %7 None 1328 OpBranch %7 1329 %10 = OpLabel 1330 OpReturn 1331 OpFunctionEnd 1332 )"; 1333 1334 SinglePassRunAndCheck<LocalMultiStoreElimPass>(before, before, true, true); 1335 } 1336 1337 TEST_F(LocalSSAElimTest, OptInitializedVariableLikeStore) { 1338 // Note: SPIR-V edited to change store to v into variable initialization 1339 // 1340 // #version 450 1341 // 1342 // layout (location=0) in vec4 iColor; 1343 // layout (location=1) in float fi; 1344 // layout (location=0) out vec4 oColor; 1345 // 1346 // void main() 1347 // { 1348 // vec4 v = vec4(0.0); 1349 // if (fi < 0.0) 1350 // v.x = iColor.x; 1351 // oColor = v; 1352 // } 1353 1354 const std::string predefs = 1355 R"(OpCapability Shader 1356 %1 = OpExtInstImport "GLSL.std.450" 1357 OpMemoryModel Logical GLSL450 1358 OpEntryPoint Fragment %main "main" %fi %iColor %oColor 1359 OpExecutionMode %main OriginUpperLeft 1360 OpSource GLSL 450 1361 OpName %main "main" 1362 OpName %v "v" 1363 OpName %fi "fi" 1364 OpName %iColor "iColor" 1365 OpName %oColor "oColor" 1366 OpDecorate %fi Location 1 1367 OpDecorate %iColor Location 0 1368 OpDecorate %oColor Location 0 1369 %void = OpTypeVoid 1370 %8 = OpTypeFunction %void 1371 %float = OpTypeFloat 32 1372 %v4float = OpTypeVector %float 4 1373 %_ptr_Function_v4float = OpTypePointer Function %v4float 1374 %float_0 = OpConstant %float 0 1375 %13 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0 1376 %_ptr_Input_float = OpTypePointer Input %float 1377 %fi = OpVariable %_ptr_Input_float Input 1378 %bool = OpTypeBool 1379 %_ptr_Input_v4float = OpTypePointer Input %v4float 1380 %iColor = OpVariable %_ptr_Input_v4float Input 1381 %uint = OpTypeInt 32 0 1382 %uint_0 = OpConstant %uint 0 1383 %_ptr_Function_float = OpTypePointer Function %float 1384 %_ptr_Output_v4float = OpTypePointer Output %v4float 1385 %oColor = OpVariable %_ptr_Output_v4float Output 1386 )"; 1387 1388 const std::string func_before = 1389 R"(%main = OpFunction %void None %8 1390 %21 = OpLabel 1391 %v = OpVariable %_ptr_Function_v4float Function %13 1392 %22 = OpLoad %float %fi 1393 %23 = OpFOrdLessThan %bool %22 %float_0 1394 OpSelectionMerge %24 None 1395 OpBranchConditional %23 %25 %24 1396 %25 = OpLabel 1397 %26 = OpAccessChain %_ptr_Input_float %iColor %uint_0 1398 %27 = OpLoad %float %26 1399 %28 = OpLoad %v4float %v 1400 %29 = OpCompositeInsert %v4float %27 %28 0 1401 OpStore %v %29 1402 OpBranch %24 1403 %24 = OpLabel 1404 %30 = OpLoad %v4float %v 1405 OpStore %oColor %30 1406 OpReturn 1407 OpFunctionEnd 1408 )"; 1409 1410 const std::string func_after = 1411 R"(%main = OpFunction %void None %8 1412 %21 = OpLabel 1413 %v = OpVariable %_ptr_Function_v4float Function %13 1414 %22 = OpLoad %float %fi 1415 %23 = OpFOrdLessThan %bool %22 %float_0 1416 OpSelectionMerge %24 None 1417 OpBranchConditional %23 %25 %24 1418 %25 = OpLabel 1419 %26 = OpAccessChain %_ptr_Input_float %iColor %uint_0 1420 %27 = OpLoad %float %26 1421 %29 = OpCompositeInsert %v4float %27 %13 0 1422 OpStore %v %29 1423 OpBranch %24 1424 %24 = OpLabel 1425 %31 = OpPhi %v4float %13 %21 %29 %25 1426 OpStore %oColor %31 1427 OpReturn 1428 OpFunctionEnd 1429 )"; 1430 1431 SinglePassRunAndCheck<LocalMultiStoreElimPass>( 1432 predefs + func_before, predefs + func_after, true, true); 1433 } 1434 1435 TEST_F(LocalSSAElimTest, PointerVariable) { 1436 // Test that checks if a pointer variable is removed. 1437 1438 const std::string before = 1439 R"(OpCapability Shader 1440 OpMemoryModel Logical GLSL450 1441 OpEntryPoint Fragment %1 "main" %2 1442 OpExecutionMode %1 OriginUpperLeft 1443 OpMemberDecorate %_struct_3 0 Offset 0 1444 OpDecorate %_runtimearr__struct_3 ArrayStride 16 1445 OpMemberDecorate %_struct_5 0 Offset 0 1446 OpDecorate %_struct_5 BufferBlock 1447 OpMemberDecorate %_struct_6 0 Offset 0 1448 OpDecorate %_struct_6 BufferBlock 1449 OpDecorate %2 Location 0 1450 OpDecorate %7 DescriptorSet 0 1451 OpDecorate %7 Binding 0 1452 %void = OpTypeVoid 1453 %10 = OpTypeFunction %void 1454 %int = OpTypeInt 32 1 1455 %uint = OpTypeInt 32 0 1456 %float = OpTypeFloat 32 1457 %v4float = OpTypeVector %float 4 1458 %_ptr_Output_v4float = OpTypePointer Output %v4float 1459 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float 1460 %_struct_3 = OpTypeStruct %v4float 1461 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3 1462 %_struct_5 = OpTypeStruct %_runtimearr__struct_3 1463 %_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5 1464 %_struct_6 = OpTypeStruct %int 1465 %_ptr_Uniform__struct_6 = OpTypePointer Uniform %_struct_6 1466 %_ptr_Function__ptr_Uniform__struct_5 = OpTypePointer Function %_ptr_Uniform__struct_5 1467 %_ptr_Function__ptr_Uniform__struct_6 = OpTypePointer Function %_ptr_Uniform__struct_6 1468 %int_0 = OpConstant %int 0 1469 %uint_0 = OpConstant %uint 0 1470 %2 = OpVariable %_ptr_Output_v4float Output 1471 %7 = OpVariable %_ptr_Uniform__struct_5 Uniform 1472 %1 = OpFunction %void None %10 1473 %23 = OpLabel 1474 %24 = OpVariable %_ptr_Function__ptr_Uniform__struct_5 Function 1475 OpStore %24 %7 1476 %26 = OpLoad %_ptr_Uniform__struct_5 %24 1477 %27 = OpAccessChain %_ptr_Uniform_v4float %26 %int_0 %uint_0 %int_0 1478 %28 = OpLoad %v4float %27 1479 %29 = OpCopyObject %v4float %28 1480 OpStore %2 %28 1481 OpReturn 1482 OpFunctionEnd 1483 )"; 1484 1485 const std::string after = 1486 R"(OpCapability Shader 1487 OpMemoryModel Logical GLSL450 1488 OpEntryPoint Fragment %1 "main" %2 1489 OpExecutionMode %1 OriginUpperLeft 1490 OpMemberDecorate %_struct_3 0 Offset 0 1491 OpDecorate %_runtimearr__struct_3 ArrayStride 16 1492 OpMemberDecorate %_struct_5 0 Offset 0 1493 OpDecorate %_struct_5 BufferBlock 1494 OpMemberDecorate %_struct_6 0 Offset 0 1495 OpDecorate %_struct_6 BufferBlock 1496 OpDecorate %2 Location 0 1497 OpDecorate %7 DescriptorSet 0 1498 OpDecorate %7 Binding 0 1499 %void = OpTypeVoid 1500 %10 = OpTypeFunction %void 1501 %int = OpTypeInt 32 1 1502 %uint = OpTypeInt 32 0 1503 %float = OpTypeFloat 32 1504 %v4float = OpTypeVector %float 4 1505 %_ptr_Output_v4float = OpTypePointer Output %v4float 1506 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float 1507 %_struct_3 = OpTypeStruct %v4float 1508 %_runtimearr__struct_3 = OpTypeRuntimeArray %_struct_3 1509 %_struct_5 = OpTypeStruct %_runtimearr__struct_3 1510 %_ptr_Uniform__struct_5 = OpTypePointer Uniform %_struct_5 1511 %_struct_6 = OpTypeStruct %int 1512 %_ptr_Uniform__struct_6 = OpTypePointer Uniform %_struct_6 1513 %_ptr_Function__ptr_Uniform__struct_5 = OpTypePointer Function %_ptr_Uniform__struct_5 1514 %_ptr_Function__ptr_Uniform__struct_6 = OpTypePointer Function %_ptr_Uniform__struct_6 1515 %int_0 = OpConstant %int 0 1516 %uint_0 = OpConstant %uint 0 1517 %2 = OpVariable %_ptr_Output_v4float Output 1518 %7 = OpVariable %_ptr_Uniform__struct_5 Uniform 1519 %1 = OpFunction %void None %10 1520 %23 = OpLabel 1521 %24 = OpVariable %_ptr_Function__ptr_Uniform__struct_5 Function 1522 OpStore %24 %7 1523 %27 = OpAccessChain %_ptr_Uniform_v4float %7 %int_0 %uint_0 %int_0 1524 %28 = OpLoad %v4float %27 1525 %29 = OpCopyObject %v4float %28 1526 OpStore %2 %28 1527 OpReturn 1528 OpFunctionEnd 1529 )"; 1530 1531 // Relax logical pointers to allow pointer allocations. 1532 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1533 ValidatorOptions()->relax_logical_pointer = true; 1534 SinglePassRunAndCheck<LocalMultiStoreElimPass>(before, after, true, true); 1535 } 1536 1537 TEST_F(LocalSSAElimTest, VerifyInstToBlockMap) { 1538 // #version 140 1539 // 1540 // in vec4 BC; 1541 // out float fo; 1542 // 1543 // void main() 1544 // { 1545 // float f = 0.0; 1546 // for (int i=0; i<4; i++) { 1547 // f = f + BC[i]; 1548 // } 1549 // fo = f; 1550 // } 1551 1552 const std::string text = R"( 1553 OpCapability Shader 1554 %1 = OpExtInstImport "GLSL.std.450" 1555 OpMemoryModel Logical GLSL450 1556 OpEntryPoint Fragment %main "main" %BC %fo 1557 OpExecutionMode %main OriginUpperLeft 1558 OpSource GLSL 140 1559 OpName %main "main" 1560 OpName %f "f" 1561 OpName %i "i" 1562 OpName %BC "BC" 1563 OpName %fo "fo" 1564 %void = OpTypeVoid 1565 %8 = OpTypeFunction %void 1566 %float = OpTypeFloat 32 1567 %_ptr_Function_float = OpTypePointer Function %float 1568 %float_0 = OpConstant %float 0 1569 %int = OpTypeInt 32 1 1570 %_ptr_Function_int = OpTypePointer Function %int 1571 %int_0 = OpConstant %int 0 1572 %int_4 = OpConstant %int 4 1573 %bool = OpTypeBool 1574 %v4float = OpTypeVector %float 4 1575 %_ptr_Input_v4float = OpTypePointer Input %v4float 1576 %BC = OpVariable %_ptr_Input_v4float Input 1577 %_ptr_Input_float = OpTypePointer Input %float 1578 %int_1 = OpConstant %int 1 1579 %_ptr_Output_float = OpTypePointer Output %float 1580 %fo = OpVariable %_ptr_Output_float Output 1581 %main = OpFunction %void None %8 1582 %22 = OpLabel 1583 %f = OpVariable %_ptr_Function_float Function 1584 %i = OpVariable %_ptr_Function_int Function 1585 OpStore %f %float_0 1586 OpStore %i %int_0 1587 OpBranch %23 1588 %23 = OpLabel 1589 OpLoopMerge %24 %25 None 1590 OpBranch %26 1591 %26 = OpLabel 1592 %27 = OpLoad %int %i 1593 %28 = OpSLessThan %bool %27 %int_4 1594 OpBranchConditional %28 %29 %24 1595 %29 = OpLabel 1596 %30 = OpLoad %float %f 1597 %31 = OpLoad %int %i 1598 %32 = OpAccessChain %_ptr_Input_float %BC %31 1599 %33 = OpLoad %float %32 1600 %34 = OpFAdd %float %30 %33 1601 OpStore %f %34 1602 OpBranch %25 1603 %25 = OpLabel 1604 %35 = OpLoad %int %i 1605 %36 = OpIAdd %int %35 %int_1 1606 OpStore %i %36 1607 OpBranch %23 1608 %24 = OpLabel 1609 %37 = OpLoad %float %f 1610 OpStore %fo %37 1611 OpReturn 1612 OpFunctionEnd 1613 )"; 1614 1615 std::unique_ptr<IRContext> context = 1616 BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text, 1617 SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 1618 EXPECT_NE(nullptr, context); 1619 1620 // Force the instruction to block mapping to get built. 1621 context->get_instr_block(27u); 1622 1623 auto pass = MakeUnique<LocalMultiStoreElimPass>(); 1624 pass->SetMessageConsumer(nullptr); 1625 const auto status = pass->Run(context.get()); 1626 EXPECT_TRUE(status == Pass::Status::SuccessWithChange); 1627 } 1628 1629 TEST_F(LocalSSAElimTest, CompositeExtractProblem) { 1630 const std::string spv_asm = R"( 1631 OpCapability Tessellation 1632 %1 = OpExtInstImport "GLSL.std.450" 1633 OpMemoryModel Logical GLSL450 1634 OpEntryPoint TessellationControl %2 "main" %16 %17 %18 %20 %22 %26 %27 %30 %31 1635 %void = OpTypeVoid 1636 %4 = OpTypeFunction %void 1637 %float = OpTypeFloat 32 1638 %v4float = OpTypeVector %float 4 1639 %uint = OpTypeInt 32 0 1640 %uint_3 = OpConstant %uint 3 1641 %v3float = OpTypeVector %float 3 1642 %v2float = OpTypeVector %float 2 1643 %_struct_11 = OpTypeStruct %v4float %v4float %v4float %v3float %v3float %v2float %v2float 1644 %_arr__struct_11_uint_3 = OpTypeArray %_struct_11 %uint_3 1645 %_ptr_Function__arr__struct_11_uint_3 = OpTypePointer Function %_arr__struct_11_uint_3 1646 %_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3 1647 %_ptr_Input__arr_v4float_uint_3 = OpTypePointer Input %_arr_v4float_uint_3 1648 %16 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input 1649 %17 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input 1650 %18 = OpVariable %_ptr_Input__arr_v4float_uint_3 Input 1651 %_ptr_Input_uint = OpTypePointer Input %uint 1652 %20 = OpVariable %_ptr_Input_uint Input 1653 %_ptr_Output__arr_v4float_uint_3 = OpTypePointer Output %_arr_v4float_uint_3 1654 %22 = OpVariable %_ptr_Output__arr_v4float_uint_3 Output 1655 %_ptr_Output_v4float = OpTypePointer Output %v4float 1656 %_arr_v3float_uint_3 = OpTypeArray %v3float %uint_3 1657 %_ptr_Input__arr_v3float_uint_3 = OpTypePointer Input %_arr_v3float_uint_3 1658 %26 = OpVariable %_ptr_Input__arr_v3float_uint_3 Input 1659 %27 = OpVariable %_ptr_Input__arr_v3float_uint_3 Input 1660 %_arr_v2float_uint_3 = OpTypeArray %v2float %uint_3 1661 %_ptr_Input__arr_v2float_uint_3 = OpTypePointer Input %_arr_v2float_uint_3 1662 %30 = OpVariable %_ptr_Input__arr_v2float_uint_3 Input 1663 %31 = OpVariable %_ptr_Input__arr_v2float_uint_3 Input 1664 %_ptr_Function__struct_11 = OpTypePointer Function %_struct_11 1665 %2 = OpFunction %void None %4 1666 %33 = OpLabel 1667 %66 = OpVariable %_ptr_Function__arr__struct_11_uint_3 Function 1668 %34 = OpLoad %_arr_v4float_uint_3 %16 1669 %35 = OpLoad %_arr_v4float_uint_3 %17 1670 %36 = OpLoad %_arr_v4float_uint_3 %18 1671 %37 = OpLoad %_arr_v3float_uint_3 %26 1672 %38 = OpLoad %_arr_v3float_uint_3 %27 1673 %39 = OpLoad %_arr_v2float_uint_3 %30 1674 %40 = OpLoad %_arr_v2float_uint_3 %31 1675 %41 = OpCompositeExtract %v4float %34 0 1676 %42 = OpCompositeExtract %v4float %35 0 1677 %43 = OpCompositeExtract %v4float %36 0 1678 %44 = OpCompositeExtract %v3float %37 0 1679 %45 = OpCompositeExtract %v3float %38 0 1680 %46 = OpCompositeExtract %v2float %39 0 1681 %47 = OpCompositeExtract %v2float %40 0 1682 %48 = OpCompositeConstruct %_struct_11 %41 %42 %43 %44 %45 %46 %47 1683 %49 = OpCompositeExtract %v4float %34 1 1684 %50 = OpCompositeExtract %v4float %35 1 1685 %51 = OpCompositeExtract %v4float %36 1 1686 %52 = OpCompositeExtract %v3float %37 1 1687 %53 = OpCompositeExtract %v3float %38 1 1688 %54 = OpCompositeExtract %v2float %39 1 1689 %55 = OpCompositeExtract %v2float %40 1 1690 %56 = OpCompositeConstruct %_struct_11 %49 %50 %51 %52 %53 %54 %55 1691 %57 = OpCompositeExtract %v4float %34 2 1692 %58 = OpCompositeExtract %v4float %35 2 1693 %59 = OpCompositeExtract %v4float %36 2 1694 %60 = OpCompositeExtract %v3float %37 2 1695 %61 = OpCompositeExtract %v3float %38 2 1696 %62 = OpCompositeExtract %v2float %39 2 1697 %63 = OpCompositeExtract %v2float %40 2 1698 %64 = OpCompositeConstruct %_struct_11 %57 %58 %59 %60 %61 %62 %63 1699 %65 = OpCompositeConstruct %_arr__struct_11_uint_3 %48 %56 %64 1700 %67 = OpLoad %uint %20 1701 1702 ; CHECK OpStore {{%\d+}} [[store_source:%\d+]] 1703 OpStore %66 %65 1704 %68 = OpAccessChain %_ptr_Function__struct_11 %66 %67 1705 1706 ; This load was being removed, because %_ptr_Function__struct_11 was being 1707 ; wrongfully considered an SSA target. 1708 ; CHECK OpLoad %_struct_11 %68 1709 %69 = OpLoad %_struct_11 %68 1710 1711 ; Similarly, %69 cannot be replaced with %65. 1712 ; CHECK-NOT: OpCompositeExtract %v4float [[store_source]] 0 1713 %70 = OpCompositeExtract %v4float %69 0 1714 1715 %71 = OpAccessChain %_ptr_Output_v4float %22 %67 1716 OpStore %71 %70 1717 OpReturn 1718 OpFunctionEnd)"; 1719 1720 SinglePassRunAndMatch<SSARewritePass>(spv_asm, true); 1721 } 1722 1723 // Test that the RelaxedPrecision decoration on the variable to added to the 1724 // result of the OpPhi instruction. 1725 TEST_F(LocalSSAElimTest, DecoratedVariable) { 1726 const std::string spv_asm = R"( 1727 ; CHECK: OpDecorate [[var:%\w+]] RelaxedPrecision 1728 ; CHECK: OpDecorate [[phi_id:%\w+]] RelaxedPrecision 1729 ; CHECK: [[phi_id]] = OpPhi 1730 OpCapability Shader 1731 %1 = OpExtInstImport "GLSL.std.450" 1732 OpMemoryModel Logical GLSL450 1733 OpEntryPoint GLCompute %2 "main" 1734 OpDecorate %v RelaxedPrecision 1735 %void = OpTypeVoid 1736 %func_t = OpTypeFunction %void 1737 %bool = OpTypeBool 1738 %true = OpConstantTrue %bool 1739 %int = OpTypeInt 32 0 1740 %int_p = OpTypePointer Function %int 1741 %int_1 = OpConstant %int 1 1742 %int_0 = OpConstant %int 0 1743 %2 = OpFunction %void None %func_t 1744 %33 = OpLabel 1745 %v = OpVariable %int_p Function 1746 OpSelectionMerge %merge None 1747 OpBranchConditional %true %l1 %l2 1748 %l1 = OpLabel 1749 OpStore %v %int_1 1750 OpBranch %merge 1751 %l2 = OpLabel 1752 OpStore %v %int_0 1753 OpBranch %merge 1754 %merge = OpLabel 1755 %ld = OpLoad %int %v 1756 OpReturn 1757 OpFunctionEnd)"; 1758 1759 SinglePassRunAndMatch<SSARewritePass>(spv_asm, true); 1760 } 1761 1762 // Test that the RelaxedPrecision decoration on the variable to added to the 1763 // result of the OpPhi instruction. 1764 TEST_F(LocalSSAElimTest, MultipleEdges) { 1765 const std::string spv_asm = R"( 1766 ; CHECK: OpSelectionMerge 1767 ; CHECK: [[header_bb:%\w+]] = OpLabel 1768 ; CHECK-NOT: OpLabel 1769 ; CHECK: OpSwitch {{%\w+}} {{%\w+}} 76 [[bb1:%\w+]] 17 [[bb2:%\w+]] 1770 ; CHECK-SAME: 4 [[bb2]] 1771 ; CHECK: [[bb2]] = OpLabel 1772 ; CHECK-NEXT: OpPhi [[type:%\w+]] [[val:%\w+]] [[header_bb]] %int_0 [[bb1]] 1773 OpCapability Shader 1774 %1 = OpExtInstImport "GLSL.std.450" 1775 OpMemoryModel Logical GLSL450 1776 OpEntryPoint Fragment %4 "main" 1777 OpExecutionMode %4 OriginUpperLeft 1778 OpSource ESSL 310 1779 %void = OpTypeVoid 1780 %3 = OpTypeFunction %void 1781 %int = OpTypeInt 32 1 1782 %_ptr_Function_int = OpTypePointer Function %int 1783 %int_0 = OpConstant %int 0 1784 %bool = OpTypeBool 1785 %true = OpConstantTrue %bool 1786 %false = OpConstantFalse %bool 1787 %int_1 = OpConstant %int 1 1788 %4 = OpFunction %void None %3 1789 %5 = OpLabel 1790 %8 = OpVariable %_ptr_Function_int Function 1791 OpBranch %10 1792 %10 = OpLabel 1793 OpLoopMerge %12 %13 None 1794 OpBranch %14 1795 %14 = OpLabel 1796 OpBranchConditional %true %11 %12 1797 %11 = OpLabel 1798 OpSelectionMerge %19 None 1799 OpBranchConditional %false %18 %19 1800 %18 = OpLabel 1801 OpSelectionMerge %22 None 1802 OpSwitch %int_0 %22 76 %20 17 %21 4 %21 1803 %20 = OpLabel 1804 %23 = OpLoad %int %8 1805 OpStore %8 %int_0 1806 OpBranch %21 1807 %21 = OpLabel 1808 OpBranch %22 1809 %22 = OpLabel 1810 OpBranch %19 1811 %19 = OpLabel 1812 OpBranch %13 1813 %13 = OpLabel 1814 OpBranch %10 1815 %12 = OpLabel 1816 OpReturn 1817 OpFunctionEnd 1818 )"; 1819 1820 SinglePassRunAndMatch<SSARewritePass>(spv_asm, true); 1821 } 1822 1823 // TODO(greg-lunarg): Add tests to verify handling of these cases: 1824 // 1825 // No optimization in the presence of 1826 // access chains 1827 // function calls 1828 // OpCopyMemory? 1829 // unsupported extensions 1830 // Others? 1831 1832 } // namespace 1833 } // namespace opt 1834 } // namespace spvtools 1835