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