Home | History | Annotate | Download | only in opt
      1 // Copyright (c) 2019 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 CodeSinkTest = PassTest<::testing::Test>;
     27 
     28 TEST_F(CodeSinkTest, MoveToNextBlock) {
     29   const std::string text = R"(
     30 ;CHECK: OpFunction
     31 ;CHECK: OpLabel
     32 ;CHECK: OpLabel
     33 ;CHECK: [[ac:%\w+]] = OpAccessChain
     34 ;CHECK: [[ld:%\w+]] = OpLoad %uint [[ac]]
     35 ;CHECK: OpCopyObject %uint [[ld]]
     36                OpCapability Shader
     37                OpMemoryModel Logical GLSL450
     38                OpEntryPoint GLCompute %1 "main"
     39        %void = OpTypeVoid
     40        %uint = OpTypeInt 32 0
     41      %uint_0 = OpConstant %uint 0
     42      %uint_4 = OpConstant %uint 4
     43 %_arr_uint_uint_4 = OpTypeArray %uint %uint_4
     44 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
     45 %_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4
     46           %9 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform
     47          %10 = OpTypeFunction %void
     48           %1 = OpFunction %void None %10
     49          %11 = OpLabel
     50          %12 = OpAccessChain %_ptr_Uniform_uint %9 %uint_0
     51          %13 = OpLoad %uint %12
     52                OpBranch %14
     53          %14 = OpLabel
     54          %15 = OpCopyObject %uint %13
     55                OpReturn
     56                OpFunctionEnd
     57 )";
     58 
     59   SinglePassRunAndMatch<CodeSinkingPass>(text, true);
     60 }
     61 
     62 TEST_F(CodeSinkTest, MovePastSelection) {
     63   const std::string text = R"(
     64 ;CHECK: OpFunction
     65 ;CHECK: OpLabel
     66 ;CHECK: OpSelectionMerge [[merge_bb:%\w+]]
     67 ;CHECK: [[merge_bb]] = OpLabel
     68 ;CHECK: [[ac:%\w+]] = OpAccessChain
     69 ;CHECK: [[ld:%\w+]] = OpLoad %uint [[ac]]
     70 ;CHECK: OpCopyObject %uint [[ld]]
     71                OpCapability Shader
     72                OpMemoryModel Logical GLSL450
     73                OpEntryPoint GLCompute %1 "main"
     74        %void = OpTypeVoid
     75        %bool = OpTypeBool
     76        %true = OpConstantTrue %bool
     77        %uint = OpTypeInt 32 0
     78      %uint_0 = OpConstant %uint 0
     79      %uint_4 = OpConstant %uint 4
     80 %_arr_uint_uint_4 = OpTypeArray %uint %uint_4
     81 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
     82 %_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4
     83          %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform
     84          %12 = OpTypeFunction %void
     85           %1 = OpFunction %void None %12
     86          %13 = OpLabel
     87          %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0
     88          %15 = OpLoad %uint %14
     89                OpSelectionMerge %16 None
     90                OpBranchConditional %true %17 %16
     91          %17 = OpLabel
     92                OpBranch %16
     93          %16 = OpLabel
     94          %18 = OpCopyObject %uint %15
     95                OpReturn
     96                OpFunctionEnd
     97 )";
     98 
     99   SinglePassRunAndMatch<CodeSinkingPass>(text, true);
    100 }
    101 
    102 TEST_F(CodeSinkTest, MoveIntoSelection) {
    103   const std::string text = R"(
    104 ;CHECK: OpFunction
    105 ;CHECK: OpLabel
    106 ;CHECK: OpSelectionMerge [[merge_bb:%\w+]]
    107 ;CHECK-NEXT: OpBranchConditional %true [[bb:%\w+]] [[merge_bb]]
    108 ;CHECK: [[bb]] = OpLabel
    109 ;CHECK-NEXT: [[ac:%\w+]] = OpAccessChain
    110 ;CHECK-NEXT: [[ld:%\w+]] = OpLoad %uint [[ac]]
    111 ;CHECK-NEXT: OpCopyObject %uint [[ld]]
    112                OpCapability Shader
    113                OpMemoryModel Logical GLSL450
    114                OpEntryPoint GLCompute %1 "main"
    115        %void = OpTypeVoid
    116        %bool = OpTypeBool
    117        %true = OpConstantTrue %bool
    118        %uint = OpTypeInt 32 0
    119      %uint_0 = OpConstant %uint 0
    120      %uint_4 = OpConstant %uint 4
    121 %_arr_uint_uint_4 = OpTypeArray %uint %uint_4
    122 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
    123 %_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4
    124          %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform
    125          %12 = OpTypeFunction %void
    126           %1 = OpFunction %void None %12
    127          %13 = OpLabel
    128          %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0
    129          %15 = OpLoad %uint %14
    130                OpSelectionMerge %16 None
    131                OpBranchConditional %true %17 %16
    132          %17 = OpLabel
    133          %18 = OpCopyObject %uint %15
    134                OpBranch %16
    135          %16 = OpLabel
    136                OpReturn
    137                OpFunctionEnd
    138 )";
    139 
    140   SinglePassRunAndMatch<CodeSinkingPass>(text, true);
    141 }
    142 
    143 TEST_F(CodeSinkTest, LeaveBeforeSelection) {
    144   const std::string text = R"(
    145                OpCapability Shader
    146                OpMemoryModel Logical GLSL450
    147                OpEntryPoint GLCompute %1 "main"
    148        %void = OpTypeVoid
    149        %bool = OpTypeBool
    150        %true = OpConstantTrue %bool
    151        %uint = OpTypeInt 32 0
    152      %uint_0 = OpConstant %uint 0
    153      %uint_4 = OpConstant %uint 4
    154 %_arr_uint_uint_4 = OpTypeArray %uint %uint_4
    155 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
    156 %_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4
    157          %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform
    158          %12 = OpTypeFunction %void
    159           %1 = OpFunction %void None %12
    160          %13 = OpLabel
    161          %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0
    162          %15 = OpLoad %uint %14
    163                OpSelectionMerge %16 None
    164                OpBranchConditional %true %17 %20
    165          %20 = OpLabel
    166                OpBranch %16
    167          %17 = OpLabel
    168          %18 = OpCopyObject %uint %15
    169                OpBranch %16
    170          %16 = OpLabel
    171          %19 = OpCopyObject %uint %15
    172                OpReturn
    173                OpFunctionEnd
    174 )";
    175 
    176   auto result = SinglePassRunAndDisassemble<CodeSinkingPass>(
    177       text, /* skip_nop = */ true, /* do_validation = */ true);
    178   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
    179 }
    180 
    181 TEST_F(CodeSinkTest, LeaveAloneUseInSameBlock) {
    182   const std::string text = R"(
    183                OpCapability Shader
    184                OpMemoryModel Logical GLSL450
    185                OpEntryPoint GLCompute %1 "main"
    186        %void = OpTypeVoid
    187        %bool = OpTypeBool
    188        %true = OpConstantTrue %bool
    189        %uint = OpTypeInt 32 0
    190      %uint_0 = OpConstant %uint 0
    191      %uint_4 = OpConstant %uint 4
    192 %_arr_uint_uint_4 = OpTypeArray %uint %uint_4
    193 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
    194 %_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4
    195          %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform
    196          %12 = OpTypeFunction %void
    197           %1 = OpFunction %void None %12
    198          %13 = OpLabel
    199          %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0
    200          %15 = OpLoad %uint %14
    201        %cond = OpIEqual %bool %15 %uint_0
    202                OpSelectionMerge %16 None
    203                OpBranchConditional %cond %17 %16
    204          %17 = OpLabel
    205                OpBranch %16
    206          %16 = OpLabel
    207          %19 = OpCopyObject %uint %15
    208                OpReturn
    209                OpFunctionEnd
    210 )";
    211 
    212   auto result = SinglePassRunAndDisassemble<CodeSinkingPass>(
    213       text, /* skip_nop = */ true, /* do_validation = */ true);
    214   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
    215 }
    216 
    217 TEST_F(CodeSinkTest, DontMoveIntoLoop) {
    218   const std::string text = R"(
    219                OpCapability Shader
    220                OpMemoryModel Logical GLSL450
    221                OpEntryPoint GLCompute %1 "main"
    222        %void = OpTypeVoid
    223        %bool = OpTypeBool
    224        %true = OpConstantTrue %bool
    225        %uint = OpTypeInt 32 0
    226      %uint_0 = OpConstant %uint 0
    227      %uint_4 = OpConstant %uint 4
    228 %_arr_uint_uint_4 = OpTypeArray %uint %uint_4
    229 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
    230 %_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4
    231          %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform
    232          %12 = OpTypeFunction %void
    233           %1 = OpFunction %void None %12
    234          %13 = OpLabel
    235          %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0
    236          %15 = OpLoad %uint %14
    237                OpBranch %17
    238          %17 = OpLabel
    239                OpLoopMerge %merge %cont None
    240                OpBranch %cont
    241        %cont = OpLabel
    242        %cond = OpIEqual %bool %15 %uint_0
    243                OpBranchConditional %cond %merge %17
    244       %merge = OpLabel
    245                OpReturn
    246                OpFunctionEnd
    247 )";
    248 
    249   auto result = SinglePassRunAndDisassemble<CodeSinkingPass>(
    250       text, /* skip_nop = */ true, /* do_validation = */ true);
    251   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
    252 }
    253 
    254 TEST_F(CodeSinkTest, DontMoveIntoLoop2) {
    255   const std::string text = R"(
    256                OpCapability Shader
    257                OpMemoryModel Logical GLSL450
    258                OpEntryPoint GLCompute %1 "main"
    259        %void = OpTypeVoid
    260        %bool = OpTypeBool
    261        %true = OpConstantTrue %bool
    262        %uint = OpTypeInt 32 0
    263      %uint_0 = OpConstant %uint 0
    264      %uint_4 = OpConstant %uint 4
    265 %_arr_uint_uint_4 = OpTypeArray %uint %uint_4
    266 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
    267 %_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4
    268          %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform
    269          %12 = OpTypeFunction %void
    270           %1 = OpFunction %void None %12
    271          %13 = OpLabel
    272          %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0
    273          %15 = OpLoad %uint %14
    274                OpSelectionMerge %16 None
    275                OpBranchConditional %true %17 %16
    276          %17 = OpLabel
    277                OpLoopMerge %merge %cont None
    278                OpBranch %cont
    279        %cont = OpLabel
    280        %cond = OpIEqual %bool %15 %uint_0
    281                OpBranchConditional %cond %merge %17
    282       %merge = OpLabel
    283                OpBranch %16
    284          %16 = OpLabel
    285                OpReturn
    286                OpFunctionEnd
    287 )";
    288 
    289   auto result = SinglePassRunAndDisassemble<CodeSinkingPass>(
    290       text, /* skip_nop = */ true, /* do_validation = */ true);
    291   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
    292 }
    293 
    294 TEST_F(CodeSinkTest, DontMoveSelectionUsedInBothSides) {
    295   const std::string text = R"(
    296                OpCapability Shader
    297                OpMemoryModel Logical GLSL450
    298                OpEntryPoint GLCompute %1 "main"
    299        %void = OpTypeVoid
    300        %bool = OpTypeBool
    301        %true = OpConstantTrue %bool
    302        %uint = OpTypeInt 32 0
    303      %uint_0 = OpConstant %uint 0
    304      %uint_4 = OpConstant %uint 4
    305 %_arr_uint_uint_4 = OpTypeArray %uint %uint_4
    306 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
    307 %_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4
    308          %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform
    309          %12 = OpTypeFunction %void
    310           %1 = OpFunction %void None %12
    311          %13 = OpLabel
    312          %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0
    313          %15 = OpLoad %uint %14
    314                OpSelectionMerge %16 None
    315                OpBranchConditional %true %17 %20
    316          %20 = OpLabel
    317          %19 = OpCopyObject %uint %15
    318                OpBranch %16
    319          %17 = OpLabel
    320          %18 = OpCopyObject %uint %15
    321                OpBranch %16
    322          %16 = OpLabel
    323                OpReturn
    324                OpFunctionEnd
    325 )";
    326 
    327   auto result = SinglePassRunAndDisassemble<CodeSinkingPass>(
    328       text, /* skip_nop = */ true, /* do_validation = */ true);
    329   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
    330 }
    331 
    332 TEST_F(CodeSinkTest, DontMoveBecauseOfStore) {
    333   const std::string text = R"(
    334                OpCapability Shader
    335                OpMemoryModel Logical GLSL450
    336                OpEntryPoint GLCompute %1 "main"
    337        %void = OpTypeVoid
    338        %bool = OpTypeBool
    339        %true = OpConstantTrue %bool
    340        %uint = OpTypeInt 32 0
    341      %uint_0 = OpConstant %uint 0
    342      %uint_4 = OpConstant %uint 4
    343 %_arr_uint_uint_4 = OpTypeArray %uint %uint_4
    344 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
    345 %_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4
    346          %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform
    347          %12 = OpTypeFunction %void
    348           %1 = OpFunction %void None %12
    349          %13 = OpLabel
    350          %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0
    351          %15 = OpLoad %uint %14
    352                OpStore %14 %15
    353                OpSelectionMerge %16 None
    354                OpBranchConditional %true %17 %20
    355          %20 = OpLabel
    356                OpBranch %16
    357          %17 = OpLabel
    358          %18 = OpCopyObject %uint %15
    359                OpBranch %16
    360          %16 = OpLabel
    361                OpReturn
    362                OpFunctionEnd
    363 )";
    364 
    365   auto result = SinglePassRunAndDisassemble<CodeSinkingPass>(
    366       text, /* skip_nop = */ true, /* do_validation = */ true);
    367   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
    368 }
    369 
    370 TEST_F(CodeSinkTest, MoveReadOnlyLoadWithSync) {
    371   const std::string text = R"(
    372                OpCapability Shader
    373                OpMemoryModel Logical GLSL450
    374                OpEntryPoint GLCompute %1 "main"
    375        %void = OpTypeVoid
    376        %bool = OpTypeBool
    377        %true = OpConstantTrue %bool
    378        %uint = OpTypeInt 32 0
    379      %uint_0 = OpConstant %uint 0
    380      %uint_4 = OpConstant %uint 4
    381 %mem_semantics = OpConstant %uint 0x42 ; Uniform memeory arquire
    382 %_arr_uint_uint_4 = OpTypeArray %uint %uint_4
    383 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
    384 %_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4
    385          %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform
    386          %12 = OpTypeFunction %void
    387           %1 = OpFunction %void None %12
    388          %13 = OpLabel
    389          %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0
    390          %15 = OpLoad %uint %14
    391                OpMemoryBarrier %uint_4 %mem_semantics
    392                OpSelectionMerge %16 None
    393                OpBranchConditional %true %17 %20
    394          %20 = OpLabel
    395                OpBranch %16
    396          %17 = OpLabel
    397          %18 = OpCopyObject %uint %15
    398                OpBranch %16
    399          %16 = OpLabel
    400                OpReturn
    401                OpFunctionEnd
    402 )";
    403 
    404   auto result = SinglePassRunAndDisassemble<CodeSinkingPass>(
    405       text, /* skip_nop = */ true, /* do_validation = */ true);
    406   EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result));
    407 }
    408 
    409 TEST_F(CodeSinkTest, DontMoveBecauseOfSync) {
    410   const std::string text = R"(
    411                OpCapability Shader
    412                OpMemoryModel Logical GLSL450
    413                OpEntryPoint GLCompute %1 "main"
    414                OpDecorate %_arr_uint_uint_4 BufferBlock
    415                OpMemberDecorate %_arr_uint_uint_4 0 Offset 0
    416        %void = OpTypeVoid
    417        %bool = OpTypeBool
    418        %true = OpConstantTrue %bool
    419        %uint = OpTypeInt 32 0
    420      %uint_0 = OpConstant %uint 0
    421      %uint_4 = OpConstant %uint 4
    422 %mem_semantics = OpConstant %uint 0x42 ; Uniform memeory arquire
    423 %_arr_uint_uint_4 = OpTypeStruct %uint
    424 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
    425 %_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4
    426          %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform
    427          %12 = OpTypeFunction %void
    428           %1 = OpFunction %void None %12
    429          %13 = OpLabel
    430          %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0
    431          %15 = OpLoad %uint %14
    432                OpMemoryBarrier %uint_4 %mem_semantics
    433                OpSelectionMerge %16 None
    434                OpBranchConditional %true %17 %20
    435          %20 = OpLabel
    436                OpBranch %16
    437          %17 = OpLabel
    438          %18 = OpCopyObject %uint %15
    439                OpBranch %16
    440          %16 = OpLabel
    441                OpReturn
    442                OpFunctionEnd
    443 )";
    444 
    445   auto result = SinglePassRunAndDisassemble<CodeSinkingPass>(
    446       text, /* skip_nop = */ true, /* do_validation = */ true);
    447   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
    448 }
    449 
    450 TEST_F(CodeSinkTest, DontMoveBecauseOfAtomicWithSync) {
    451   const std::string text = R"(
    452                OpCapability Shader
    453                OpMemoryModel Logical GLSL450
    454                OpEntryPoint GLCompute %1 "main"
    455                OpDecorate %_arr_uint_uint_4 BufferBlock
    456                OpMemberDecorate %_arr_uint_uint_4 0 Offset 0
    457        %void = OpTypeVoid
    458        %bool = OpTypeBool
    459        %true = OpConstantTrue %bool
    460        %uint = OpTypeInt 32 0
    461      %uint_0 = OpConstant %uint 0
    462      %uint_4 = OpConstant %uint 4
    463 %mem_semantics = OpConstant %uint 0x42 ; Uniform memeory arquire
    464 %_arr_uint_uint_4 = OpTypeStruct %uint
    465 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
    466 %_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4
    467          %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform
    468          %12 = OpTypeFunction %void
    469           %1 = OpFunction %void None %12
    470          %13 = OpLabel
    471          %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0
    472          %15 = OpLoad %uint %14
    473          %al = OpAtomicLoad %uint %14 %uint_4 %mem_semantics
    474                OpSelectionMerge %16 None
    475                OpBranchConditional %true %17 %20
    476          %20 = OpLabel
    477                OpBranch %16
    478          %17 = OpLabel
    479          %18 = OpCopyObject %uint %15
    480                OpBranch %16
    481          %16 = OpLabel
    482                OpReturn
    483                OpFunctionEnd
    484 )";
    485 
    486   auto result = SinglePassRunAndDisassemble<CodeSinkingPass>(
    487       text, /* skip_nop = */ true, /* do_validation = */ true);
    488   EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
    489 }
    490 
    491 TEST_F(CodeSinkTest, MoveWithAtomicWithoutSync) {
    492   const std::string text = R"(
    493                OpCapability Shader
    494                OpMemoryModel Logical GLSL450
    495                OpEntryPoint GLCompute %1 "main"
    496                OpDecorate %_arr_uint_uint_4 BufferBlock
    497                OpMemberDecorate %_arr_uint_uint_4 0 Offset 0
    498        %void = OpTypeVoid
    499        %bool = OpTypeBool
    500        %true = OpConstantTrue %bool
    501        %uint = OpTypeInt 32 0
    502      %uint_0 = OpConstant %uint 0
    503      %uint_4 = OpConstant %uint 4
    504 %_arr_uint_uint_4 = OpTypeStruct %uint
    505 %_ptr_Uniform_uint = OpTypePointer Uniform %uint
    506 %_ptr_Uniform__arr_uint_uint_4 = OpTypePointer Uniform %_arr_uint_uint_4
    507          %11 = OpVariable %_ptr_Uniform__arr_uint_uint_4 Uniform
    508          %12 = OpTypeFunction %void
    509           %1 = OpFunction %void None %12
    510          %13 = OpLabel
    511          %14 = OpAccessChain %_ptr_Uniform_uint %11 %uint_0
    512          %15 = OpLoad %uint %14
    513          %al = OpAtomicLoad %uint %14 %uint_4 %uint_0
    514                OpSelectionMerge %16 None
    515                OpBranchConditional %true %17 %20
    516          %20 = OpLabel
    517                OpBranch %16
    518          %17 = OpLabel
    519          %18 = OpCopyObject %uint %15
    520                OpBranch %16
    521          %16 = OpLabel
    522                OpReturn
    523                OpFunctionEnd
    524 )";
    525 
    526   auto result = SinglePassRunAndDisassemble<CodeSinkingPass>(
    527       text, /* skip_nop = */ true, /* do_validation = */ true);
    528   EXPECT_EQ(Pass::Status::SuccessWithChange, std::get<1>(result));
    529 }
    530 
    531 }  // namespace
    532 }  // namespace opt
    533 }  // namespace spvtools
    534