• 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 "source/fuzz/transformation_move_block_down.h"
16 #include "test/fuzz/fuzz_test_util.h"
17 
18 namespace spvtools {
19 namespace fuzz {
20 namespace {
21 
TEST(TransformationMoveBlockDownTest,NoMovePossible1)22 TEST(TransformationMoveBlockDownTest, NoMovePossible1) {
23   // Block 11 cannot be moved down as it dominates block 12.
24   std::string shader = R"(
25                OpCapability Shader
26           %1 = OpExtInstImport "GLSL.std.450"
27                OpMemoryModel Logical GLSL450
28                OpEntryPoint Fragment %4 "main"
29                OpExecutionMode %4 OriginUpperLeft
30                OpSource ESSL 310
31                OpDecorate %8 RelaxedPrecision
32           %2 = OpTypeVoid
33           %3 = OpTypeFunction %2
34           %6 = OpTypeInt 32 1
35           %7 = OpTypePointer Function %6
36           %9 = OpConstant %6 1
37          %10 = OpConstant %6 2
38           %4 = OpFunction %2 None %3
39           %5 = OpLabel
40           %8 = OpVariable %7 Function
41                OpBranch %11
42          %11 = OpLabel
43                OpStore %8 %9
44                OpBranch %12
45          %12 = OpLabel
46                OpStore %8 %10
47                OpReturn
48                OpFunctionEnd
49   )";
50 
51   const auto env = SPV_ENV_UNIVERSAL_1_3;
52   const auto consumer = nullptr;
53   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
54 
55   FactManager fact_manager;
56   spvtools::ValidatorOptions validator_options;
57   TransformationContext transformation_context(&fact_manager,
58                                                validator_options);
59 
60   auto transformation = TransformationMoveBlockDown(11);
61   ASSERT_FALSE(
62       transformation.IsApplicable(context.get(), transformation_context));
63 }
64 
TEST(TransformationMoveBlockDownTest,NoMovePossible2)65 TEST(TransformationMoveBlockDownTest, NoMovePossible2) {
66   // Block 5 cannot be moved down as it is the entry block.
67   std::string shader = R"(
68                OpCapability Shader
69           %1 = OpExtInstImport "GLSL.std.450"
70                OpMemoryModel Logical GLSL450
71                OpEntryPoint Fragment %4 "main"
72                OpExecutionMode %4 OriginUpperLeft
73                OpSource ESSL 310
74                OpDecorate %8 RelaxedPrecision
75           %2 = OpTypeVoid
76           %3 = OpTypeFunction %2
77           %6 = OpTypeInt 32 1
78           %7 = OpTypePointer Function %6
79           %9 = OpConstant %6 1
80          %10 = OpConstant %6 2
81           %4 = OpFunction %2 None %3
82           %5 = OpLabel
83           %8 = OpVariable %7 Function
84                OpStore %8 %9
85                OpStore %8 %10
86                OpReturn
87          %11 = OpLabel
88                OpReturn
89                OpFunctionEnd
90   )";
91 
92   const auto env = SPV_ENV_UNIVERSAL_1_3;
93   const auto consumer = nullptr;
94   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
95 
96   FactManager fact_manager;
97   spvtools::ValidatorOptions validator_options;
98   TransformationContext transformation_context(&fact_manager,
99                                                validator_options);
100 
101   auto transformation = TransformationMoveBlockDown(5);
102   ASSERT_FALSE(
103       transformation.IsApplicable(context.get(), transformation_context));
104 }
105 
TEST(TransformationMoveBlockDownTest,NoMovePossible3)106 TEST(TransformationMoveBlockDownTest, NoMovePossible3) {
107   // Block 100 does not exist, so cannot be moved down.
108   std::string shader = R"(
109                OpCapability Shader
110           %1 = OpExtInstImport "GLSL.std.450"
111                OpMemoryModel Logical GLSL450
112                OpEntryPoint Fragment %4 "main"
113                OpExecutionMode %4 OriginUpperLeft
114                OpSource ESSL 310
115                OpDecorate %8 RelaxedPrecision
116           %2 = OpTypeVoid
117           %3 = OpTypeFunction %2
118           %6 = OpTypeInt 32 1
119           %7 = OpTypePointer Function %6
120           %9 = OpConstant %6 1
121          %10 = OpConstant %6 2
122           %4 = OpFunction %2 None %3
123           %5 = OpLabel
124           %8 = OpVariable %7 Function
125                OpBranch %11
126          %11 = OpLabel
127                OpStore %8 %9
128                OpBranch %12
129          %12 = OpLabel
130                OpStore %8 %10
131                OpReturn
132                OpFunctionEnd
133   )";
134 
135   const auto env = SPV_ENV_UNIVERSAL_1_3;
136   const auto consumer = nullptr;
137   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
138 
139   FactManager fact_manager;
140   spvtools::ValidatorOptions validator_options;
141   TransformationContext transformation_context(&fact_manager,
142                                                validator_options);
143 
144   auto transformation = TransformationMoveBlockDown(100);
145   ASSERT_FALSE(
146       transformation.IsApplicable(context.get(), transformation_context));
147 }
148 
TEST(TransformationMoveBlockDownTest,NoMovePossible4)149 TEST(TransformationMoveBlockDownTest, NoMovePossible4) {
150   // Block 12 is the last block in its function, so cannot be moved down.
151   std::string shader = R"(
152                OpCapability Shader
153           %1 = OpExtInstImport "GLSL.std.450"
154                OpMemoryModel Logical GLSL450
155                OpEntryPoint Fragment %4 "main"
156                OpExecutionMode %4 OriginUpperLeft
157                OpSource ESSL 310
158                OpDecorate %8 RelaxedPrecision
159           %2 = OpTypeVoid
160           %3 = OpTypeFunction %2
161           %6 = OpTypeInt 32 1
162           %7 = OpTypePointer Function %6
163           %9 = OpConstant %6 1
164          %10 = OpConstant %6 2
165           %4 = OpFunction %2 None %3
166           %5 = OpLabel
167           %8 = OpVariable %7 Function
168                OpBranch %11
169          %11 = OpLabel
170                OpStore %8 %9
171                OpBranch %12
172          %12 = OpLabel
173                OpStore %8 %10
174                OpReturn
175                OpFunctionEnd
176          %13 = OpFunction %2 None %3
177          %14 = OpLabel
178                OpReturn
179                OpFunctionEnd
180   )";
181 
182   const auto env = SPV_ENV_UNIVERSAL_1_3;
183   const auto consumer = nullptr;
184   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
185 
186   FactManager fact_manager;
187   spvtools::ValidatorOptions validator_options;
188   TransformationContext transformation_context(&fact_manager,
189                                                validator_options);
190 
191   auto transformation = TransformationMoveBlockDown(12);
192   ASSERT_FALSE(
193       transformation.IsApplicable(context.get(), transformation_context));
194 }
195 
TEST(TransformationMoveBlockDownTest,ManyMovesPossible)196 TEST(TransformationMoveBlockDownTest, ManyMovesPossible) {
197   // The SPIR-V arising from this shader has lots of opportunities for moving
198   // blocks around.
199   //
200   // void main() {
201   //   int x;
202   //   int y;
203   //   if (x < y) {
204   //     x = 1;
205   //     if (y == x) {
206   //       x = 3;
207   //     } else {
208   //       x = 4;
209   //     }
210   //   } else {
211   //     if (y < x) {
212   //       x = 5;
213   //     } else {
214   //       x = 6;
215   //     }
216   //   }
217   // }
218 
219   std::string before_transformation = R"(
220                OpCapability Shader
221           %1 = OpExtInstImport "GLSL.std.450"
222                OpMemoryModel Logical GLSL450
223                OpEntryPoint Fragment %4 "main"
224                OpExecutionMode %4 OriginUpperLeft
225                OpSource ESSL 310
226                OpName %4 "main"
227                OpName %8 "x"
228                OpName %10 "y"
229                OpDecorate %8 RelaxedPrecision
230                OpDecorate %9 RelaxedPrecision
231                OpDecorate %10 RelaxedPrecision
232                OpDecorate %11 RelaxedPrecision
233                OpDecorate %17 RelaxedPrecision
234                OpDecorate %18 RelaxedPrecision
235                OpDecorate %26 RelaxedPrecision
236                OpDecorate %27 RelaxedPrecision
237           %2 = OpTypeVoid
238           %3 = OpTypeFunction %2
239           %6 = OpTypeInt 32 1
240           %7 = OpTypePointer Function %6
241          %12 = OpTypeBool
242          %16 = OpConstant %6 1
243          %22 = OpConstant %6 3
244          %24 = OpConstant %6 4
245          %31 = OpConstant %6 5
246          %33 = OpConstant %6 6
247           %4 = OpFunction %2 None %3
248           %5 = OpLabel
249           %8 = OpVariable %7 Function
250          %10 = OpVariable %7 Function
251           %9 = OpLoad %6 %8
252          %11 = OpLoad %6 %10
253          %13 = OpSLessThan %12 %9 %11
254                OpSelectionMerge %15 None
255                OpBranchConditional %13 %14 %25
256          %14 = OpLabel
257                OpStore %8 %16
258          %17 = OpLoad %6 %10
259          %18 = OpLoad %6 %8
260          %19 = OpIEqual %12 %17 %18
261                OpSelectionMerge %21 None
262                OpBranchConditional %19 %20 %23
263          %20 = OpLabel
264                OpStore %8 %22
265                OpBranch %21
266          %23 = OpLabel
267                OpStore %8 %24
268                OpBranch %21
269          %21 = OpLabel
270                OpBranch %15
271          %25 = OpLabel
272          %26 = OpLoad %6 %10
273          %27 = OpLoad %6 %8
274          %28 = OpSLessThan %12 %26 %27
275                OpSelectionMerge %30 None
276                OpBranchConditional %28 %29 %32
277          %29 = OpLabel
278                OpStore %8 %31
279                OpBranch %30
280          %32 = OpLabel
281                OpStore %8 %33
282                OpBranch %30
283          %30 = OpLabel
284                OpBranch %15
285          %15 = OpLabel
286                OpReturn
287                OpFunctionEnd
288   )";
289 
290   const auto env = SPV_ENV_UNIVERSAL_1_3;
291   const auto consumer = nullptr;
292   const auto context =
293       BuildModule(env, consumer, before_transformation, kFuzzAssembleOption);
294 
295   FactManager fact_manager;
296   spvtools::ValidatorOptions validator_options;
297   TransformationContext transformation_context(&fact_manager,
298                                                validator_options);
299 
300   // The block ids are: 5 14 20 23 21 25 29 32 30 15
301   // We make a transformation to move each of them down, plus a transformation
302   // to move a non-block, 27, down.
303   auto move_down_5 = TransformationMoveBlockDown(5);
304   auto move_down_14 = TransformationMoveBlockDown(14);
305   auto move_down_20 = TransformationMoveBlockDown(20);
306   auto move_down_23 = TransformationMoveBlockDown(23);
307   auto move_down_21 = TransformationMoveBlockDown(21);
308   auto move_down_25 = TransformationMoveBlockDown(25);
309   auto move_down_29 = TransformationMoveBlockDown(29);
310   auto move_down_32 = TransformationMoveBlockDown(32);
311   auto move_down_30 = TransformationMoveBlockDown(30);
312   auto move_down_15 = TransformationMoveBlockDown(15);
313   auto move_down_27 = TransformationMoveBlockDown(27);
314 
315   // Dominance is as follows:
316   //  5 dominates everything else
317   // 14 dominates 20, 23, 21
318   // 20 dominates nothing
319   // 23 dominates nothing
320   // 21 dominates nothing
321   // 25 dominates 29, 32, 30
322   // 29 dominates nothing
323   // 32 dominates nothing
324   // 30 dominates nothing
325   // 15 dominates nothing
326 
327   // Current ordering: 5 14 20 23 21 25 29 32 30 15
328   ASSERT_FALSE(move_down_5.IsApplicable(context.get(), transformation_context));
329   ASSERT_FALSE(
330       move_down_14.IsApplicable(context.get(), transformation_context));
331   ASSERT_TRUE(move_down_20.IsApplicable(context.get(), transformation_context));
332   ASSERT_TRUE(move_down_23.IsApplicable(context.get(), transformation_context));
333   ASSERT_TRUE(move_down_21.IsApplicable(context.get(), transformation_context));
334   ASSERT_FALSE(
335       move_down_25.IsApplicable(context.get(), transformation_context));
336   ASSERT_TRUE(move_down_29.IsApplicable(context.get(), transformation_context));
337   ASSERT_TRUE(move_down_32.IsApplicable(context.get(), transformation_context));
338   ASSERT_TRUE(move_down_30.IsApplicable(context.get(), transformation_context));
339   ASSERT_FALSE(
340       move_down_15.IsApplicable(context.get(), transformation_context));
341 
342   // Let's bubble 20 all the way down.
343 
344   move_down_20.Apply(context.get(), &transformation_context);
345   ASSERT_TRUE(IsValid(env, context.get()));
346 
347   // Current ordering: 5 14 23 20 21 25 29 32 30 15
348   ASSERT_FALSE(move_down_5.IsApplicable(context.get(), transformation_context));
349   ASSERT_FALSE(
350       move_down_14.IsApplicable(context.get(), transformation_context));
351   ASSERT_TRUE(move_down_23.IsApplicable(context.get(), transformation_context));
352   ASSERT_TRUE(move_down_20.IsApplicable(context.get(), transformation_context));
353   ASSERT_TRUE(move_down_21.IsApplicable(context.get(), transformation_context));
354   ASSERT_FALSE(
355       move_down_25.IsApplicable(context.get(), transformation_context));
356   ASSERT_TRUE(move_down_29.IsApplicable(context.get(), transformation_context));
357   ASSERT_TRUE(move_down_32.IsApplicable(context.get(), transformation_context));
358   ASSERT_TRUE(move_down_30.IsApplicable(context.get(), transformation_context));
359   ASSERT_FALSE(
360       move_down_15.IsApplicable(context.get(), transformation_context));
361 
362   move_down_20.Apply(context.get(), &transformation_context);
363   ASSERT_TRUE(IsValid(env, context.get()));
364 
365   // Current ordering: 5 14 23 21 20 25 29 32 30 15
366   ASSERT_FALSE(move_down_5.IsApplicable(context.get(), transformation_context));
367   ASSERT_FALSE(
368       move_down_14.IsApplicable(context.get(), transformation_context));
369   ASSERT_TRUE(move_down_23.IsApplicable(context.get(), transformation_context));
370   ASSERT_TRUE(move_down_21.IsApplicable(context.get(), transformation_context));
371   ASSERT_TRUE(move_down_20.IsApplicable(context.get(), transformation_context));
372   ASSERT_FALSE(
373       move_down_25.IsApplicable(context.get(), transformation_context));
374   ASSERT_TRUE(move_down_29.IsApplicable(context.get(), transformation_context));
375   ASSERT_TRUE(move_down_32.IsApplicable(context.get(), transformation_context));
376   ASSERT_TRUE(move_down_30.IsApplicable(context.get(), transformation_context));
377   ASSERT_FALSE(
378       move_down_15.IsApplicable(context.get(), transformation_context));
379 
380   move_down_20.Apply(context.get(), &transformation_context);
381   ASSERT_TRUE(IsValid(env, context.get()));
382 
383   // Current ordering: 5 14 23 21 25 20 29 32 30 15
384   ASSERT_FALSE(move_down_5.IsApplicable(context.get(), transformation_context));
385   ASSERT_FALSE(
386       move_down_14.IsApplicable(context.get(), transformation_context));
387   ASSERT_TRUE(move_down_23.IsApplicable(context.get(), transformation_context));
388   ASSERT_TRUE(move_down_21.IsApplicable(context.get(), transformation_context));
389   ASSERT_TRUE(move_down_25.IsApplicable(context.get(), transformation_context));
390   ASSERT_TRUE(move_down_20.IsApplicable(context.get(), transformation_context));
391   ASSERT_TRUE(move_down_29.IsApplicable(context.get(), transformation_context));
392   ASSERT_TRUE(move_down_32.IsApplicable(context.get(), transformation_context));
393   ASSERT_TRUE(move_down_30.IsApplicable(context.get(), transformation_context));
394   ASSERT_FALSE(
395       move_down_15.IsApplicable(context.get(), transformation_context));
396 
397   move_down_20.Apply(context.get(), &transformation_context);
398   ASSERT_TRUE(IsValid(env, context.get()));
399 
400   // Current ordering: 5 14 23 21 25 29 20 32 30 15
401   ASSERT_FALSE(move_down_5.IsApplicable(context.get(), transformation_context));
402   ASSERT_FALSE(
403       move_down_14.IsApplicable(context.get(), transformation_context));
404   ASSERT_TRUE(move_down_23.IsApplicable(context.get(), transformation_context));
405   ASSERT_TRUE(move_down_21.IsApplicable(context.get(), transformation_context));
406   ASSERT_FALSE(
407       move_down_25.IsApplicable(context.get(), transformation_context));
408   ASSERT_TRUE(move_down_29.IsApplicable(context.get(), transformation_context));
409   ASSERT_TRUE(move_down_20.IsApplicable(context.get(), transformation_context));
410   ASSERT_TRUE(move_down_32.IsApplicable(context.get(), transformation_context));
411   ASSERT_TRUE(move_down_30.IsApplicable(context.get(), transformation_context));
412   ASSERT_FALSE(
413       move_down_15.IsApplicable(context.get(), transformation_context));
414 
415   move_down_20.Apply(context.get(), &transformation_context);
416   ASSERT_TRUE(IsValid(env, context.get()));
417 
418   // Current ordering: 5 14 23 21 25 29 32 20 30 15
419   ASSERT_FALSE(move_down_5.IsApplicable(context.get(), transformation_context));
420   ASSERT_FALSE(
421       move_down_14.IsApplicable(context.get(), transformation_context));
422   ASSERT_TRUE(move_down_23.IsApplicable(context.get(), transformation_context));
423   ASSERT_TRUE(move_down_21.IsApplicable(context.get(), transformation_context));
424   ASSERT_FALSE(
425       move_down_25.IsApplicable(context.get(), transformation_context));
426   ASSERT_TRUE(move_down_29.IsApplicable(context.get(), transformation_context));
427   ASSERT_TRUE(move_down_32.IsApplicable(context.get(), transformation_context));
428   ASSERT_TRUE(move_down_20.IsApplicable(context.get(), transformation_context));
429   ASSERT_TRUE(move_down_30.IsApplicable(context.get(), transformation_context));
430   ASSERT_FALSE(
431       move_down_15.IsApplicable(context.get(), transformation_context));
432 
433   move_down_20.Apply(context.get(), &transformation_context);
434   ASSERT_TRUE(IsValid(env, context.get()));
435 
436   // Current ordering: 5 14 23 21 25 29 32 30 20 15
437   ASSERT_FALSE(move_down_5.IsApplicable(context.get(), transformation_context));
438   ASSERT_FALSE(
439       move_down_14.IsApplicable(context.get(), transformation_context));
440   ASSERT_TRUE(move_down_23.IsApplicable(context.get(), transformation_context));
441   ASSERT_TRUE(move_down_21.IsApplicable(context.get(), transformation_context));
442   ASSERT_FALSE(
443       move_down_25.IsApplicable(context.get(), transformation_context));
444   ASSERT_TRUE(move_down_29.IsApplicable(context.get(), transformation_context));
445   ASSERT_TRUE(move_down_32.IsApplicable(context.get(), transformation_context));
446   ASSERT_TRUE(move_down_30.IsApplicable(context.get(), transformation_context));
447   ASSERT_TRUE(move_down_20.IsApplicable(context.get(), transformation_context));
448   ASSERT_FALSE(
449       move_down_15.IsApplicable(context.get(), transformation_context));
450 
451   move_down_20.Apply(context.get(), &transformation_context);
452   ASSERT_TRUE(IsValid(env, context.get()));
453 
454   std::string after_bubbling_20_down = R"(
455                OpCapability Shader
456           %1 = OpExtInstImport "GLSL.std.450"
457                OpMemoryModel Logical GLSL450
458                OpEntryPoint Fragment %4 "main"
459                OpExecutionMode %4 OriginUpperLeft
460                OpSource ESSL 310
461                OpName %4 "main"
462                OpName %8 "x"
463                OpName %10 "y"
464                OpDecorate %8 RelaxedPrecision
465                OpDecorate %9 RelaxedPrecision
466                OpDecorate %10 RelaxedPrecision
467                OpDecorate %11 RelaxedPrecision
468                OpDecorate %17 RelaxedPrecision
469                OpDecorate %18 RelaxedPrecision
470                OpDecorate %26 RelaxedPrecision
471                OpDecorate %27 RelaxedPrecision
472           %2 = OpTypeVoid
473           %3 = OpTypeFunction %2
474           %6 = OpTypeInt 32 1
475           %7 = OpTypePointer Function %6
476          %12 = OpTypeBool
477          %16 = OpConstant %6 1
478          %22 = OpConstant %6 3
479          %24 = OpConstant %6 4
480          %31 = OpConstant %6 5
481          %33 = OpConstant %6 6
482           %4 = OpFunction %2 None %3
483           %5 = OpLabel
484           %8 = OpVariable %7 Function
485          %10 = OpVariable %7 Function
486           %9 = OpLoad %6 %8
487          %11 = OpLoad %6 %10
488          %13 = OpSLessThan %12 %9 %11
489                OpSelectionMerge %15 None
490                OpBranchConditional %13 %14 %25
491          %14 = OpLabel
492                OpStore %8 %16
493          %17 = OpLoad %6 %10
494          %18 = OpLoad %6 %8
495          %19 = OpIEqual %12 %17 %18
496                OpSelectionMerge %21 None
497                OpBranchConditional %19 %20 %23
498          %23 = OpLabel
499                OpStore %8 %24
500                OpBranch %21
501          %21 = OpLabel
502                OpBranch %15
503          %25 = OpLabel
504          %26 = OpLoad %6 %10
505          %27 = OpLoad %6 %8
506          %28 = OpSLessThan %12 %26 %27
507                OpSelectionMerge %30 None
508                OpBranchConditional %28 %29 %32
509          %29 = OpLabel
510                OpStore %8 %31
511                OpBranch %30
512          %32 = OpLabel
513                OpStore %8 %33
514                OpBranch %30
515          %30 = OpLabel
516                OpBranch %15
517          %15 = OpLabel
518                OpReturn
519          %20 = OpLabel
520                OpStore %8 %22
521                OpBranch %21
522                OpFunctionEnd
523   )";
524   ASSERT_TRUE(IsEqual(env, after_bubbling_20_down, context.get()));
525 
526   // Current ordering: 5 14 23 21 25 29 32 30 15 20
527   ASSERT_FALSE(move_down_5.IsApplicable(context.get(), transformation_context));
528   ASSERT_FALSE(
529       move_down_14.IsApplicable(context.get(), transformation_context));
530   ASSERT_TRUE(move_down_23.IsApplicable(context.get(), transformation_context));
531   ASSERT_TRUE(move_down_21.IsApplicable(context.get(), transformation_context));
532   ASSERT_FALSE(
533       move_down_25.IsApplicable(context.get(), transformation_context));
534   ASSERT_TRUE(move_down_29.IsApplicable(context.get(), transformation_context));
535   ASSERT_TRUE(move_down_32.IsApplicable(context.get(), transformation_context));
536   ASSERT_TRUE(move_down_30.IsApplicable(context.get(), transformation_context));
537   ASSERT_TRUE(move_down_15.IsApplicable(context.get(), transformation_context));
538   ASSERT_FALSE(
539       move_down_20.IsApplicable(context.get(), transformation_context));
540 
541   move_down_23.Apply(context.get(), &transformation_context);
542   ASSERT_TRUE(IsValid(env, context.get()));
543 
544   // Current ordering: 5 14 21 23 25 29 32 30 15 20
545   ASSERT_FALSE(move_down_5.IsApplicable(context.get(), transformation_context));
546   ASSERT_FALSE(
547       move_down_14.IsApplicable(context.get(), transformation_context));
548   ASSERT_TRUE(move_down_21.IsApplicable(context.get(), transformation_context));
549   ASSERT_TRUE(move_down_23.IsApplicable(context.get(), transformation_context));
550   ASSERT_FALSE(
551       move_down_25.IsApplicable(context.get(), transformation_context));
552   ASSERT_TRUE(move_down_29.IsApplicable(context.get(), transformation_context));
553   ASSERT_TRUE(move_down_32.IsApplicable(context.get(), transformation_context));
554   ASSERT_TRUE(move_down_30.IsApplicable(context.get(), transformation_context));
555   ASSERT_TRUE(move_down_15.IsApplicable(context.get(), transformation_context));
556   ASSERT_FALSE(
557       move_down_20.IsApplicable(context.get(), transformation_context));
558 
559   move_down_23.Apply(context.get(), &transformation_context);
560   ASSERT_TRUE(IsValid(env, context.get()));
561 
562   // Current ordering: 5 14 21 25 23 29 32 30 15 20
563   ASSERT_FALSE(move_down_5.IsApplicable(context.get(), transformation_context));
564   ASSERT_FALSE(
565       move_down_14.IsApplicable(context.get(), transformation_context));
566   ASSERT_TRUE(move_down_21.IsApplicable(context.get(), transformation_context));
567   ASSERT_TRUE(move_down_25.IsApplicable(context.get(), transformation_context));
568   ASSERT_TRUE(move_down_23.IsApplicable(context.get(), transformation_context));
569   ASSERT_TRUE(move_down_29.IsApplicable(context.get(), transformation_context));
570   ASSERT_TRUE(move_down_32.IsApplicable(context.get(), transformation_context));
571   ASSERT_TRUE(move_down_30.IsApplicable(context.get(), transformation_context));
572   ASSERT_TRUE(move_down_15.IsApplicable(context.get(), transformation_context));
573   ASSERT_FALSE(
574       move_down_20.IsApplicable(context.get(), transformation_context));
575 
576   move_down_21.Apply(context.get(), &transformation_context);
577   ASSERT_TRUE(IsValid(env, context.get()));
578 
579   // Current ordering: 5 14 25 21 23 29 32 30 15 20
580   ASSERT_FALSE(move_down_5.IsApplicable(context.get(), transformation_context));
581   ASSERT_TRUE(move_down_14.IsApplicable(context.get(), transformation_context));
582   ASSERT_TRUE(move_down_21.IsApplicable(context.get(), transformation_context));
583   ASSERT_TRUE(move_down_25.IsApplicable(context.get(), transformation_context));
584   ASSERT_TRUE(move_down_23.IsApplicable(context.get(), transformation_context));
585   ASSERT_TRUE(move_down_29.IsApplicable(context.get(), transformation_context));
586   ASSERT_TRUE(move_down_32.IsApplicable(context.get(), transformation_context));
587   ASSERT_TRUE(move_down_30.IsApplicable(context.get(), transformation_context));
588   ASSERT_TRUE(move_down_15.IsApplicable(context.get(), transformation_context));
589   ASSERT_FALSE(
590       move_down_20.IsApplicable(context.get(), transformation_context));
591 
592   move_down_14.Apply(context.get(), &transformation_context);
593   ASSERT_TRUE(IsValid(env, context.get()));
594 
595   std::string after_more_shuffling = R"(
596                OpCapability Shader
597           %1 = OpExtInstImport "GLSL.std.450"
598                OpMemoryModel Logical GLSL450
599                OpEntryPoint Fragment %4 "main"
600                OpExecutionMode %4 OriginUpperLeft
601                OpSource ESSL 310
602                OpName %4 "main"
603                OpName %8 "x"
604                OpName %10 "y"
605                OpDecorate %8 RelaxedPrecision
606                OpDecorate %9 RelaxedPrecision
607                OpDecorate %10 RelaxedPrecision
608                OpDecorate %11 RelaxedPrecision
609                OpDecorate %17 RelaxedPrecision
610                OpDecorate %18 RelaxedPrecision
611                OpDecorate %26 RelaxedPrecision
612                OpDecorate %27 RelaxedPrecision
613           %2 = OpTypeVoid
614           %3 = OpTypeFunction %2
615           %6 = OpTypeInt 32 1
616           %7 = OpTypePointer Function %6
617          %12 = OpTypeBool
618          %16 = OpConstant %6 1
619          %22 = OpConstant %6 3
620          %24 = OpConstant %6 4
621          %31 = OpConstant %6 5
622          %33 = OpConstant %6 6
623           %4 = OpFunction %2 None %3
624           %5 = OpLabel
625           %8 = OpVariable %7 Function
626          %10 = OpVariable %7 Function
627           %9 = OpLoad %6 %8
628          %11 = OpLoad %6 %10
629          %13 = OpSLessThan %12 %9 %11
630                OpSelectionMerge %15 None
631                OpBranchConditional %13 %14 %25
632          %25 = OpLabel
633          %26 = OpLoad %6 %10
634          %27 = OpLoad %6 %8
635          %28 = OpSLessThan %12 %26 %27
636                OpSelectionMerge %30 None
637                OpBranchConditional %28 %29 %32
638          %14 = OpLabel
639                OpStore %8 %16
640          %17 = OpLoad %6 %10
641          %18 = OpLoad %6 %8
642          %19 = OpIEqual %12 %17 %18
643                OpSelectionMerge %21 None
644                OpBranchConditional %19 %20 %23
645          %21 = OpLabel
646                OpBranch %15
647          %23 = OpLabel
648                OpStore %8 %24
649                OpBranch %21
650          %29 = OpLabel
651                OpStore %8 %31
652                OpBranch %30
653          %32 = OpLabel
654                OpStore %8 %33
655                OpBranch %30
656          %30 = OpLabel
657                OpBranch %15
658          %15 = OpLabel
659                OpReturn
660          %20 = OpLabel
661                OpStore %8 %22
662                OpBranch %21
663                OpFunctionEnd
664   )";
665   ASSERT_TRUE(IsEqual(env, after_more_shuffling, context.get()));
666 
667   // Final ordering: 5 25 14 21 23 29 32 30 15 20
668   ASSERT_FALSE(move_down_5.IsApplicable(context.get(), transformation_context));
669   ASSERT_TRUE(move_down_25.IsApplicable(context.get(), transformation_context));
670   ASSERT_FALSE(
671       move_down_14.IsApplicable(context.get(), transformation_context));
672   ASSERT_TRUE(move_down_21.IsApplicable(context.get(), transformation_context));
673   ASSERT_TRUE(move_down_23.IsApplicable(context.get(), transformation_context));
674   ASSERT_TRUE(move_down_29.IsApplicable(context.get(), transformation_context));
675   ASSERT_TRUE(move_down_32.IsApplicable(context.get(), transformation_context));
676   ASSERT_TRUE(move_down_30.IsApplicable(context.get(), transformation_context));
677   ASSERT_TRUE(move_down_15.IsApplicable(context.get(), transformation_context));
678   ASSERT_FALSE(
679       move_down_20.IsApplicable(context.get(), transformation_context));
680 }
681 
TEST(TransformationMoveBlockDownTest,DoNotMoveUnreachable)682 TEST(TransformationMoveBlockDownTest, DoNotMoveUnreachable) {
683   // Block 6 is unreachable, so cannot be moved down.
684   std::string shader = R"(
685                OpCapability Shader
686           %1 = OpExtInstImport "GLSL.std.450"
687                OpMemoryModel Logical GLSL450
688                OpEntryPoint Fragment %4 "main"
689                OpExecutionMode %4 OriginUpperLeft
690                OpSource ESSL 310
691                OpName %4 "main"
692           %2 = OpTypeVoid
693           %3 = OpTypeFunction %2
694          %10 = OpTypeInt 32 1
695           %4 = OpFunction %2 None %3
696           %5 = OpLabel
697                OpReturn
698           %6 = OpLabel
699           %7 = OpUndef %10
700                OpBranch %8
701           %8 = OpLabel
702           %9 = OpCopyObject %10 %7
703                OpReturn
704                OpFunctionEnd
705   )";
706 
707   const auto env = SPV_ENV_UNIVERSAL_1_3;
708   const auto consumer = nullptr;
709   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
710   ASSERT_TRUE(IsValid(env, context.get()));
711 
712   FactManager fact_manager;
713   spvtools::ValidatorOptions validator_options;
714   TransformationContext transformation_context(&fact_manager,
715                                                validator_options);
716 
717   auto transformation = TransformationMoveBlockDown(6);
718   ASSERT_FALSE(
719       transformation.IsApplicable(context.get(), transformation_context));
720 }
721 
722 }  // namespace
723 }  // namespace fuzz
724 }  // namespace spvtools
725