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
21namespace spvtools {
22namespace opt {
23namespace {
24
25using CodeSinkTest = PassTest<::testing::Test>;
26
27TEST_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
61TEST_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
101TEST_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
142TEST_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
180TEST_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
216TEST_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
253TEST_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
293TEST_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
331TEST_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
369TEST_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
408TEST_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
449TEST_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
490TEST_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
530TEST_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