• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TEST_F(CodeSinkTest,MoveToNextBlock)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 
TEST_F(CodeSinkTest,MovePastSelection)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 
TEST_F(CodeSinkTest,MoveIntoSelection)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 
TEST_F(CodeSinkTest,LeaveBeforeSelection)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 
TEST_F(CodeSinkTest,LeaveAloneUseInSameBlock)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 
TEST_F(CodeSinkTest,DontMoveIntoLoop)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 
TEST_F(CodeSinkTest,DontMoveIntoLoop2)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 
TEST_F(CodeSinkTest,DontMoveSelectionUsedInBothSides)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 
TEST_F(CodeSinkTest,DontMoveBecauseOfStore)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 
TEST_F(CodeSinkTest,MoveReadOnlyLoadWithSync)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 
TEST_F(CodeSinkTest,DontMoveBecauseOfSync)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 
TEST_F(CodeSinkTest,DontMoveBecauseOfAtomicWithSync)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 
TEST_F(CodeSinkTest,MoveWithAtomicWithoutSync)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