1 // Copyright (c) 2017 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <string> 16 17 #include "gmock/gmock.h" 18 #include "gtest/gtest.h" 19 #include "source/opt/ccp_pass.h" 20 #include "test/opt/pass_fixture.h" 21 #include "test/opt/pass_utils.h" 22 23 namespace spvtools { 24 namespace opt { 25 namespace { 26 27 using CCPTest = PassTest<::testing::Test>; 28 29 TEST_F(CCPTest, PropagateThroughPhis) { 30 const std::string spv_asm = R"( 31 OpCapability Shader 32 %1 = OpExtInstImport "GLSL.std.450" 33 OpMemoryModel Logical GLSL450 34 OpEntryPoint Fragment %main "main" %x %outparm 35 OpExecutionMode %main OriginUpperLeft 36 OpSource GLSL 450 37 OpName %main "main" 38 OpName %x "x" 39 OpName %outparm "outparm" 40 OpDecorate %x Flat 41 OpDecorate %x Location 0 42 OpDecorate %outparm Location 0 43 %void = OpTypeVoid 44 %3 = OpTypeFunction %void 45 %int = OpTypeInt 32 1 46 %bool = OpTypeBool 47 %_ptr_Function_int = OpTypePointer Function %int 48 %int_4 = OpConstant %int 4 49 %int_3 = OpConstant %int 3 50 %int_1 = OpConstant %int 1 51 %_ptr_Input_int = OpTypePointer Input %int 52 %x = OpVariable %_ptr_Input_int Input 53 %_ptr_Output_int = OpTypePointer Output %int 54 %outparm = OpVariable %_ptr_Output_int Output 55 %main = OpFunction %void None %3 56 %4 = OpLabel 57 %5 = OpLoad %int %x 58 %9 = OpIAdd %int %int_1 %int_3 59 %6 = OpSGreaterThan %bool %5 %int_3 60 OpSelectionMerge %25 None 61 OpBranchConditional %6 %22 %23 62 %22 = OpLabel 63 64 ; CHECK: OpCopyObject %int %int_4 65 %7 = OpCopyObject %int %9 66 67 OpBranch %25 68 %23 = OpLabel 69 %8 = OpCopyObject %int %int_4 70 OpBranch %25 71 %25 = OpLabel 72 73 ; %int_4 should have propagated to both OpPhi operands. 74 ; CHECK: OpPhi %int %int_4 {{%\d+}} %int_4 {{%\d+}} 75 %35 = OpPhi %int %7 %22 %8 %23 76 77 ; This function always returns 4. DCE should get rid of everything else. 78 ; CHECK OpStore %outparm %int_4 79 OpStore %outparm %35 80 OpReturn 81 OpFunctionEnd 82 )"; 83 84 SinglePassRunAndMatch<CCPPass>(spv_asm, true); 85 } 86 87 TEST_F(CCPTest, SimplifyConditionals) { 88 const std::string spv_asm = R"( 89 OpCapability Shader 90 %1 = OpExtInstImport "GLSL.std.450" 91 OpMemoryModel Logical GLSL450 92 OpEntryPoint Fragment %main "main" %outparm 93 OpExecutionMode %main OriginUpperLeft 94 OpSource GLSL 450 95 OpName %main "main" 96 OpName %outparm "outparm" 97 OpDecorate %outparm Location 0 98 %void = OpTypeVoid 99 %3 = OpTypeFunction %void 100 %int = OpTypeInt 32 1 101 %bool = OpTypeBool 102 %_ptr_Function_int = OpTypePointer Function %int 103 %int_4 = OpConstant %int 4 104 %int_3 = OpConstant %int 3 105 %int_1 = OpConstant %int 1 106 %_ptr_Output_int = OpTypePointer Output %int 107 %outparm = OpVariable %_ptr_Output_int Output 108 %main = OpFunction %void None %3 109 %4 = OpLabel 110 %9 = OpIAdd %int %int_4 %int_3 111 %6 = OpSGreaterThan %bool %9 %int_3 112 OpSelectionMerge %25 None 113 ; CHECK: OpBranchConditional %true [[bb_taken:%\d+]] [[bb_not_taken:%\d+]] 114 OpBranchConditional %6 %22 %23 115 ; CHECK: [[bb_taken]] = OpLabel 116 %22 = OpLabel 117 ; CHECK: OpCopyObject %int %int_7 118 %7 = OpCopyObject %int %9 119 OpBranch %25 120 ; CHECK: [[bb_not_taken]] = OpLabel 121 %23 = OpLabel 122 ; CHECK: [[id_not_evaluated:%\d+]] = OpCopyObject %int %int_4 123 %8 = OpCopyObject %int %int_4 124 OpBranch %25 125 %25 = OpLabel 126 127 ; %int_7 should have propagated to the first OpPhi operand. But the else branch 128 ; is not executable (conditional is always true), so no values should be 129 ; propagated there and the value of the OpPhi should always be %int_7. 130 ; CHECK: OpPhi %int %int_7 [[bb_taken]] [[id_not_evaluated]] [[bb_not_taken]] 131 %35 = OpPhi %int %7 %22 %8 %23 132 133 ; Only the true path of the conditional is ever executed. The output of this 134 ; function is always %int_7. 135 ; CHECK: OpStore %outparm %int_7 136 OpStore %outparm %35 137 OpReturn 138 OpFunctionEnd 139 )"; 140 141 SinglePassRunAndMatch<CCPPass>(spv_asm, true); 142 } 143 144 TEST_F(CCPTest, SimplifySwitches) { 145 const std::string spv_asm = R"( 146 OpCapability Shader 147 %1 = OpExtInstImport "GLSL.std.450" 148 OpMemoryModel Logical GLSL450 149 OpEntryPoint Fragment %main "main" %outparm 150 OpExecutionMode %main OriginUpperLeft 151 OpSource GLSL 450 152 OpName %main "main" 153 OpName %outparm "outparm" 154 OpDecorate %outparm Location 0 155 %void = OpTypeVoid 156 %6 = OpTypeFunction %void 157 %int = OpTypeInt 32 1 158 %_ptr_Function_int = OpTypePointer Function %int 159 %int_23 = OpConstant %int 23 160 %int_42 = OpConstant %int 42 161 %int_14 = OpConstant %int 14 162 %int_15 = OpConstant %int 15 163 %int_4 = OpConstant %int 4 164 %_ptr_Output_int = OpTypePointer Output %int 165 %outparm = OpVariable %_ptr_Output_int Output 166 %main = OpFunction %void None %6 167 %15 = OpLabel 168 OpSelectionMerge %17 None 169 OpSwitch %int_23 %17 10 %18 13 %19 23 %20 170 %18 = OpLabel 171 OpBranch %17 172 %19 = OpLabel 173 OpBranch %17 174 %20 = OpLabel 175 OpBranch %17 176 %17 = OpLabel 177 %24 = OpPhi %int %int_23 %15 %int_42 %18 %int_14 %19 %int_15 %20 178 179 ; The switch will always jump to label %20, which carries the value %int_15. 180 ; CHECK: OpIAdd %int %int_15 %int_4 181 %22 = OpIAdd %int %24 %int_4 182 183 ; Consequently, the return value will always be %int_19. 184 ; CHECK: OpStore %outparm %int_19 185 OpStore %outparm %22 186 OpReturn 187 OpFunctionEnd 188 )"; 189 190 SinglePassRunAndMatch<CCPPass>(spv_asm, true); 191 } 192 193 TEST_F(CCPTest, SimplifySwitchesDefaultBranch) { 194 const std::string spv_asm = R"( 195 OpCapability Shader 196 %1 = OpExtInstImport "GLSL.std.450" 197 OpMemoryModel Logical GLSL450 198 OpEntryPoint Fragment %main "main" %outparm 199 OpExecutionMode %main OriginUpperLeft 200 OpSource GLSL 450 201 OpName %main "main" 202 OpName %outparm "outparm" 203 OpDecorate %outparm Location 0 204 %void = OpTypeVoid 205 %6 = OpTypeFunction %void 206 %int = OpTypeInt 32 1 207 %_ptr_Function_int = OpTypePointer Function %int 208 %int_42 = OpConstant %int 42 209 %int_4 = OpConstant %int 4 210 %int_1 = OpConstant %int 1 211 %_ptr_Output_int = OpTypePointer Output %int 212 %outparm = OpVariable %_ptr_Output_int Output 213 %main = OpFunction %void None %6 214 %13 = OpLabel 215 %15 = OpIAdd %int %int_42 %int_4 216 OpSelectionMerge %16 None 217 218 ; CHECK: OpSwitch %int_46 {{%\d+}} 10 {{%\d+}} 219 OpSwitch %15 %17 10 %18 220 %18 = OpLabel 221 OpBranch %16 222 %17 = OpLabel 223 OpBranch %16 224 %16 = OpLabel 225 %22 = OpPhi %int %int_42 %18 %int_1 %17 226 227 ; The switch will always jump to the default label %17. This carries the value 228 ; %int_1. 229 ; CHECK: OpIAdd %int %int_1 %int_4 230 %20 = OpIAdd %int %22 %int_4 231 232 ; Resulting in a return value of %int_5. 233 ; CHECK: OpStore %outparm %int_5 234 OpStore %outparm %20 235 OpReturn 236 OpFunctionEnd 237 )"; 238 239 SinglePassRunAndMatch<CCPPass>(spv_asm, true); 240 } 241 242 TEST_F(CCPTest, SimplifyIntVector) { 243 const std::string spv_asm = R"( 244 OpCapability Shader 245 %1 = OpExtInstImport "GLSL.std.450" 246 OpMemoryModel Logical GLSL450 247 OpEntryPoint Fragment %main "main" %OutColor 248 OpExecutionMode %main OriginUpperLeft 249 OpSource GLSL 450 250 OpName %main "main" 251 OpName %v "v" 252 OpName %OutColor "OutColor" 253 OpDecorate %OutColor Location 0 254 %void = OpTypeVoid 255 %3 = OpTypeFunction %void 256 %int = OpTypeInt 32 1 257 %v4int = OpTypeVector %int 4 258 %_ptr_Function_v4int = OpTypePointer Function %v4int 259 %int_1 = OpConstant %int 1 260 %int_2 = OpConstant %int 2 261 %int_3 = OpConstant %int 3 262 %int_4 = OpConstant %int 4 263 %14 = OpConstantComposite %v4int %int_1 %int_2 %int_3 %int_4 264 %uint = OpTypeInt 32 0 265 %uint_0 = OpConstant %uint 0 266 %_ptr_Function_int = OpTypePointer Function %int 267 %_ptr_Output_v4int = OpTypePointer Output %v4int 268 %OutColor = OpVariable %_ptr_Output_v4int Output 269 %main = OpFunction %void None %3 270 %5 = OpLabel 271 %v = OpVariable %_ptr_Function_v4int Function 272 OpStore %v %14 273 %18 = OpAccessChain %_ptr_Function_int %v %uint_0 274 %19 = OpLoad %int %18 275 276 ; The constant folder does not see through access chains. To get this, the 277 ; vector would have to be scalarized. 278 ; CHECK: [[result_id:%\d+]] = OpIAdd %int {{%\d+}} %int_1 279 %20 = OpIAdd %int %19 %int_1 280 %21 = OpAccessChain %_ptr_Function_int %v %uint_0 281 282 ; CHECK: OpStore {{%\d+}} [[result_id]] 283 OpStore %21 %20 284 %24 = OpLoad %v4int %v 285 OpStore %OutColor %24 286 OpReturn 287 OpFunctionEnd 288 )"; 289 290 SinglePassRunAndMatch<CCPPass>(spv_asm, true); 291 } 292 293 TEST_F(CCPTest, BadSimplifyFloatVector) { 294 const std::string spv_asm = R"( 295 OpCapability Shader 296 %1 = OpExtInstImport "GLSL.std.450" 297 OpMemoryModel Logical GLSL450 298 OpEntryPoint Fragment %main "main" %OutColor 299 OpExecutionMode %main OriginUpperLeft 300 OpSource GLSL 450 301 OpName %main "main" 302 OpName %v "v" 303 OpName %OutColor "OutColor" 304 OpDecorate %OutColor Location 0 305 %void = OpTypeVoid 306 %3 = OpTypeFunction %void 307 %float = OpTypeFloat 32 308 %v4float = OpTypeVector %float 4 309 %_ptr_Function_v4float = OpTypePointer Function %v4float 310 %float_1 = OpConstant %float 1 311 %float_2 = OpConstant %float 2 312 %float_3 = OpConstant %float 3 313 %float_4 = OpConstant %float 4 314 %14 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4 315 %uint = OpTypeInt 32 0 316 %uint_0 = OpConstant %uint 0 317 %_ptr_Function_float = OpTypePointer Function %float 318 %_ptr_Output_v4float = OpTypePointer Output %v4float 319 %OutColor = OpVariable %_ptr_Output_v4float Output 320 %main = OpFunction %void None %3 321 %5 = OpLabel 322 %v = OpVariable %_ptr_Function_v4float Function 323 OpStore %v %14 324 %18 = OpAccessChain %_ptr_Function_float %v %uint_0 325 %19 = OpLoad %float %18 326 327 ; NOTE: This test should start failing once floating point folding is 328 ; implemented (https://github.com/KhronosGroup/SPIRV-Tools/issues/943). 329 ; This should be checking that we are adding %float_1 + %float_1. 330 ; CHECK: [[result_id:%\d+]] = OpFAdd %float {{%\d+}} %float_1 331 %20 = OpFAdd %float %19 %float_1 332 %21 = OpAccessChain %_ptr_Function_float %v %uint_0 333 334 ; This should be checkint that we are storing %float_2 instead of result_it. 335 ; CHECK: OpStore {{%\d+}} [[result_id]] 336 OpStore %21 %20 337 %24 = OpLoad %v4float %v 338 OpStore %OutColor %24 339 OpReturn 340 OpFunctionEnd 341 )"; 342 343 SinglePassRunAndMatch<CCPPass>(spv_asm, true); 344 } 345 346 TEST_F(CCPTest, NoLoadStorePropagation) { 347 const std::string spv_asm = R"( 348 OpCapability Shader 349 %1 = OpExtInstImport "GLSL.std.450" 350 OpMemoryModel Logical GLSL450 351 OpEntryPoint Fragment %main "main" %outparm 352 OpExecutionMode %main OriginUpperLeft 353 OpSource GLSL 450 354 OpName %main "main" 355 OpName %x "x" 356 OpName %outparm "outparm" 357 OpDecorate %outparm Location 0 358 %void = OpTypeVoid 359 %3 = OpTypeFunction %void 360 %int = OpTypeInt 32 1 361 %_ptr_Function_int = OpTypePointer Function %int 362 %int_23 = OpConstant %int 23 363 %_ptr_Output_int = OpTypePointer Output %int 364 %outparm = OpVariable %_ptr_Output_int Output 365 %main = OpFunction %void None %3 366 %5 = OpLabel 367 %x = OpVariable %_ptr_Function_int Function 368 OpStore %x %int_23 369 370 ; int_23 should not propagate into this load. 371 ; CHECK: [[load_id:%\d+]] = OpLoad %int %x 372 %12 = OpLoad %int %x 373 374 ; Nor into this copy operation. 375 ; CHECK: [[copy_id:%\d+]] = OpCopyObject %int [[load_id]] 376 %13 = OpCopyObject %int %12 377 378 ; Likewise here. 379 ; CHECK: OpStore %outparm [[copy_id]] 380 OpStore %outparm %13 381 OpReturn 382 OpFunctionEnd 383 )"; 384 385 SinglePassRunAndMatch<CCPPass>(spv_asm, true); 386 } 387 388 TEST_F(CCPTest, HandleAbortInstructions) { 389 const std::string spv_asm = R"( 390 OpCapability Shader 391 %1 = OpExtInstImport "GLSL.std.450" 392 OpMemoryModel Logical GLSL450 393 OpEntryPoint Fragment %main "main" 394 OpExecutionMode %main OriginUpperLeft 395 OpSource HLSL 500 396 OpName %main "main" 397 %void = OpTypeVoid 398 %3 = OpTypeFunction %void 399 %int = OpTypeInt 32 1 400 %bool = OpTypeBool 401 ; CHECK: %true = OpConstantTrue %bool 402 %int_3 = OpConstant %int 3 403 %int_1 = OpConstant %int 1 404 %main = OpFunction %void None %3 405 %4 = OpLabel 406 %9 = OpIAdd %int %int_3 %int_1 407 %6 = OpSGreaterThan %bool %9 %int_3 408 OpSelectionMerge %23 None 409 ; CHECK: OpBranchConditional %true {{%\d+}} {{%\d+}} 410 OpBranchConditional %6 %22 %23 411 %22 = OpLabel 412 OpKill 413 %23 = OpLabel 414 OpReturn 415 OpFunctionEnd 416 )"; 417 418 SinglePassRunAndMatch<CCPPass>(spv_asm, true); 419 } 420 421 TEST_F(CCPTest, SSAWebCycles) { 422 // Test reduced from https://github.com/KhronosGroup/SPIRV-Tools/issues/1159 423 // When there is a cycle in the SSA def-use web, the propagator was getting 424 // into an infinite loop. SSA edges for Phi instructions should not be 425 // added to the edges to simulate. 426 const std::string spv_asm = R"( 427 OpCapability Shader 428 %1 = OpExtInstImport "GLSL.std.450" 429 OpMemoryModel Logical GLSL450 430 OpEntryPoint Fragment %main "main" 431 OpExecutionMode %main OriginUpperLeft 432 OpSource GLSL 450 433 OpName %main "main" 434 %void = OpTypeVoid 435 %3 = OpTypeFunction %void 436 %int = OpTypeInt 32 1 437 %_ptr_Function_int = OpTypePointer Function %int 438 %int_0 = OpConstant %int 0 439 %int_4 = OpConstant %int 4 440 %bool = OpTypeBool 441 %int_1 = OpConstant %int 1 442 %_ptr_Output_int = OpTypePointer Output %int 443 %main = OpFunction %void None %3 444 %5 = OpLabel 445 OpBranch %11 446 %11 = OpLabel 447 %29 = OpPhi %int %int_0 %5 %22 %14 448 %30 = OpPhi %int %int_0 %5 %25 %14 449 OpLoopMerge %13 %14 None 450 OpBranch %15 451 %15 = OpLabel 452 %19 = OpSLessThan %bool %30 %int_4 453 ; CHECK: OpBranchConditional %true {{%\d+}} {{%\d+}} 454 OpBranchConditional %19 %12 %13 455 %12 = OpLabel 456 ; CHECK: OpIAdd %int %int_0 %int_0 457 %22 = OpIAdd %int %29 %30 458 OpBranch %14 459 %14 = OpLabel 460 ; CHECK: OpPhi %int %int_0 {{%\d+}} 461 %25 = OpPhi %int %30 %12 462 OpBranch %11 463 %13 = OpLabel 464 OpReturn 465 OpFunctionEnd 466 )"; 467 468 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 469 SinglePassRunAndMatch<CCPPass>(spv_asm, true); 470 } 471 472 TEST_F(CCPTest, LoopInductionVariables) { 473 // Test reduced from https://github.com/KhronosGroup/SPIRV-Tools/issues/1143 474 // We are failing to properly consider the induction variable for this loop 475 // as Varying. 476 const std::string spv_asm = R"( 477 OpCapability Shader 478 %1 = OpExtInstImport "GLSL.std.450" 479 OpMemoryModel Logical GLSL450 480 OpEntryPoint Fragment %main "main" 481 OpExecutionMode %main OriginUpperLeft 482 OpSource GLSL 430 483 OpName %main "main" 484 %void = OpTypeVoid 485 %5 = OpTypeFunction %void 486 %int = OpTypeInt 32 1 487 %_ptr_Function_int = OpTypePointer Function %int 488 %int_0 = OpConstant %int 0 489 %int_10 = OpConstant %int 10 490 %bool = OpTypeBool 491 %int_1 = OpConstant %int 1 492 %main = OpFunction %void None %5 493 %12 = OpLabel 494 OpBranch %13 495 %13 = OpLabel 496 497 ; This Phi should not have all constant arguments: 498 ; CHECK: [[phi_id:%\d+]] = OpPhi %int %int_0 {{%\d+}} {{%\d+}} {{%\d+}} 499 %22 = OpPhi %int %int_0 %12 %21 %15 500 OpLoopMerge %14 %15 None 501 OpBranch %16 502 %16 = OpLabel 503 504 ; The Phi should never be considered to have the value %int_0. 505 ; CHECK: [[branch_selector:%\d+]] = OpSLessThan %bool [[phi_id]] %int_10 506 %18 = OpSLessThan %bool %22 %int_10 507 508 ; This conditional was wrongly converted into an always-true jump due to the 509 ; bad meet evaluation of %22. 510 ; CHECK: OpBranchConditional [[branch_selector]] {{%\d+}} {{%\d+}} 511 OpBranchConditional %18 %19 %14 512 %19 = OpLabel 513 OpBranch %15 514 %15 = OpLabel 515 ; CHECK: OpIAdd %int [[phi_id]] %int_1 516 %21 = OpIAdd %int %22 %int_1 517 OpBranch %13 518 %14 = OpLabel 519 OpReturn 520 OpFunctionEnd 521 )"; 522 523 SinglePassRunAndMatch<CCPPass>(spv_asm, true); 524 } 525 526 TEST_F(CCPTest, HandleCompositeWithUndef) { 527 // Check to make sure that CCP does not crash when given a "constant" struct 528 // with an undef. If at a later time CCP is enhanced to optimize this case, 529 // it is not wrong. 530 const std::string spv_asm = R"( 531 OpCapability Shader 532 %1 = OpExtInstImport "GLSL.std.450" 533 OpMemoryModel Logical GLSL450 534 OpEntryPoint Fragment %main "main" 535 OpExecutionMode %main OriginUpperLeft 536 OpSource HLSL 500 537 OpName %main "main" 538 %void = OpTypeVoid 539 %4 = OpTypeFunction %void 540 %int = OpTypeInt 32 1 541 %bool = OpTypeBool 542 %_struct_7 = OpTypeStruct %int %int 543 %int_1 = OpConstant %int 1 544 %9 = OpUndef %int 545 %10 = OpConstantComposite %_struct_7 %int_1 %9 546 %main = OpFunction %void None %4 547 %11 = OpLabel 548 %12 = OpCompositeExtract %int %10 0 549 %13 = OpCopyObject %int %12 550 OpReturn 551 OpFunctionEnd 552 )"; 553 554 auto res = SinglePassRunToBinary<CCPPass>(spv_asm, true); 555 EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange); 556 } 557 558 TEST_F(CCPTest, SkipSpecConstantInstrucitons) { 559 const std::string spv_asm = R"( 560 OpCapability Shader 561 %1 = OpExtInstImport "GLSL.std.450" 562 OpMemoryModel Logical GLSL450 563 OpEntryPoint Fragment %main "main" 564 OpExecutionMode %main OriginUpperLeft 565 OpSource HLSL 500 566 OpName %main "main" 567 %void = OpTypeVoid 568 %4 = OpTypeFunction %void 569 %bool = OpTypeBool 570 %10 = OpSpecConstantFalse %bool 571 %main = OpFunction %void None %4 572 %11 = OpLabel 573 %12 = OpBranchConditional %10 %l1 %l2 574 %l1 = OpLabel 575 OpReturn 576 %l2 = OpLabel 577 OpReturn 578 OpFunctionEnd 579 )"; 580 581 auto res = SinglePassRunToBinary<CCPPass>(spv_asm, true); 582 EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange); 583 } 584 585 TEST_F(CCPTest, UpdateSubsequentPhisToVarying) { 586 const std::string text = R"( 587 OpCapability Shader 588 OpMemoryModel Logical GLSL450 589 OpEntryPoint Fragment %func "func" %in 590 OpExecutionMode %func OriginUpperLeft 591 %void = OpTypeVoid 592 %bool = OpTypeBool 593 %int = OpTypeInt 32 1 594 %false = OpConstantFalse %bool 595 %int0 = OpConstant %int 0 596 %int1 = OpConstant %int 1 597 %int6 = OpConstant %int 6 598 %int_ptr_Input = OpTypePointer Input %int 599 %in = OpVariable %int_ptr_Input Input 600 %undef = OpUndef %int 601 %functy = OpTypeFunction %void 602 %func = OpFunction %void None %functy 603 %1 = OpLabel 604 OpBranch %2 605 %2 = OpLabel 606 %outer_phi = OpPhi %int %int0 %1 %outer_add %15 607 %cond1 = OpSLessThanEqual %bool %outer_phi %int6 608 OpLoopMerge %3 %15 None 609 OpBranchConditional %cond1 %4 %3 610 %4 = OpLabel 611 %ld = OpLoad %int %in 612 %cond2 = OpSGreaterThanEqual %bool %int1 %ld 613 OpSelectionMerge %10 None 614 OpBranchConditional %cond2 %8 %9 615 %8 = OpLabel 616 OpBranch %10 617 %9 = OpLabel 618 OpBranch %10 619 %10 = OpLabel 620 %extra_phi = OpPhi %int %outer_phi %8 %outer_phi %9 621 OpBranch %11 622 %11 = OpLabel 623 %inner_phi = OpPhi %int %int0 %10 %inner_add %13 624 %cond3 = OpSLessThanEqual %bool %inner_phi %int6 625 OpLoopMerge %14 %13 None 626 OpBranchConditional %cond3 %12 %14 627 %12 = OpLabel 628 OpBranch %13 629 %13 = OpLabel 630 %inner_add = OpIAdd %int %inner_phi %int1 631 OpBranch %11 632 %14 = OpLabel 633 OpBranch %15 634 %15 = OpLabel 635 %outer_add = OpIAdd %int %extra_phi %int1 636 OpBranch %2 637 %3 = OpLabel 638 OpReturn 639 OpFunctionEnd 640 )"; 641 642 auto res = SinglePassRunToBinary<CCPPass>(text, true); 643 EXPECT_EQ(std::get<1>(res), Pass::Status::SuccessWithoutChange); 644 } 645 646 TEST_F(CCPTest, UndefInPhi) { 647 const std::string text = R"( 648 ; CHECK: [[uint1:%\w+]] = OpConstant {{%\w+}} 1 649 ; CHECK: [[phi:%\w+]] = OpPhi 650 ; CHECK: OpIAdd {{%\w+}} [[phi]] [[uint1]] 651 OpCapability Kernel 652 OpCapability Linkage 653 OpMemoryModel Logical OpenCL 654 OpDecorate %1 LinkageAttributes "func" Export 655 %void = OpTypeVoid 656 %bool = OpTypeBool 657 %uint = OpTypeInt 32 0 658 %uint_0 = OpConstant %uint 0 659 %uint_1 = OpConstant %uint 1 660 %7 = OpUndef %uint 661 %8 = OpTypeFunction %void %bool 662 %1 = OpFunction %void None %8 663 %9 = OpFunctionParameter %bool 664 %10 = OpLabel 665 OpBranchConditional %9 %11 %12 666 %11 = OpLabel 667 OpBranch %13 668 %12 = OpLabel 669 OpBranch %14 670 %14 = OpLabel 671 OpBranchConditional %9 %13 %15 672 %15 = OpLabel 673 OpBranch %13 674 %13 = OpLabel 675 %16 = OpPhi %uint %uint_0 %11 %7 %14 %uint_1 %15 676 %17 = OpIAdd %uint %16 %uint_1 677 OpReturn 678 OpFunctionEnd 679 )"; 680 681 SinglePassRunAndMatch<CCPPass>(text, true); 682 } 683 684 // Just test to make sure the constant fold rules are being used. Will rely on 685 // the folding test for specific testing of specific rules. 686 TEST_F(CCPTest, UseConstantFoldingRules) { 687 const std::string text = R"( 688 ; CHECK: [[float1:%\w+]] = OpConstant {{%\w+}} 1 689 ; CHECK: OpReturnValue [[float1]] 690 OpCapability Shader 691 OpCapability Linkage 692 OpMemoryModel Logical GLSL450 693 OpDecorate %1 LinkageAttributes "func" Export 694 %void = OpTypeVoid 695 %bool = OpTypeBool 696 %float = OpTypeFloat 32 697 %float_0 = OpConstant %float 0 698 %float_1 = OpConstant %float 1 699 %8 = OpTypeFunction %float 700 %1 = OpFunction %float None %8 701 %10 = OpLabel 702 %17 = OpFAdd %float %float_0 %float_1 703 OpReturnValue %17 704 OpFunctionEnd 705 )"; 706 707 SinglePassRunAndMatch<CCPPass>(text, true); 708 } 709 710 // Test for #1300. Previously value for %5 would not settle during simulation. 711 TEST_F(CCPTest, SettlePhiLatticeValue) { 712 const std::string text = R"( 713 OpCapability Kernel 714 OpCapability Linkage 715 OpMemoryModel Logical OpenCL 716 OpDecorate %func LinkageAttributes "func" Export 717 %void = OpTypeVoid 718 %bool = OpTypeBool 719 %true = OpConstantTrue %bool 720 %false = OpConstantFalse %bool 721 %functy = OpTypeFunction %void 722 %func = OpFunction %void None %functy 723 %1 = OpLabel 724 OpBranchConditional %true %2 %3 725 %3 = OpLabel 726 OpBranch %2 727 %2 = OpLabel 728 %5 = OpPhi %bool %true %1 %false %3 729 OpReturn 730 OpFunctionEnd 731 )"; 732 733 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 734 SinglePassRunToBinary<CCPPass>(text, true); 735 } 736 737 TEST_F(CCPTest, NullBranchCondition) { 738 const std::string text = R"( 739 ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1 740 ; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2 741 ; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]] 742 OpCapability Shader 743 OpMemoryModel Logical GLSL450 744 OpEntryPoint Fragment %func "func" 745 OpExecutionMode %func OriginUpperLeft 746 %void = OpTypeVoid 747 %bool = OpTypeBool 748 %int = OpTypeInt 32 1 749 %null = OpConstantNull %bool 750 %int_1 = OpConstant %int 1 751 %int_2 = OpConstant %int 2 752 %functy = OpTypeFunction %void 753 %func = OpFunction %void None %functy 754 %1 = OpLabel 755 OpSelectionMerge %2 None 756 OpBranchConditional %null %2 %3 757 %3 = OpLabel 758 OpBranch %2 759 %2 = OpLabel 760 %phi = OpPhi %int %int_1 %1 %int_2 %3 761 %add = OpIAdd %int %int_1 %phi 762 OpReturn 763 OpFunctionEnd 764 )"; 765 766 SinglePassRunAndMatch<CCPPass>(text, true); 767 } 768 769 TEST_F(CCPTest, UndefBranchCondition) { 770 const std::string text = R"( 771 ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1 772 ; CHECK: [[phi:%\w+]] = OpPhi 773 ; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]] 774 OpCapability Shader 775 OpMemoryModel Logical GLSL450 776 OpEntryPoint Fragment %func "func" 777 OpExecutionMode %func OriginUpperLeft 778 %void = OpTypeVoid 779 %bool = OpTypeBool 780 %int = OpTypeInt 32 1 781 %undef = OpUndef %bool 782 %int_1 = OpConstant %int 1 783 %int_2 = OpConstant %int 2 784 %functy = OpTypeFunction %void 785 %func = OpFunction %void None %functy 786 %1 = OpLabel 787 OpSelectionMerge %2 None 788 OpBranchConditional %undef %2 %3 789 %3 = OpLabel 790 OpBranch %2 791 %2 = OpLabel 792 %phi = OpPhi %int %int_1 %1 %int_2 %3 793 %add = OpIAdd %int %int_1 %phi 794 OpReturn 795 OpFunctionEnd 796 )"; 797 798 SinglePassRunAndMatch<CCPPass>(text, true); 799 } 800 801 TEST_F(CCPTest, NullSwitchCondition) { 802 const std::string text = R"( 803 ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1 804 ; CHECK: [[int2:%\w+]] = OpConstant {{%\w+}} 2 805 ; CHECK: OpIAdd {{%\w+}} [[int1]] [[int2]] 806 OpCapability Shader 807 OpMemoryModel Logical GLSL450 808 OpEntryPoint Fragment %func "func" 809 OpExecutionMode %func OriginUpperLeft 810 %void = OpTypeVoid 811 %int = OpTypeInt 32 1 812 %null = OpConstantNull %int 813 %int_1 = OpConstant %int 1 814 %int_2 = OpConstant %int 2 815 %functy = OpTypeFunction %void 816 %func = OpFunction %void None %functy 817 %1 = OpLabel 818 OpSelectionMerge %2 None 819 OpSwitch %null %2 0 %3 820 %3 = OpLabel 821 OpBranch %2 822 %2 = OpLabel 823 %phi = OpPhi %int %int_1 %1 %int_2 %3 824 %add = OpIAdd %int %int_1 %phi 825 OpReturn 826 OpFunctionEnd 827 )"; 828 829 SinglePassRunAndMatch<CCPPass>(text, true); 830 } 831 832 TEST_F(CCPTest, UndefSwitchCondition) { 833 const std::string text = R"( 834 ; CHECK: [[int1:%\w+]] = OpConstant {{%\w+}} 1 835 ; CHECK: [[phi:%\w+]] = OpPhi 836 ; CHECK: OpIAdd {{%\w+}} [[int1]] [[phi]] 837 OpCapability Shader 838 OpMemoryModel Logical GLSL450 839 OpEntryPoint Fragment %func "func" 840 OpExecutionMode %func OriginUpperLeft 841 %void = OpTypeVoid 842 %int = OpTypeInt 32 1 843 %undef = OpUndef %int 844 %int_1 = OpConstant %int 1 845 %int_2 = OpConstant %int 2 846 %functy = OpTypeFunction %void 847 %func = OpFunction %void None %functy 848 %1 = OpLabel 849 OpSelectionMerge %2 None 850 OpSwitch %undef %2 0 %3 851 %3 = OpLabel 852 OpBranch %2 853 %2 = OpLabel 854 %phi = OpPhi %int %int_1 %1 %int_2 %3 855 %add = OpIAdd %int %int_1 %phi 856 OpReturn 857 OpFunctionEnd 858 )"; 859 860 SinglePassRunAndMatch<CCPPass>(text, true); 861 } 862 863 // Test for #1361. 864 TEST_F(CCPTest, CompositeConstructOfGlobalValue) { 865 const std::string text = R"( 866 ; CHECK: [[phi:%\w+]] = OpPhi 867 ; CHECK-NEXT: OpCompositeExtract {{%\w+}} [[phi]] 0 868 OpCapability Shader 869 OpMemoryModel Logical GLSL450 870 OpEntryPoint Fragment %func "func" %in 871 OpExecutionMode %func OriginUpperLeft 872 %void = OpTypeVoid 873 %int = OpTypeInt 32 1 874 %bool = OpTypeBool 875 %functy = OpTypeFunction %void 876 %ptr_int_Input = OpTypePointer Input %int 877 %in = OpVariable %ptr_int_Input Input 878 %struct = OpTypeStruct %ptr_int_Input %ptr_int_Input 879 %struct_null = OpConstantNull %struct 880 %func = OpFunction %void None %functy 881 %1 = OpLabel 882 OpBranch %2 883 %2 = OpLabel 884 %phi = OpPhi %struct %struct_null %1 %5 %4 885 %extract = OpCompositeExtract %ptr_int_Input %phi 0 886 OpLoopMerge %3 %4 None 887 OpBranch %4 888 %4 = OpLabel 889 %5 = OpCompositeConstruct %struct %in %in 890 OpBranch %2 891 %3 = OpLabel 892 OpReturn 893 OpFunctionEnd 894 )"; 895 896 SinglePassRunAndMatch<CCPPass>(text, true); 897 } 898 899 } // namespace 900 } // namespace opt 901 } // namespace spvtools 902