Home | History | Annotate | Download | only in opt
      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 <string>
     16 
     17 #include "gmock/gmock.h"
     18 #include "test/opt/assembly_builder.h"
     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 IfConversionTest = PassTest<::testing::Test>;
     27 
     28 TEST_F(IfConversionTest, TestSimpleIfThenElse) {
     29   const std::string text = R"(
     30 ; CHECK: OpSelectionMerge [[merge:%\w+]]
     31 ; CHECK: [[merge]] = OpLabel
     32 ; CHECK-NOT: OpPhi
     33 ; CHECK: [[sel:%\w+]] = OpSelect %uint %true %uint_0 %uint_1
     34 ; CHECK OpStore {{%\w+}} [[sel]]
     35 OpCapability Shader
     36 OpMemoryModel Logical GLSL450
     37 OpEntryPoint Vertex %1 "func" %2
     38 %void = OpTypeVoid
     39 %bool = OpTypeBool
     40 %true = OpConstantTrue %bool
     41 %uint = OpTypeInt 32 0
     42 %uint_0 = OpConstant %uint 0
     43 %uint_1 = OpConstant %uint 1
     44 %_ptr_Output_uint = OpTypePointer Output %uint
     45 %2 = OpVariable %_ptr_Output_uint Output
     46 %11 = OpTypeFunction %void
     47 %1 = OpFunction %void None %11
     48 %12 = OpLabel
     49 OpSelectionMerge %14 None
     50 OpBranchConditional %true %15 %16
     51 %15 = OpLabel
     52 OpBranch %14
     53 %16 = OpLabel
     54 OpBranch %14
     55 %14 = OpLabel
     56 %18 = OpPhi %uint %uint_0 %15 %uint_1 %16
     57 OpStore %2 %18
     58 OpReturn
     59 OpFunctionEnd
     60 )";
     61 
     62   SinglePassRunAndMatch<IfConversion>(text, true);
     63 }
     64 
     65 TEST_F(IfConversionTest, TestSimpleHalfIfTrue) {
     66   const std::string text = R"(
     67 ; CHECK: OpSelectionMerge [[merge:%\w+]]
     68 ; CHECK: [[merge]] = OpLabel
     69 ; CHECK-NOT: OpPhi
     70 ; CHECK: [[sel:%\w+]] = OpSelect %uint %true %uint_0 %uint_1
     71 ; CHECK OpStore {{%\w+}} [[sel]]
     72 OpCapability Shader
     73 OpMemoryModel Logical GLSL450
     74 OpEntryPoint Vertex %1 "func" %2
     75 %void = OpTypeVoid
     76 %bool = OpTypeBool
     77 %true = OpConstantTrue %bool
     78 %uint = OpTypeInt 32 0
     79 %uint_0 = OpConstant %uint 0
     80 %uint_1 = OpConstant %uint 1
     81 %_ptr_Output_uint = OpTypePointer Output %uint
     82 %2 = OpVariable %_ptr_Output_uint Output
     83 %11 = OpTypeFunction %void
     84 %1 = OpFunction %void None %11
     85 %12 = OpLabel
     86 OpSelectionMerge %14 None
     87 OpBranchConditional %true %15 %14
     88 %15 = OpLabel
     89 OpBranch %14
     90 %14 = OpLabel
     91 %18 = OpPhi %uint %uint_0 %15 %uint_1 %12
     92 OpStore %2 %18
     93 OpReturn
     94 OpFunctionEnd
     95 )";
     96 
     97   SinglePassRunAndMatch<IfConversion>(text, true);
     98 }
     99 
    100 TEST_F(IfConversionTest, TestSimpleHalfIfExtraBlock) {
    101   const std::string text = R"(
    102 ; CHECK: OpSelectionMerge [[merge:%\w+]]
    103 ; CHECK: [[merge]] = OpLabel
    104 ; CHECK-NOT: OpPhi
    105 ; CHECK: [[sel:%\w+]] = OpSelect %uint %true %uint_0 %uint_1
    106 ; CHECK OpStore {{%\w+}} [[sel]]
    107 OpCapability Shader
    108 OpMemoryModel Logical GLSL450
    109 OpEntryPoint Vertex %1 "func" %2
    110 %void = OpTypeVoid
    111 %bool = OpTypeBool
    112 %true = OpConstantTrue %bool
    113 %uint = OpTypeInt 32 0
    114 %uint_0 = OpConstant %uint 0
    115 %uint_1 = OpConstant %uint 1
    116 %_ptr_Output_uint = OpTypePointer Output %uint
    117 %2 = OpVariable %_ptr_Output_uint Output
    118 %11 = OpTypeFunction %void
    119 %1 = OpFunction %void None %11
    120 %12 = OpLabel
    121 OpSelectionMerge %14 None
    122 OpBranchConditional %true %15 %14
    123 %15 = OpLabel
    124 OpBranch %16
    125 %16 = OpLabel
    126 OpBranch %14
    127 %14 = OpLabel
    128 %18 = OpPhi %uint %uint_0 %15 %uint_1 %12
    129 OpStore %2 %18
    130 OpReturn
    131 OpFunctionEnd
    132 )";
    133 
    134   SinglePassRunAndMatch<IfConversion>(text, true);
    135 }
    136 
    137 TEST_F(IfConversionTest, TestSimpleHalfIfFalse) {
    138   const std::string text = R"(
    139 ; CHECK: OpSelectionMerge [[merge:%\w+]]
    140 ; CHECK: [[merge]] = OpLabel
    141 ; CHECK-NOT: OpPhi
    142 ; CHECK: [[sel:%\w+]] = OpSelect %uint %true %uint_0 %uint_1
    143 ; CHECK OpStore {{%\w+}} [[sel]]
    144 OpCapability Shader
    145 OpMemoryModel Logical GLSL450
    146 OpEntryPoint Vertex %1 "func" %2
    147 %void = OpTypeVoid
    148 %bool = OpTypeBool
    149 %true = OpConstantTrue %bool
    150 %uint = OpTypeInt 32 0
    151 %uint_0 = OpConstant %uint 0
    152 %uint_1 = OpConstant %uint 1
    153 %_ptr_Output_uint = OpTypePointer Output %uint
    154 %2 = OpVariable %_ptr_Output_uint Output
    155 %11 = OpTypeFunction %void
    156 %1 = OpFunction %void None %11
    157 %12 = OpLabel
    158 OpSelectionMerge %14 None
    159 OpBranchConditional %true %14 %15
    160 %15 = OpLabel
    161 OpBranch %14
    162 %14 = OpLabel
    163 %18 = OpPhi %uint %uint_0 %12 %uint_1 %15
    164 OpStore %2 %18
    165 OpReturn
    166 OpFunctionEnd
    167 )";
    168 
    169   SinglePassRunAndMatch<IfConversion>(text, true);
    170 }
    171 
    172 TEST_F(IfConversionTest, TestVectorSplat) {
    173   const std::string text = R"(
    174 ; CHECK: [[bool_vec:%\w+]] = OpTypeVector %bool 2
    175 ; CHECK: OpSelectionMerge [[merge:%\w+]]
    176 ; CHECK: [[merge]] = OpLabel
    177 ; CHECK-NOT: OpPhi
    178 ; CHECK: [[comp:%\w+]] = OpCompositeConstruct [[bool_vec]] %true %true
    179 ; CHECK: [[sel:%\w+]] = OpSelect {{%\w+}} [[comp]]
    180 ; CHECK OpStore {{%\w+}} [[sel]]
    181 OpCapability Shader
    182 OpMemoryModel Logical GLSL450
    183 OpEntryPoint Vertex %1 "func" %2
    184 %void = OpTypeVoid
    185 %bool = OpTypeBool
    186 %true = OpConstantTrue %bool
    187 %uint = OpTypeInt 32 0
    188 %uint_0 = OpConstant %uint 0
    189 %uint_1 = OpConstant %uint 1
    190 %uint_vec2 = OpTypeVector %uint 2
    191 %vec2_01 = OpConstantComposite %uint_vec2 %uint_0 %uint_1
    192 %vec2_10 = OpConstantComposite %uint_vec2 %uint_1 %uint_0
    193 %_ptr_Output_uint = OpTypePointer Output %uint_vec2
    194 %2 = OpVariable %_ptr_Output_uint Output
    195 %11 = OpTypeFunction %void
    196 %1 = OpFunction %void None %11
    197 %12 = OpLabel
    198 OpSelectionMerge %14 None
    199 OpBranchConditional %true %15 %16
    200 %15 = OpLabel
    201 OpBranch %14
    202 %16 = OpLabel
    203 OpBranch %14
    204 %14 = OpLabel
    205 %18 = OpPhi %uint_vec2 %vec2_01 %15 %vec2_10 %16
    206 OpStore %2 %18
    207 OpReturn
    208 OpFunctionEnd
    209 )";
    210 
    211   SinglePassRunAndMatch<IfConversion>(text, true);
    212 }
    213 
    214 TEST_F(IfConversionTest, CodeMotionSameValue) {
    215   const std::string text = R"(
    216 ; CHECK: [[var:%\w+]] = OpVariable
    217 ; CHECK: OpFunction
    218 ; CHECK: OpLabel
    219 ; CHECK-NOT: OpLabel
    220 ; CHECK: [[add:%\w+]] = OpIAdd %uint %uint_0 %uint_1
    221 ; CHECK: OpSelectionMerge [[merge_lab:%\w+]] None
    222 ; CHECK-NEXT: OpBranchConditional
    223 ; CHECK: [[merge_lab]] = OpLabel
    224 ; CHECK-NOT: OpLabel
    225 ; CHECK: OpStore [[var]] [[add]]
    226                     OpCapability Shader
    227                     OpMemoryModel Logical GLSL450
    228                     OpEntryPoint Vertex %1 "func" %2
    229             %void = OpTypeVoid
    230             %uint = OpTypeInt 32 0
    231           %uint_0 = OpConstant %uint 0
    232           %uint_1 = OpConstant %uint 1
    233 %_ptr_Output_uint = OpTypePointer Output %uint
    234                %2 = OpVariable %_ptr_Output_uint Output
    235                %8 = OpTypeFunction %void
    236             %bool = OpTypeBool
    237             %true = OpConstantTrue %bool
    238                %1 = OpFunction %void None %8
    239               %11 = OpLabel
    240                     OpSelectionMerge %12 None
    241                     OpBranchConditional %true %13 %15
    242               %13 = OpLabel
    243               %14 = OpIAdd %uint %uint_0 %uint_1
    244                     OpBranch %12
    245               %15 = OpLabel
    246               %16 = OpIAdd %uint %uint_0 %uint_1
    247                     OpBranch %12
    248               %12 = OpLabel
    249               %17 = OpPhi %uint %16 %15 %14 %13
    250                     OpStore %2 %17
    251                     OpReturn
    252                     OpFunctionEnd
    253 )";
    254 
    255   SinglePassRunAndMatch<IfConversion>(text, true);
    256 }
    257 
    258 TEST_F(IfConversionTest, CodeMotionMultipleInstructions) {
    259   const std::string text = R"(
    260 ; CHECK: [[var:%\w+]] = OpVariable
    261 ; CHECK: OpFunction
    262 ; CHECK: OpLabel
    263 ; CHECK-NOT: OpLabel
    264 ; CHECK: [[a1:%\w+]] = OpIAdd %uint %uint_0 %uint_1
    265 ; CHECK: [[a2:%\w+]] = OpIAdd %uint [[a1]] %uint_1
    266 ; CHECK: OpSelectionMerge [[merge_lab:%\w+]] None
    267 ; CHECK-NEXT: OpBranchConditional
    268 ; CHECK: [[merge_lab]] = OpLabel
    269 ; CHECK-NOT: OpLabel
    270 ; CHECK: OpStore [[var]] [[a2]]
    271                     OpCapability Shader
    272                     OpMemoryModel Logical GLSL450
    273                     OpEntryPoint Vertex %1 "func" %2
    274             %void = OpTypeVoid
    275             %uint = OpTypeInt 32 0
    276           %uint_0 = OpConstant %uint 0
    277           %uint_1 = OpConstant %uint 1
    278 %_ptr_Output_uint = OpTypePointer Output %uint
    279                %2 = OpVariable %_ptr_Output_uint Output
    280                %8 = OpTypeFunction %void
    281             %bool = OpTypeBool
    282             %true = OpConstantTrue %bool
    283                %1 = OpFunction %void None %8
    284               %11 = OpLabel
    285                     OpSelectionMerge %12 None
    286                     OpBranchConditional %true %13 %15
    287               %13 = OpLabel
    288               %a1 = OpIAdd %uint %uint_0 %uint_1
    289               %a2 = OpIAdd %uint %a1 %uint_1
    290                     OpBranch %12
    291               %15 = OpLabel
    292               %b1 = OpIAdd %uint %uint_0 %uint_1
    293               %b2 = OpIAdd %uint %b1 %uint_1
    294                     OpBranch %12
    295               %12 = OpLabel
    296               %17 = OpPhi %uint %b2 %15 %a2 %13
    297                     OpStore %2 %17
    298                     OpReturn
    299                     OpFunctionEnd
    300 )";
    301 
    302   SinglePassRunAndMatch<IfConversion>(text, true);
    303 }
    304 
    305 TEST_F(IfConversionTest, NoCommonDominator) {
    306   const std::string text = R"(OpCapability Shader
    307 OpMemoryModel Logical GLSL450
    308 OpEntryPoint Vertex %1 "func" %2
    309 %void = OpTypeVoid
    310 %uint = OpTypeInt 32 0
    311 %uint_0 = OpConstant %uint 0
    312 %uint_1 = OpConstant %uint 1
    313 %_ptr_Output_uint = OpTypePointer Output %uint
    314 %2 = OpVariable %_ptr_Output_uint Output
    315 %8 = OpTypeFunction %void
    316 %1 = OpFunction %void None %8
    317 %9 = OpLabel
    318 OpBranch %10
    319 %11 = OpLabel
    320 OpBranch %10
    321 %10 = OpLabel
    322 %12 = OpPhi %uint %uint_0 %9 %uint_1 %11
    323 OpStore %2 %12
    324 OpReturn
    325 OpFunctionEnd
    326 )";
    327 
    328   SinglePassRunAndCheck<IfConversion>(text, text, true, true);
    329 }
    330 
    331 TEST_F(IfConversionTest, LoopUntouched) {
    332   const std::string text = R"(OpCapability Shader
    333 OpMemoryModel Logical GLSL450
    334 OpEntryPoint Vertex %1 "func" %2
    335 %void = OpTypeVoid
    336 %uint = OpTypeInt 32 0
    337 %uint_0 = OpConstant %uint 0
    338 %uint_1 = OpConstant %uint 1
    339 %_ptr_Output_uint = OpTypePointer Output %uint
    340 %2 = OpVariable %_ptr_Output_uint Output
    341 %8 = OpTypeFunction %void
    342 %bool = OpTypeBool
    343 %true = OpConstantTrue %bool
    344 %1 = OpFunction %void None %8
    345 %11 = OpLabel
    346 OpBranch %12
    347 %12 = OpLabel
    348 %13 = OpPhi %uint %uint_0 %11 %uint_1 %12
    349 OpLoopMerge %14 %12 None
    350 OpBranchConditional %true %14 %12
    351 %14 = OpLabel
    352 OpStore %2 %13
    353 OpReturn
    354 OpFunctionEnd
    355 )";
    356 
    357   SinglePassRunAndCheck<IfConversion>(text, text, true, true);
    358 }
    359 
    360 TEST_F(IfConversionTest, TooManyPredecessors) {
    361   const std::string text = R"(OpCapability Shader
    362 OpMemoryModel Logical GLSL450
    363 OpEntryPoint Vertex %1 "func" %2
    364 %void = OpTypeVoid
    365 %uint = OpTypeInt 32 0
    366 %uint_0 = OpConstant %uint 0
    367 %uint_1 = OpConstant %uint 1
    368 %_ptr_Output_uint = OpTypePointer Output %uint
    369 %2 = OpVariable %_ptr_Output_uint Output
    370 %8 = OpTypeFunction %void
    371 %bool = OpTypeBool
    372 %true = OpConstantTrue %bool
    373 %1 = OpFunction %void None %8
    374 %11 = OpLabel
    375 OpSelectionMerge %12 None
    376 OpBranchConditional %true %13 %12
    377 %13 = OpLabel
    378 OpBranchConditional %true %14 %15
    379 %14 = OpLabel
    380 OpBranch %12
    381 %15 = OpLabel
    382 OpBranch %12
    383 %12 = OpLabel
    384 %16 = OpPhi %uint %uint_0 %11 %uint_0 %14 %uint_1 %15
    385 OpStore %2 %16
    386 OpReturn
    387 OpFunctionEnd
    388 )";
    389 
    390   SinglePassRunAndCheck<IfConversion>(text, text, true, true);
    391 }
    392 
    393 TEST_F(IfConversionTest, NoCodeMotion) {
    394   const std::string text = R"(OpCapability Shader
    395 OpMemoryModel Logical GLSL450
    396 OpEntryPoint Vertex %1 "func" %2
    397 %void = OpTypeVoid
    398 %uint = OpTypeInt 32 0
    399 %uint_0 = OpConstant %uint 0
    400 %uint_1 = OpConstant %uint 1
    401 %_ptr_Output_uint = OpTypePointer Output %uint
    402 %2 = OpVariable %_ptr_Output_uint Output
    403 %8 = OpTypeFunction %void
    404 %bool = OpTypeBool
    405 %true = OpConstantTrue %bool
    406 %1 = OpFunction %void None %8
    407 %11 = OpLabel
    408 OpSelectionMerge %12 None
    409 OpBranchConditional %true %13 %12
    410 %13 = OpLabel
    411 %14 = OpIAdd %uint %uint_0 %uint_1
    412 OpBranch %12
    413 %12 = OpLabel
    414 %15 = OpPhi %uint %uint_0 %11 %14 %13
    415 OpStore %2 %15
    416 OpReturn
    417 OpFunctionEnd
    418 )";
    419 
    420   SinglePassRunAndCheck<IfConversion>(text, text, true, true);
    421 }
    422 
    423 TEST_F(IfConversionTest, NoCodeMotionImmovableInst) {
    424   const std::string text = R"(OpCapability Shader
    425 OpMemoryModel Logical GLSL450
    426 OpEntryPoint Vertex %1 "func" %2
    427 %void = OpTypeVoid
    428 %uint = OpTypeInt 32 0
    429 %uint_0 = OpConstant %uint 0
    430 %uint_1 = OpConstant %uint 1
    431 %_ptr_Output_uint = OpTypePointer Output %uint
    432 %2 = OpVariable %_ptr_Output_uint Output
    433 %8 = OpTypeFunction %void
    434 %bool = OpTypeBool
    435 %true = OpConstantTrue %bool
    436 %1 = OpFunction %void None %8
    437 %11 = OpLabel
    438 OpSelectionMerge %12 None
    439 OpBranchConditional %true %13 %14
    440 %13 = OpLabel
    441 OpSelectionMerge %15 None
    442 OpBranchConditional %true %16 %15
    443 %16 = OpLabel
    444 %17 = OpIAdd %uint %uint_0 %uint_1
    445 OpBranch %15
    446 %15 = OpLabel
    447 %18 = OpPhi %uint %uint_0 %13 %17 %16
    448 %19 = OpIAdd %uint %18 %uint_1
    449 OpBranch %12
    450 %14 = OpLabel
    451 OpSelectionMerge %20 None
    452 OpBranchConditional %true %21 %20
    453 %21 = OpLabel
    454 %22 = OpIAdd %uint %uint_0 %uint_1
    455 OpBranch %20
    456 %20 = OpLabel
    457 %23 = OpPhi %uint %uint_0 %14 %22 %21
    458 %24 = OpIAdd %uint %23 %uint_1
    459 OpBranch %12
    460 %12 = OpLabel
    461 %25 = OpPhi %uint %24 %20 %19 %15
    462 OpStore %2 %25
    463 OpReturn
    464 OpFunctionEnd
    465 )";
    466 
    467   SinglePassRunAndCheck<IfConversion>(text, text, true, true);
    468 }
    469 
    470 TEST_F(IfConversionTest, InvalidCommonDominator) {
    471   const std::string text = R"(OpCapability Shader
    472 OpCapability Linkage
    473 OpMemoryModel Logical GLSL450
    474 %void = OpTypeVoid
    475 %float = OpTypeFloat 32
    476 %float_0 = OpConstant %float 0
    477 %float_1 = OpConstant %float 1
    478 %bool = OpTypeBool
    479 %true = OpConstantTrue %bool
    480 %1 = OpTypeFunction %void
    481 %2 = OpFunction %void None %1
    482 %3 = OpLabel
    483 OpBranch %4
    484 %4 = OpLabel
    485 OpLoopMerge %5 %6 None
    486 OpBranch %7
    487 %7 = OpLabel
    488 OpSelectionMerge %8 None
    489 OpBranchConditional %true %8 %9
    490 %9 = OpLabel
    491 OpSelectionMerge %10 None
    492 OpBranchConditional %true %10 %5
    493 %10 = OpLabel
    494 OpBranch %8
    495 %8 = OpLabel
    496 OpBranch %6
    497 %6 = OpLabel
    498 OpBranchConditional %true %4 %5
    499 %5 = OpLabel
    500 %11 = OpPhi %float %float_0 %6 %float_1 %9
    501 OpReturn
    502 OpFunctionEnd
    503 )";
    504 
    505   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
    506   SinglePassRunAndCheck<IfConversion>(text, text, true, true);
    507 }
    508 
    509 }  // namespace
    510 }  // namespace opt
    511 }  // namespace spvtools
    512