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_set_loop_control.h"
16 
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "test/fuzz/fuzz_test_util.h"
20 
21 namespace spvtools {
22 namespace fuzz {
23 namespace {
24 
TEST(TransformationSetLoopControlTest,VariousScenarios)25 TEST(TransformationSetLoopControlTest, VariousScenarios) {
26   // This test features loops with various different controls, and goes through
27   // a number of acceptable and unacceptable transformations to those controls.
28 
29   std::string shader = R"(
30                OpCapability Shader
31           %1 = OpExtInstImport "GLSL.std.450"
32                OpMemoryModel Logical GLSL450
33                OpEntryPoint Fragment %4 "main"
34                OpExecutionMode %4 OriginUpperLeft
35                OpSource ESSL 310
36                OpName %4 "main"
37           %2 = OpTypeVoid
38           %3 = OpTypeFunction %2
39           %6 = OpTypeInt 32 1
40           %7 = OpTypePointer Function %6
41           %9 = OpConstant %6 0
42          %16 = OpConstant %6 100
43          %17 = OpTypeBool
44          %20 = OpConstant %6 1
45           %4 = OpFunction %2 None %3
46           %5 = OpLabel
47           %8 = OpVariable %7 Function
48          %22 = OpVariable %7 Function
49          %32 = OpVariable %7 Function
50          %42 = OpVariable %7 Function
51          %52 = OpVariable %7 Function
52          %62 = OpVariable %7 Function
53          %72 = OpVariable %7 Function
54          %82 = OpVariable %7 Function
55          %92 = OpVariable %7 Function
56         %102 = OpVariable %7 Function
57         %112 = OpVariable %7 Function
58         %122 = OpVariable %7 Function
59                OpStore %8 %9
60                OpBranch %10
61          %10 = OpLabel
62         %132 = OpPhi %6 %9 %5 %21 %13
63                OpLoopMerge %12 %13 None
64                OpBranch %14
65          %14 = OpLabel
66          %18 = OpSLessThan %17 %132 %16
67                OpBranchConditional %18 %11 %12
68          %11 = OpLabel
69                OpBranch %13
70          %13 = OpLabel
71          %21 = OpIAdd %6 %132 %20
72                OpStore %8 %21
73                OpBranch %10
74          %12 = OpLabel
75                OpStore %22 %9
76                OpBranch %23
77          %23 = OpLabel
78         %133 = OpPhi %6 %9 %12 %31 %26
79                OpLoopMerge %25 %26 Unroll
80                OpBranch %27
81          %27 = OpLabel
82          %29 = OpSLessThan %17 %133 %16
83                OpBranchConditional %29 %24 %25
84          %24 = OpLabel
85                OpBranch %26
86          %26 = OpLabel
87          %31 = OpIAdd %6 %133 %20
88                OpStore %22 %31
89                OpBranch %23
90          %25 = OpLabel
91                OpStore %32 %9
92                OpBranch %33
93          %33 = OpLabel
94         %134 = OpPhi %6 %9 %25 %41 %36
95                OpLoopMerge %35 %36 DontUnroll
96                OpBranch %37
97          %37 = OpLabel
98          %39 = OpSLessThan %17 %134 %16
99                OpBranchConditional %39 %34 %35
100          %34 = OpLabel
101                OpBranch %36
102          %36 = OpLabel
103          %41 = OpIAdd %6 %134 %20
104                OpStore %32 %41
105                OpBranch %33
106          %35 = OpLabel
107                OpStore %42 %9
108                OpBranch %43
109          %43 = OpLabel
110         %135 = OpPhi %6 %9 %35 %51 %46
111                OpLoopMerge %45 %46 DependencyInfinite
112                OpBranch %47
113          %47 = OpLabel
114          %49 = OpSLessThan %17 %135 %16
115                OpBranchConditional %49 %44 %45
116          %44 = OpLabel
117                OpBranch %46
118          %46 = OpLabel
119          %51 = OpIAdd %6 %135 %20
120                OpStore %42 %51
121                OpBranch %43
122          %45 = OpLabel
123                OpStore %52 %9
124                OpBranch %53
125          %53 = OpLabel
126         %136 = OpPhi %6 %9 %45 %61 %56
127                OpLoopMerge %55 %56 DependencyLength 3
128                OpBranch %57
129          %57 = OpLabel
130          %59 = OpSLessThan %17 %136 %16
131                OpBranchConditional %59 %54 %55
132          %54 = OpLabel
133                OpBranch %56
134          %56 = OpLabel
135          %61 = OpIAdd %6 %136 %20
136                OpStore %52 %61
137                OpBranch %53
138          %55 = OpLabel
139                OpStore %62 %9
140                OpBranch %63
141          %63 = OpLabel
142         %137 = OpPhi %6 %9 %55 %71 %66
143                OpLoopMerge %65 %66 MinIterations 10
144                OpBranch %67
145          %67 = OpLabel
146          %69 = OpSLessThan %17 %137 %16
147                OpBranchConditional %69 %64 %65
148          %64 = OpLabel
149                OpBranch %66
150          %66 = OpLabel
151          %71 = OpIAdd %6 %137 %20
152                OpStore %62 %71
153                OpBranch %63
154          %65 = OpLabel
155                OpStore %72 %9
156                OpBranch %73
157          %73 = OpLabel
158         %138 = OpPhi %6 %9 %65 %81 %76
159                OpLoopMerge %75 %76 MaxIterations 50
160                OpBranch %77
161          %77 = OpLabel
162          %79 = OpSLessThan %17 %138 %16
163                OpBranchConditional %79 %74 %75
164          %74 = OpLabel
165                OpBranch %76
166          %76 = OpLabel
167          %81 = OpIAdd %6 %138 %20
168                OpStore %72 %81
169                OpBranch %73
170          %75 = OpLabel
171                OpStore %82 %9
172                OpBranch %83
173          %83 = OpLabel
174         %139 = OpPhi %6 %9 %75 %91 %86
175                OpLoopMerge %85 %86 IterationMultiple 4
176                OpBranch %87
177          %87 = OpLabel
178          %89 = OpSLessThan %17 %139 %16
179                OpBranchConditional %89 %84 %85
180          %84 = OpLabel
181                OpBranch %86
182          %86 = OpLabel
183          %91 = OpIAdd %6 %139 %20
184                OpStore %82 %91
185                OpBranch %83
186          %85 = OpLabel
187                OpStore %92 %9
188                OpBranch %93
189          %93 = OpLabel
190         %140 = OpPhi %6 %9 %85 %101 %96
191                OpLoopMerge %95 %96 PeelCount 2
192                OpBranch %97
193          %97 = OpLabel
194          %99 = OpSLessThan %17 %140 %16
195                OpBranchConditional %99 %94 %95
196          %94 = OpLabel
197                OpBranch %96
198          %96 = OpLabel
199         %101 = OpIAdd %6 %140 %20
200                OpStore %92 %101
201                OpBranch %93
202          %95 = OpLabel
203                OpStore %102 %9
204                OpBranch %103
205         %103 = OpLabel
206         %141 = OpPhi %6 %9 %95 %111 %106
207                OpLoopMerge %105 %106 PartialCount 3
208                OpBranch %107
209         %107 = OpLabel
210         %109 = OpSLessThan %17 %141 %16
211                OpBranchConditional %109 %104 %105
212         %104 = OpLabel
213                OpBranch %106
214         %106 = OpLabel
215         %111 = OpIAdd %6 %141 %20
216                OpStore %102 %111
217                OpBranch %103
218         %105 = OpLabel
219                OpStore %112 %9
220                OpBranch %113
221         %113 = OpLabel
222         %142 = OpPhi %6 %9 %105 %121 %116
223                OpLoopMerge %115 %116 Unroll|PeelCount|PartialCount 3 4
224                OpBranch %117
225         %117 = OpLabel
226         %119 = OpSLessThan %17 %142 %16
227                OpBranchConditional %119 %114 %115
228         %114 = OpLabel
229                OpBranch %116
230         %116 = OpLabel
231         %121 = OpIAdd %6 %142 %20
232                OpStore %112 %121
233                OpBranch %113
234         %115 = OpLabel
235                OpStore %122 %9
236                OpBranch %123
237         %123 = OpLabel
238         %143 = OpPhi %6 %9 %115 %131 %126
239                OpLoopMerge %125 %126 DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount 2 5 90 4 7 14
240                OpBranch %127
241         %127 = OpLabel
242         %129 = OpSLessThan %17 %143 %16
243                OpBranchConditional %129 %124 %125
244         %124 = OpLabel
245                OpBranch %126
246         %126 = OpLabel
247         %131 = OpIAdd %6 %143 %20
248                OpStore %122 %131
249                OpBranch %123
250         %125 = OpLabel
251                OpReturn
252                OpFunctionEnd
253   )";
254 
255   const auto env = SPV_ENV_UNIVERSAL_1_4;
256   const auto consumer = nullptr;
257   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
258 
259   spvtools::ValidatorOptions validator_options;
260   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
261                                                kConsoleMessageConsumer));
262   TransformationContext transformation_context(
263       MakeUnique<FactManager>(context.get()), validator_options);
264   // These are the loop headers together with the selection controls of their
265   // merge instructions:
266   //  %10 None
267   //  %23 Unroll
268   //  %33 DontUnroll
269   //  %43 DependencyInfinite
270   //  %53 DependencyLength 3
271   //  %63 MinIterations 10
272   //  %73 MaxIterations 50
273   //  %83 IterationMultiple 4
274   //  %93 PeelCount 2
275   // %103 PartialCount 3
276   // %113 Unroll|PeelCount|PartialCount 3 4
277   // %123
278   // DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount
279   // 2 5 90 4 7 14
280 
281   ASSERT_TRUE(TransformationSetLoopControl(10, SpvLoopControlMaskNone, 0, 0)
282                   .IsApplicable(context.get(), transformation_context));
283   ASSERT_TRUE(TransformationSetLoopControl(10, SpvLoopControlUnrollMask, 0, 0)
284                   .IsApplicable(context.get(), transformation_context));
285   ASSERT_TRUE(
286       TransformationSetLoopControl(10, SpvLoopControlDontUnrollMask, 0, 0)
287           .IsApplicable(context.get(), transformation_context));
288   ASSERT_FALSE(TransformationSetLoopControl(
289                    10, SpvLoopControlDependencyInfiniteMask, 0, 0)
290                    .IsApplicable(context.get(), transformation_context));
291   ASSERT_FALSE(
292       TransformationSetLoopControl(10, SpvLoopControlDependencyLengthMask, 0, 0)
293           .IsApplicable(context.get(), transformation_context));
294   ASSERT_FALSE(
295       TransformationSetLoopControl(10, SpvLoopControlMinIterationsMask, 0, 0)
296           .IsApplicable(context.get(), transformation_context));
297   ASSERT_FALSE(
298       TransformationSetLoopControl(10, SpvLoopControlMaxIterationsMask, 0, 0)
299           .IsApplicable(context.get(), transformation_context));
300   ASSERT_FALSE(TransformationSetLoopControl(
301                    10, SpvLoopControlIterationMultipleMask, 0, 0)
302                    .IsApplicable(context.get(), transformation_context));
303   ASSERT_TRUE(
304       TransformationSetLoopControl(10, SpvLoopControlPeelCountMask, 3, 0)
305           .IsApplicable(context.get(), transformation_context));
306   ASSERT_FALSE(
307       TransformationSetLoopControl(10, SpvLoopControlPeelCountMask, 3, 3)
308           .IsApplicable(context.get(), transformation_context));
309   ASSERT_TRUE(
310       TransformationSetLoopControl(10, SpvLoopControlPartialCountMask, 0, 3)
311           .IsApplicable(context.get(), transformation_context));
312   ASSERT_FALSE(
313       TransformationSetLoopControl(10, SpvLoopControlPartialCountMask, 3, 3)
314           .IsApplicable(context.get(), transformation_context));
315   ASSERT_TRUE(TransformationSetLoopControl(
316                   10,
317                   SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
318                   3, 3)
319                   .IsApplicable(context.get(), transformation_context));
320   ASSERT_TRUE(TransformationSetLoopControl(10,
321                                            SpvLoopControlUnrollMask |
322                                                SpvLoopControlPeelCountMask |
323                                                SpvLoopControlPartialCountMask,
324                                            3, 3)
325                   .IsApplicable(context.get(), transformation_context));
326   ASSERT_FALSE(TransformationSetLoopControl(10,
327                                             SpvLoopControlDontUnrollMask |
328                                                 SpvLoopControlPeelCountMask |
329                                                 SpvLoopControlPartialCountMask,
330                                             3, 3)
331                    .IsApplicable(context.get(), transformation_context));
332 
333   ASSERT_TRUE(TransformationSetLoopControl(23, SpvLoopControlMaskNone, 0, 0)
334                   .IsApplicable(context.get(), transformation_context));
335   ASSERT_TRUE(TransformationSetLoopControl(23, SpvLoopControlUnrollMask, 0, 0)
336                   .IsApplicable(context.get(), transformation_context));
337   ASSERT_TRUE(
338       TransformationSetLoopControl(23, SpvLoopControlDontUnrollMask, 0, 0)
339           .IsApplicable(context.get(), transformation_context));
340   ASSERT_TRUE(TransformationSetLoopControl(
341                   23,
342                   SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
343                   3, 3)
344                   .IsApplicable(context.get(), transformation_context));
345   ASSERT_FALSE(
346       TransformationSetLoopControl(23, SpvLoopControlMaxIterationsMask, 2, 3)
347           .IsApplicable(context.get(), transformation_context));
348 
349   ASSERT_TRUE(TransformationSetLoopControl(33, SpvLoopControlMaskNone, 0, 0)
350                   .IsApplicable(context.get(), transformation_context));
351   ASSERT_TRUE(TransformationSetLoopControl(33, SpvLoopControlUnrollMask, 0, 0)
352                   .IsApplicable(context.get(), transformation_context));
353   ASSERT_TRUE(
354       TransformationSetLoopControl(33, SpvLoopControlDontUnrollMask, 0, 0)
355           .IsApplicable(context.get(), transformation_context));
356   ASSERT_FALSE(
357       TransformationSetLoopControl(33, SpvLoopControlMinIterationsMask, 0, 0)
358           .IsApplicable(context.get(), transformation_context));
359   ASSERT_TRUE(
360       TransformationSetLoopControl(
361           33, SpvLoopControlUnrollMask | SpvLoopControlPeelCountMask, 5, 0)
362           .IsApplicable(context.get(), transformation_context));
363   ASSERT_FALSE(TransformationSetLoopControl(33,
364                                             SpvLoopControlDontUnrollMask |
365                                                 SpvLoopControlPartialCountMask,
366                                             0, 10)
367                    .IsApplicable(context.get(), transformation_context));
368 
369   ASSERT_TRUE(TransformationSetLoopControl(43, SpvLoopControlMaskNone, 0, 0)
370                   .IsApplicable(context.get(), transformation_context));
371   ASSERT_TRUE(TransformationSetLoopControl(43, SpvLoopControlUnrollMask, 0, 0)
372                   .IsApplicable(context.get(), transformation_context));
373   ASSERT_TRUE(
374       TransformationSetLoopControl(43, SpvLoopControlDontUnrollMask, 0, 0)
375           .IsApplicable(context.get(), transformation_context));
376   ASSERT_TRUE(TransformationSetLoopControl(
377                   43,
378                   SpvLoopControlMaskNone | SpvLoopControlDependencyInfiniteMask,
379                   0, 0)
380                   .IsApplicable(context.get(), transformation_context));
381   ASSERT_TRUE(
382       TransformationSetLoopControl(
383           43, SpvLoopControlUnrollMask | SpvLoopControlDependencyInfiniteMask,
384           0, 0)
385           .IsApplicable(context.get(), transformation_context));
386   ASSERT_TRUE(
387       TransformationSetLoopControl(
388           43,
389           SpvLoopControlDontUnrollMask | SpvLoopControlDependencyInfiniteMask,
390           0, 0)
391           .IsApplicable(context.get(), transformation_context));
392   ASSERT_FALSE(
393       TransformationSetLoopControl(43,
394                                    SpvLoopControlDependencyInfiniteMask |
395                                        SpvLoopControlDependencyLengthMask,
396                                    0, 0)
397           .IsApplicable(context.get(), transformation_context));
398   ASSERT_TRUE(
399       TransformationSetLoopControl(
400           43, SpvLoopControlUnrollMask | SpvLoopControlPeelCountMask, 5, 0)
401           .IsApplicable(context.get(), transformation_context));
402 
403   ASSERT_TRUE(TransformationSetLoopControl(53, SpvLoopControlMaskNone, 0, 0)
404                   .IsApplicable(context.get(), transformation_context));
405   ASSERT_TRUE(TransformationSetLoopControl(53, SpvLoopControlUnrollMask, 0, 0)
406                   .IsApplicable(context.get(), transformation_context));
407   ASSERT_TRUE(
408       TransformationSetLoopControl(53, SpvLoopControlDontUnrollMask, 0, 0)
409           .IsApplicable(context.get(), transformation_context));
410   ASSERT_FALSE(
411       TransformationSetLoopControl(53, SpvLoopControlMaxIterationsMask, 0, 0)
412           .IsApplicable(context.get(), transformation_context));
413   ASSERT_TRUE(
414       TransformationSetLoopControl(
415           53, SpvLoopControlMaskNone | SpvLoopControlDependencyLengthMask, 0, 0)
416           .IsApplicable(context.get(), transformation_context));
417   ASSERT_FALSE(
418       TransformationSetLoopControl(
419           53, SpvLoopControlUnrollMask | SpvLoopControlDependencyInfiniteMask,
420           0, 0)
421           .IsApplicable(context.get(), transformation_context));
422   ASSERT_TRUE(
423       TransformationSetLoopControl(
424           53, SpvLoopControlDontUnrollMask | SpvLoopControlDependencyLengthMask,
425           0, 0)
426           .IsApplicable(context.get(), transformation_context));
427   ASSERT_FALSE(
428       TransformationSetLoopControl(53,
429                                    SpvLoopControlDependencyInfiniteMask |
430                                        SpvLoopControlDependencyLengthMask,
431                                    0, 0)
432           .IsApplicable(context.get(), transformation_context));
433   ASSERT_TRUE(
434       TransformationSetLoopControl(
435           53,
436           SpvLoopControlUnrollMask | SpvLoopControlDependencyLengthMask |
437               SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
438           5, 3)
439           .IsApplicable(context.get(), transformation_context));
440 
441   ASSERT_TRUE(TransformationSetLoopControl(63, SpvLoopControlMaskNone, 0, 0)
442                   .IsApplicable(context.get(), transformation_context));
443   ASSERT_TRUE(TransformationSetLoopControl(63, SpvLoopControlUnrollMask, 0, 0)
444                   .IsApplicable(context.get(), transformation_context));
445   ASSERT_TRUE(
446       TransformationSetLoopControl(63, SpvLoopControlDontUnrollMask, 0, 0)
447           .IsApplicable(context.get(), transformation_context));
448   ASSERT_TRUE(TransformationSetLoopControl(63,
449                                            SpvLoopControlUnrollMask |
450                                                SpvLoopControlMinIterationsMask |
451                                                SpvLoopControlPeelCountMask |
452                                                SpvLoopControlPartialCountMask,
453                                            5, 3)
454                   .IsApplicable(context.get(), transformation_context));
455   ASSERT_TRUE(TransformationSetLoopControl(63,
456                                            SpvLoopControlUnrollMask |
457                                                SpvLoopControlMinIterationsMask |
458                                                SpvLoopControlPeelCountMask,
459                                            23, 0)
460                   .IsApplicable(context.get(), transformation_context));
461   ASSERT_FALSE(TransformationSetLoopControl(
462                    63,
463                    SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
464                        SpvLoopControlPeelCountMask,
465                    2, 23)
466                    .IsApplicable(context.get(), transformation_context));
467 
468   ASSERT_TRUE(TransformationSetLoopControl(73, SpvLoopControlMaskNone, 0, 0)
469                   .IsApplicable(context.get(), transformation_context));
470   ASSERT_TRUE(TransformationSetLoopControl(73, SpvLoopControlUnrollMask, 0, 0)
471                   .IsApplicable(context.get(), transformation_context));
472   ASSERT_TRUE(
473       TransformationSetLoopControl(73, SpvLoopControlDontUnrollMask, 0, 0)
474           .IsApplicable(context.get(), transformation_context));
475   ASSERT_FALSE(TransformationSetLoopControl(
476                    73,
477                    SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
478                        SpvLoopControlPeelCountMask |
479                        SpvLoopControlPartialCountMask,
480                    5, 3)
481                    .IsApplicable(context.get(), transformation_context));
482   ASSERT_TRUE(TransformationSetLoopControl(73,
483                                            SpvLoopControlUnrollMask |
484                                                SpvLoopControlMaxIterationsMask |
485                                                SpvLoopControlPeelCountMask,
486                                            23, 0)
487                   .IsApplicable(context.get(), transformation_context));
488   ASSERT_FALSE(TransformationSetLoopControl(
489                    73,
490                    SpvLoopControlUnrollMask | SpvLoopControlMaxIterationsMask |
491                        SpvLoopControlPeelCountMask,
492                    2, 23)
493                    .IsApplicable(context.get(), transformation_context));
494 
495   ASSERT_TRUE(TransformationSetLoopControl(83, SpvLoopControlMaskNone, 0, 0)
496                   .IsApplicable(context.get(), transformation_context));
497   ASSERT_TRUE(TransformationSetLoopControl(83, SpvLoopControlUnrollMask, 0, 0)
498                   .IsApplicable(context.get(), transformation_context));
499   ASSERT_TRUE(
500       TransformationSetLoopControl(83, SpvLoopControlDontUnrollMask, 0, 0)
501           .IsApplicable(context.get(), transformation_context));
502   ASSERT_FALSE(TransformationSetLoopControl(
503                    83,
504                    SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
505                        SpvLoopControlPeelCountMask |
506                        SpvLoopControlPartialCountMask,
507                    5, 3)
508                    .IsApplicable(context.get(), transformation_context));
509   ASSERT_TRUE(
510       TransformationSetLoopControl(83,
511                                    SpvLoopControlUnrollMask |
512                                        SpvLoopControlIterationMultipleMask |
513                                        SpvLoopControlPeelCountMask,
514                                    23, 0)
515           .IsApplicable(context.get(), transformation_context));
516   ASSERT_FALSE(
517       TransformationSetLoopControl(83,
518                                    SpvLoopControlUnrollMask |
519                                        SpvLoopControlIterationMultipleMask |
520                                        SpvLoopControlPeelCountMask,
521                                    2, 23)
522           .IsApplicable(context.get(), transformation_context));
523 
524   ASSERT_TRUE(TransformationSetLoopControl(93, SpvLoopControlMaskNone, 0, 0)
525                   .IsApplicable(context.get(), transformation_context));
526   ASSERT_TRUE(TransformationSetLoopControl(93, SpvLoopControlUnrollMask, 0, 0)
527                   .IsApplicable(context.get(), transformation_context));
528   ASSERT_TRUE(
529       TransformationSetLoopControl(93, SpvLoopControlDontUnrollMask, 0, 0)
530           .IsApplicable(context.get(), transformation_context));
531   ASSERT_TRUE(
532       TransformationSetLoopControl(93, SpvLoopControlPeelCountMask, 8, 0)
533           .IsApplicable(context.get(), transformation_context));
534   ASSERT_FALSE(
535       TransformationSetLoopControl(93, SpvLoopControlPeelCountMask, 8, 8)
536           .IsApplicable(context.get(), transformation_context));
537   ASSERT_TRUE(
538       TransformationSetLoopControl(93, SpvLoopControlPartialCountMask, 0, 8)
539           .IsApplicable(context.get(), transformation_context));
540   ASSERT_TRUE(TransformationSetLoopControl(
541                   93,
542                   SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
543                   16, 8)
544                   .IsApplicable(context.get(), transformation_context));
545 
546   ASSERT_TRUE(TransformationSetLoopControl(103, SpvLoopControlMaskNone, 0, 0)
547                   .IsApplicable(context.get(), transformation_context));
548   ASSERT_TRUE(TransformationSetLoopControl(103, SpvLoopControlUnrollMask, 0, 0)
549                   .IsApplicable(context.get(), transformation_context));
550   ASSERT_TRUE(
551       TransformationSetLoopControl(103, SpvLoopControlDontUnrollMask, 0, 0)
552           .IsApplicable(context.get(), transformation_context));
553   ASSERT_TRUE(
554       TransformationSetLoopControl(103, SpvLoopControlPartialCountMask, 0, 60)
555           .IsApplicable(context.get(), transformation_context));
556   ASSERT_FALSE(TransformationSetLoopControl(103,
557                                             SpvLoopControlDontUnrollMask |
558                                                 SpvLoopControlPartialCountMask,
559                                             0, 60)
560                    .IsApplicable(context.get(), transformation_context));
561 
562   ASSERT_TRUE(TransformationSetLoopControl(113, SpvLoopControlMaskNone, 0, 0)
563                   .IsApplicable(context.get(), transformation_context));
564   ASSERT_TRUE(TransformationSetLoopControl(113, SpvLoopControlUnrollMask, 0, 0)
565                   .IsApplicable(context.get(), transformation_context));
566   ASSERT_TRUE(
567       TransformationSetLoopControl(113, SpvLoopControlDontUnrollMask, 0, 0)
568           .IsApplicable(context.get(), transformation_context));
569   ASSERT_TRUE(
570       TransformationSetLoopControl(113, SpvLoopControlPeelCountMask, 12, 0)
571           .IsApplicable(context.get(), transformation_context));
572   ASSERT_FALSE(
573       TransformationSetLoopControl(
574           113,
575           SpvLoopControlIterationMultipleMask | SpvLoopControlPeelCountMask, 12,
576           0)
577           .IsApplicable(context.get(), transformation_context));
578 
579   ASSERT_TRUE(TransformationSetLoopControl(123, SpvLoopControlMaskNone, 0, 0)
580                   .IsApplicable(context.get(), transformation_context));
581   ASSERT_TRUE(TransformationSetLoopControl(123, SpvLoopControlUnrollMask, 0, 0)
582                   .IsApplicable(context.get(), transformation_context));
583   ASSERT_TRUE(
584       TransformationSetLoopControl(123, SpvLoopControlDontUnrollMask, 0, 0)
585           .IsApplicable(context.get(), transformation_context));
586   ASSERT_TRUE(
587       TransformationSetLoopControl(
588           123,
589           SpvLoopControlMinIterationsMask | SpvLoopControlMaxIterationsMask |
590               SpvLoopControlIterationMultipleMask |
591               SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask,
592           7, 8)
593           .IsApplicable(context.get(), transformation_context));
594   ASSERT_TRUE(TransformationSetLoopControl(123,
595                                            SpvLoopControlUnrollMask |
596                                                SpvLoopControlMinIterationsMask |
597                                                SpvLoopControlMaxIterationsMask |
598                                                SpvLoopControlPartialCountMask,
599                                            0, 9)
600                   .IsApplicable(context.get(), transformation_context));
601   ASSERT_FALSE(TransformationSetLoopControl(
602                    123,
603                    SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
604                        SpvLoopControlMaxIterationsMask |
605                        SpvLoopControlPartialCountMask,
606                    7, 9)
607                    .IsApplicable(context.get(), transformation_context));
608   ASSERT_FALSE(
609       TransformationSetLoopControl(
610           123,
611           SpvLoopControlDontUnrollMask | SpvLoopControlMinIterationsMask |
612               SpvLoopControlMaxIterationsMask | SpvLoopControlPartialCountMask,
613           7, 9)
614           .IsApplicable(context.get(), transformation_context));
615 
616   ApplyAndCheckFreshIds(
617       TransformationSetLoopControl(10,
618                                    SpvLoopControlUnrollMask |
619                                        SpvLoopControlPeelCountMask |
620                                        SpvLoopControlPartialCountMask,
621                                    3, 3),
622       context.get(), &transformation_context);
623   ApplyAndCheckFreshIds(
624       TransformationSetLoopControl(23, SpvLoopControlDontUnrollMask, 0, 0),
625       context.get(), &transformation_context);
626   ApplyAndCheckFreshIds(
627       TransformationSetLoopControl(33, SpvLoopControlUnrollMask, 0, 0),
628       context.get(), &transformation_context);
629   ApplyAndCheckFreshIds(
630       TransformationSetLoopControl(
631           43,
632           SpvLoopControlDontUnrollMask | SpvLoopControlDependencyInfiniteMask,
633           0, 0),
634       context.get(), &transformation_context);
635   ApplyAndCheckFreshIds(
636       TransformationSetLoopControl(53, SpvLoopControlMaskNone, 0, 0),
637       context.get(), &transformation_context);
638   ApplyAndCheckFreshIds(
639       TransformationSetLoopControl(63,
640                                    SpvLoopControlUnrollMask |
641                                        SpvLoopControlMinIterationsMask |
642                                        SpvLoopControlPeelCountMask,
643                                    23, 0),
644       context.get(), &transformation_context);
645   ApplyAndCheckFreshIds(
646       TransformationSetLoopControl(73,
647                                    SpvLoopControlUnrollMask |
648                                        SpvLoopControlMaxIterationsMask |
649                                        SpvLoopControlPeelCountMask,
650                                    23, 0),
651       context.get(), &transformation_context);
652   ApplyAndCheckFreshIds(
653       TransformationSetLoopControl(83, SpvLoopControlDontUnrollMask, 0, 0),
654       context.get(), &transformation_context);
655   ApplyAndCheckFreshIds(
656       TransformationSetLoopControl(
657           93, SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask, 16,
658           8),
659       context.get(), &transformation_context);
660   ApplyAndCheckFreshIds(
661       TransformationSetLoopControl(103, SpvLoopControlPartialCountMask, 0, 60),
662       context.get(), &transformation_context);
663   ApplyAndCheckFreshIds(
664       TransformationSetLoopControl(113, SpvLoopControlPeelCountMask, 12, 0),
665       context.get(), &transformation_context);
666   ApplyAndCheckFreshIds(
667       TransformationSetLoopControl(
668           123,
669           SpvLoopControlUnrollMask | SpvLoopControlMinIterationsMask |
670               SpvLoopControlMaxIterationsMask | SpvLoopControlPartialCountMask,
671           0, 9),
672       context.get(), &transformation_context);
673 
674   std::string after_transformation = R"(
675                OpCapability Shader
676           %1 = OpExtInstImport "GLSL.std.450"
677                OpMemoryModel Logical GLSL450
678                OpEntryPoint Fragment %4 "main"
679                OpExecutionMode %4 OriginUpperLeft
680                OpSource ESSL 310
681                OpName %4 "main"
682           %2 = OpTypeVoid
683           %3 = OpTypeFunction %2
684           %6 = OpTypeInt 32 1
685           %7 = OpTypePointer Function %6
686           %9 = OpConstant %6 0
687          %16 = OpConstant %6 100
688          %17 = OpTypeBool
689          %20 = OpConstant %6 1
690           %4 = OpFunction %2 None %3
691           %5 = OpLabel
692           %8 = OpVariable %7 Function
693          %22 = OpVariable %7 Function
694          %32 = OpVariable %7 Function
695          %42 = OpVariable %7 Function
696          %52 = OpVariable %7 Function
697          %62 = OpVariable %7 Function
698          %72 = OpVariable %7 Function
699          %82 = OpVariable %7 Function
700          %92 = OpVariable %7 Function
701         %102 = OpVariable %7 Function
702         %112 = OpVariable %7 Function
703         %122 = OpVariable %7 Function
704                OpStore %8 %9
705                OpBranch %10
706          %10 = OpLabel
707         %132 = OpPhi %6 %9 %5 %21 %13
708                OpLoopMerge %12 %13 Unroll|PeelCount|PartialCount 3 3
709                OpBranch %14
710          %14 = OpLabel
711          %18 = OpSLessThan %17 %132 %16
712                OpBranchConditional %18 %11 %12
713          %11 = OpLabel
714                OpBranch %13
715          %13 = OpLabel
716          %21 = OpIAdd %6 %132 %20
717                OpStore %8 %21
718                OpBranch %10
719          %12 = OpLabel
720                OpStore %22 %9
721                OpBranch %23
722          %23 = OpLabel
723         %133 = OpPhi %6 %9 %12 %31 %26
724                OpLoopMerge %25 %26 DontUnroll
725                OpBranch %27
726          %27 = OpLabel
727          %29 = OpSLessThan %17 %133 %16
728                OpBranchConditional %29 %24 %25
729          %24 = OpLabel
730                OpBranch %26
731          %26 = OpLabel
732          %31 = OpIAdd %6 %133 %20
733                OpStore %22 %31
734                OpBranch %23
735          %25 = OpLabel
736                OpStore %32 %9
737                OpBranch %33
738          %33 = OpLabel
739         %134 = OpPhi %6 %9 %25 %41 %36
740                OpLoopMerge %35 %36 Unroll
741                OpBranch %37
742          %37 = OpLabel
743          %39 = OpSLessThan %17 %134 %16
744                OpBranchConditional %39 %34 %35
745          %34 = OpLabel
746                OpBranch %36
747          %36 = OpLabel
748          %41 = OpIAdd %6 %134 %20
749                OpStore %32 %41
750                OpBranch %33
751          %35 = OpLabel
752                OpStore %42 %9
753                OpBranch %43
754          %43 = OpLabel
755         %135 = OpPhi %6 %9 %35 %51 %46
756                OpLoopMerge %45 %46 DontUnroll|DependencyInfinite
757                OpBranch %47
758          %47 = OpLabel
759          %49 = OpSLessThan %17 %135 %16
760                OpBranchConditional %49 %44 %45
761          %44 = OpLabel
762                OpBranch %46
763          %46 = OpLabel
764          %51 = OpIAdd %6 %135 %20
765                OpStore %42 %51
766                OpBranch %43
767          %45 = OpLabel
768                OpStore %52 %9
769                OpBranch %53
770          %53 = OpLabel
771         %136 = OpPhi %6 %9 %45 %61 %56
772                OpLoopMerge %55 %56 None
773                OpBranch %57
774          %57 = OpLabel
775          %59 = OpSLessThan %17 %136 %16
776                OpBranchConditional %59 %54 %55
777          %54 = OpLabel
778                OpBranch %56
779          %56 = OpLabel
780          %61 = OpIAdd %6 %136 %20
781                OpStore %52 %61
782                OpBranch %53
783          %55 = OpLabel
784                OpStore %62 %9
785                OpBranch %63
786          %63 = OpLabel
787         %137 = OpPhi %6 %9 %55 %71 %66
788                OpLoopMerge %65 %66 Unroll|MinIterations|PeelCount 10 23
789                OpBranch %67
790          %67 = OpLabel
791          %69 = OpSLessThan %17 %137 %16
792                OpBranchConditional %69 %64 %65
793          %64 = OpLabel
794                OpBranch %66
795          %66 = OpLabel
796          %71 = OpIAdd %6 %137 %20
797                OpStore %62 %71
798                OpBranch %63
799          %65 = OpLabel
800                OpStore %72 %9
801                OpBranch %73
802          %73 = OpLabel
803         %138 = OpPhi %6 %9 %65 %81 %76
804                OpLoopMerge %75 %76 Unroll|MaxIterations|PeelCount 50 23
805                OpBranch %77
806          %77 = OpLabel
807          %79 = OpSLessThan %17 %138 %16
808                OpBranchConditional %79 %74 %75
809          %74 = OpLabel
810                OpBranch %76
811          %76 = OpLabel
812          %81 = OpIAdd %6 %138 %20
813                OpStore %72 %81
814                OpBranch %73
815          %75 = OpLabel
816                OpStore %82 %9
817                OpBranch %83
818          %83 = OpLabel
819         %139 = OpPhi %6 %9 %75 %91 %86
820                OpLoopMerge %85 %86 DontUnroll
821                OpBranch %87
822          %87 = OpLabel
823          %89 = OpSLessThan %17 %139 %16
824                OpBranchConditional %89 %84 %85
825          %84 = OpLabel
826                OpBranch %86
827          %86 = OpLabel
828          %91 = OpIAdd %6 %139 %20
829                OpStore %82 %91
830                OpBranch %83
831          %85 = OpLabel
832                OpStore %92 %9
833                OpBranch %93
834          %93 = OpLabel
835         %140 = OpPhi %6 %9 %85 %101 %96
836                OpLoopMerge %95 %96 PeelCount|PartialCount 16 8
837                OpBranch %97
838          %97 = OpLabel
839          %99 = OpSLessThan %17 %140 %16
840                OpBranchConditional %99 %94 %95
841          %94 = OpLabel
842                OpBranch %96
843          %96 = OpLabel
844         %101 = OpIAdd %6 %140 %20
845                OpStore %92 %101
846                OpBranch %93
847          %95 = OpLabel
848                OpStore %102 %9
849                OpBranch %103
850         %103 = OpLabel
851         %141 = OpPhi %6 %9 %95 %111 %106
852                OpLoopMerge %105 %106 PartialCount 60
853                OpBranch %107
854         %107 = OpLabel
855         %109 = OpSLessThan %17 %141 %16
856                OpBranchConditional %109 %104 %105
857         %104 = OpLabel
858                OpBranch %106
859         %106 = OpLabel
860         %111 = OpIAdd %6 %141 %20
861                OpStore %102 %111
862                OpBranch %103
863         %105 = OpLabel
864                OpStore %112 %9
865                OpBranch %113
866         %113 = OpLabel
867         %142 = OpPhi %6 %9 %105 %121 %116
868                OpLoopMerge %115 %116 PeelCount 12
869                OpBranch %117
870         %117 = OpLabel
871         %119 = OpSLessThan %17 %142 %16
872                OpBranchConditional %119 %114 %115
873         %114 = OpLabel
874                OpBranch %116
875         %116 = OpLabel
876         %121 = OpIAdd %6 %142 %20
877                OpStore %112 %121
878                OpBranch %113
879         %115 = OpLabel
880                OpStore %122 %9
881                OpBranch %123
882         %123 = OpLabel
883         %143 = OpPhi %6 %9 %115 %131 %126
884                OpLoopMerge %125 %126 Unroll|MinIterations|MaxIterations|PartialCount 5 90 9
885                OpBranch %127
886         %127 = OpLabel
887         %129 = OpSLessThan %17 %143 %16
888                OpBranchConditional %129 %124 %125
889         %124 = OpLabel
890                OpBranch %126
891         %126 = OpLabel
892         %131 = OpIAdd %6 %143 %20
893                OpStore %122 %131
894                OpBranch %123
895         %125 = OpLabel
896                OpReturn
897                OpFunctionEnd
898   )";
899   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
900 }
901 
TEST(TransformationSetLoopControlTest,CheckSPIRVVersionsRespected)902 TEST(TransformationSetLoopControlTest, CheckSPIRVVersionsRespected) {
903   // This test checks that we do not allow introducing PeelCount and
904   // PartialCount loop controls if the SPIR-V version being used does not
905   // support them.
906 
907   std::string shader = R"(
908                OpCapability Shader
909           %1 = OpExtInstImport "GLSL.std.450"
910                OpMemoryModel Logical GLSL450
911                OpEntryPoint Fragment %4 "main"
912                OpExecutionMode %4 OriginUpperLeft
913                OpSource ESSL 310
914                OpName %4 "main"
915                OpName %8 "i"
916           %2 = OpTypeVoid
917           %3 = OpTypeFunction %2
918           %6 = OpTypeInt 32 1
919           %7 = OpTypePointer Function %6
920           %9 = OpConstant %6 0
921          %16 = OpConstant %6 10
922          %17 = OpTypeBool
923          %20 = OpConstant %6 1
924           %4 = OpFunction %2 None %3
925           %5 = OpLabel
926           %8 = OpVariable %7 Function
927                OpStore %8 %9
928                OpBranch %10
929          %10 = OpLabel
930                OpLoopMerge %12 %13 None
931                OpBranch %14
932          %14 = OpLabel
933          %15 = OpLoad %6 %8
934          %18 = OpSLessThan %17 %15 %16
935                OpBranchConditional %18 %11 %12
936          %11 = OpLabel
937                OpBranch %13
938          %13 = OpLabel
939          %19 = OpLoad %6 %8
940          %21 = OpIAdd %6 %19 %20
941                OpStore %8 %21
942                OpBranch %10
943          %12 = OpLabel
944                OpReturn
945                OpFunctionEnd
946   )";
947 
948   for (auto env :
949        {SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2,
950         SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5}) {
951     const auto consumer = nullptr;
952     const auto context =
953         BuildModule(env, consumer, shader, kFuzzAssembleOption);
954     spvtools::ValidatorOptions validator_options;
955     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
956         context.get(), validator_options, kConsoleMessageConsumer));
957     TransformationContext transformation_context(
958         MakeUnique<FactManager>(context.get()), validator_options);
959     TransformationSetLoopControl transformation(
960         10, SpvLoopControlPeelCountMask | SpvLoopControlPartialCountMask, 4, 4);
961 
962     switch (env) {
963       case SPV_ENV_UNIVERSAL_1_0:
964       case SPV_ENV_UNIVERSAL_1_1:
965       case SPV_ENV_UNIVERSAL_1_2:
966       case SPV_ENV_UNIVERSAL_1_3:
967         // PeelCount and PartialCount were introduced in SPIRV 1.4, so are not
968         // valid in the context of older versions.
969         ASSERT_FALSE(
970             transformation.IsApplicable(context.get(), transformation_context));
971         break;
972       case SPV_ENV_UNIVERSAL_1_4:
973       case SPV_ENV_UNIVERSAL_1_5:
974         ASSERT_TRUE(
975             transformation.IsApplicable(context.get(), transformation_context));
976         break;
977       default:
978         assert(false && "Unhandled environment");
979         break;
980     }
981   }
982 }
983 
984 }  // namespace
985 }  // namespace fuzz
986 }  // namespace spvtools
987