• 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_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(
282                   10, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
283                   .IsApplicable(context.get(), transformation_context));
284   ASSERT_TRUE(TransformationSetLoopControl(
285                   10, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
286                   .IsApplicable(context.get(), transformation_context));
287   ASSERT_TRUE(TransformationSetLoopControl(
288                   10, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
289                   .IsApplicable(context.get(), transformation_context));
290   ASSERT_FALSE(TransformationSetLoopControl(
291                    10, (uint32_t)spv::LoopControlMask::DependencyInfinite, 0, 0)
292                    .IsApplicable(context.get(), transformation_context));
293   ASSERT_FALSE(TransformationSetLoopControl(
294                    10, (uint32_t)spv::LoopControlMask::DependencyLength, 0, 0)
295                    .IsApplicable(context.get(), transformation_context));
296   ASSERT_FALSE(TransformationSetLoopControl(
297                    10, (uint32_t)spv::LoopControlMask::MinIterations, 0, 0)
298                    .IsApplicable(context.get(), transformation_context));
299   ASSERT_FALSE(TransformationSetLoopControl(
300                    10, (uint32_t)spv::LoopControlMask::MaxIterations, 0, 0)
301                    .IsApplicable(context.get(), transformation_context));
302   ASSERT_FALSE(TransformationSetLoopControl(
303                    10, (uint32_t)spv::LoopControlMask::IterationMultiple, 0, 0)
304                    .IsApplicable(context.get(), transformation_context));
305   ASSERT_TRUE(TransformationSetLoopControl(
306                   10, (uint32_t)spv::LoopControlMask::PeelCount, 3, 0)
307                   .IsApplicable(context.get(), transformation_context));
308   ASSERT_FALSE(TransformationSetLoopControl(
309                    10, (uint32_t)spv::LoopControlMask::PeelCount, 3, 3)
310                    .IsApplicable(context.get(), transformation_context));
311   ASSERT_TRUE(TransformationSetLoopControl(
312                   10, (uint32_t)spv::LoopControlMask::PartialCount, 0, 3)
313                   .IsApplicable(context.get(), transformation_context));
314   ASSERT_FALSE(TransformationSetLoopControl(
315                    10, (uint32_t)spv::LoopControlMask::PartialCount, 3, 3)
316                    .IsApplicable(context.get(), transformation_context));
317   ASSERT_TRUE(TransformationSetLoopControl(
318                   10,
319                   (uint32_t)spv::LoopControlMask::PeelCount |
320                       (uint32_t)spv::LoopControlMask::PartialCount,
321                   3, 3)
322                   .IsApplicable(context.get(), transformation_context));
323   ASSERT_TRUE(TransformationSetLoopControl(
324                   10,
325                   (uint32_t)spv::LoopControlMask::Unroll |
326                       (uint32_t)spv::LoopControlMask::PeelCount |
327                       (uint32_t)spv::LoopControlMask::PartialCount,
328                   3, 3)
329                   .IsApplicable(context.get(), transformation_context));
330   ASSERT_FALSE(TransformationSetLoopControl(
331                    10,
332                    (uint32_t)spv::LoopControlMask::DontUnroll |
333                        (uint32_t)spv::LoopControlMask::PeelCount |
334                        (uint32_t)spv::LoopControlMask::PartialCount,
335                    3, 3)
336                    .IsApplicable(context.get(), transformation_context));
337 
338   ASSERT_TRUE(TransformationSetLoopControl(
339                   23, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
340                   .IsApplicable(context.get(), transformation_context));
341   ASSERT_TRUE(TransformationSetLoopControl(
342                   23, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
343                   .IsApplicable(context.get(), transformation_context));
344   ASSERT_TRUE(TransformationSetLoopControl(
345                   23, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
346                   .IsApplicable(context.get(), transformation_context));
347   ASSERT_TRUE(TransformationSetLoopControl(
348                   23,
349                   (uint32_t)spv::LoopControlMask::PeelCount |
350                       (uint32_t)spv::LoopControlMask::PartialCount,
351                   3, 3)
352                   .IsApplicable(context.get(), transformation_context));
353   ASSERT_FALSE(TransformationSetLoopControl(
354                    23, (uint32_t)spv::LoopControlMask::MaxIterations, 2, 3)
355                    .IsApplicable(context.get(), transformation_context));
356 
357   ASSERT_TRUE(TransformationSetLoopControl(
358                   33, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
359                   .IsApplicable(context.get(), transformation_context));
360   ASSERT_TRUE(TransformationSetLoopControl(
361                   33, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
362                   .IsApplicable(context.get(), transformation_context));
363   ASSERT_TRUE(TransformationSetLoopControl(
364                   33, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
365                   .IsApplicable(context.get(), transformation_context));
366   ASSERT_FALSE(TransformationSetLoopControl(
367                    33, (uint32_t)spv::LoopControlMask::MinIterations, 0, 0)
368                    .IsApplicable(context.get(), transformation_context));
369   ASSERT_TRUE(TransformationSetLoopControl(
370                   33,
371                   (uint32_t)spv::LoopControlMask::Unroll |
372                       (uint32_t)spv::LoopControlMask::PeelCount,
373                   5, 0)
374                   .IsApplicable(context.get(), transformation_context));
375   ASSERT_FALSE(TransformationSetLoopControl(
376                    33,
377                    (uint32_t)spv::LoopControlMask::DontUnroll |
378                        (uint32_t)spv::LoopControlMask::PartialCount,
379                    0, 10)
380                    .IsApplicable(context.get(), transformation_context));
381 
382   ASSERT_TRUE(TransformationSetLoopControl(
383                   43, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
384                   .IsApplicable(context.get(), transformation_context));
385   ASSERT_TRUE(TransformationSetLoopControl(
386                   43, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
387                   .IsApplicable(context.get(), transformation_context));
388   ASSERT_TRUE(TransformationSetLoopControl(
389                   43, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
390                   .IsApplicable(context.get(), transformation_context));
391   ASSERT_TRUE(TransformationSetLoopControl(
392                   43,
393                   (uint32_t)spv::LoopControlMask::MaskNone |
394                       (uint32_t)spv::LoopControlMask::DependencyInfinite,
395                   0, 0)
396                   .IsApplicable(context.get(), transformation_context));
397   ASSERT_TRUE(TransformationSetLoopControl(
398                   43,
399                   (uint32_t)spv::LoopControlMask::Unroll |
400                       (uint32_t)spv::LoopControlMask::DependencyInfinite,
401                   0, 0)
402                   .IsApplicable(context.get(), transformation_context));
403   ASSERT_TRUE(TransformationSetLoopControl(
404                   43,
405                   (uint32_t)spv::LoopControlMask::DontUnroll |
406                       (uint32_t)spv::LoopControlMask::DependencyInfinite,
407                   0, 0)
408                   .IsApplicable(context.get(), transformation_context));
409   ASSERT_FALSE(TransformationSetLoopControl(
410                    43,
411                    (uint32_t)spv::LoopControlMask::DependencyInfinite |
412                        (uint32_t)spv::LoopControlMask::DependencyLength,
413                    0, 0)
414                    .IsApplicable(context.get(), transformation_context));
415   ASSERT_TRUE(TransformationSetLoopControl(
416                   43,
417                   (uint32_t)spv::LoopControlMask::Unroll |
418                       (uint32_t)spv::LoopControlMask::PeelCount,
419                   5, 0)
420                   .IsApplicable(context.get(), transformation_context));
421 
422   ASSERT_TRUE(TransformationSetLoopControl(
423                   53, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
424                   .IsApplicable(context.get(), transformation_context));
425   ASSERT_TRUE(TransformationSetLoopControl(
426                   53, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
427                   .IsApplicable(context.get(), transformation_context));
428   ASSERT_TRUE(TransformationSetLoopControl(
429                   53, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
430                   .IsApplicable(context.get(), transformation_context));
431   ASSERT_FALSE(TransformationSetLoopControl(
432                    53, (uint32_t)spv::LoopControlMask::MaxIterations, 0, 0)
433                    .IsApplicable(context.get(), transformation_context));
434   ASSERT_TRUE(TransformationSetLoopControl(
435                   53,
436                   (uint32_t)spv::LoopControlMask::MaskNone |
437                       (uint32_t)spv::LoopControlMask::DependencyLength,
438                   0, 0)
439                   .IsApplicable(context.get(), transformation_context));
440   ASSERT_FALSE(TransformationSetLoopControl(
441                    53,
442                    (uint32_t)spv::LoopControlMask::Unroll |
443                        (uint32_t)spv::LoopControlMask::DependencyInfinite,
444                    0, 0)
445                    .IsApplicable(context.get(), transformation_context));
446   ASSERT_TRUE(TransformationSetLoopControl(
447                   53,
448                   (uint32_t)spv::LoopControlMask::DontUnroll |
449                       (uint32_t)spv::LoopControlMask::DependencyLength,
450                   0, 0)
451                   .IsApplicable(context.get(), transformation_context));
452   ASSERT_FALSE(TransformationSetLoopControl(
453                    53,
454                    (uint32_t)spv::LoopControlMask::DependencyInfinite |
455                        (uint32_t)spv::LoopControlMask::DependencyLength,
456                    0, 0)
457                    .IsApplicable(context.get(), transformation_context));
458   ASSERT_TRUE(TransformationSetLoopControl(
459                   53,
460                   (uint32_t)spv::LoopControlMask::Unroll |
461                       (uint32_t)spv::LoopControlMask::DependencyLength |
462                       (uint32_t)spv::LoopControlMask::PeelCount |
463                       (uint32_t)spv::LoopControlMask::PartialCount,
464                   5, 3)
465                   .IsApplicable(context.get(), transformation_context));
466 
467   ASSERT_TRUE(TransformationSetLoopControl(
468                   63, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
469                   .IsApplicable(context.get(), transformation_context));
470   ASSERT_TRUE(TransformationSetLoopControl(
471                   63, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
472                   .IsApplicable(context.get(), transformation_context));
473   ASSERT_TRUE(TransformationSetLoopControl(
474                   63, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
475                   .IsApplicable(context.get(), transformation_context));
476   ASSERT_TRUE(TransformationSetLoopControl(
477                   63,
478                   (uint32_t)spv::LoopControlMask::Unroll |
479                       (uint32_t)spv::LoopControlMask::MinIterations |
480                       (uint32_t)spv::LoopControlMask::PeelCount |
481                       (uint32_t)spv::LoopControlMask::PartialCount,
482                   5, 3)
483                   .IsApplicable(context.get(), transformation_context));
484   ASSERT_TRUE(TransformationSetLoopControl(
485                   63,
486                   (uint32_t)spv::LoopControlMask::Unroll |
487                       (uint32_t)spv::LoopControlMask::MinIterations |
488                       (uint32_t)spv::LoopControlMask::PeelCount,
489                   23, 0)
490                   .IsApplicable(context.get(), transformation_context));
491   ASSERT_FALSE(TransformationSetLoopControl(
492                    63,
493                    (uint32_t)spv::LoopControlMask::Unroll |
494                        (uint32_t)spv::LoopControlMask::MinIterations |
495                        (uint32_t)spv::LoopControlMask::PeelCount,
496                    2, 23)
497                    .IsApplicable(context.get(), transformation_context));
498 
499   ASSERT_TRUE(TransformationSetLoopControl(
500                   73, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
501                   .IsApplicable(context.get(), transformation_context));
502   ASSERT_TRUE(TransformationSetLoopControl(
503                   73, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
504                   .IsApplicable(context.get(), transformation_context));
505   ASSERT_TRUE(TransformationSetLoopControl(
506                   73, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
507                   .IsApplicable(context.get(), transformation_context));
508   ASSERT_FALSE(TransformationSetLoopControl(
509                    73,
510                    (uint32_t)spv::LoopControlMask::Unroll |
511                        (uint32_t)spv::LoopControlMask::MinIterations |
512                        (uint32_t)spv::LoopControlMask::PeelCount |
513                        (uint32_t)spv::LoopControlMask::PartialCount,
514                    5, 3)
515                    .IsApplicable(context.get(), transformation_context));
516   ASSERT_TRUE(TransformationSetLoopControl(
517                   73,
518                   (uint32_t)spv::LoopControlMask::Unroll |
519                       (uint32_t)spv::LoopControlMask::MaxIterations |
520                       (uint32_t)spv::LoopControlMask::PeelCount,
521                   23, 0)
522                   .IsApplicable(context.get(), transformation_context));
523   ASSERT_FALSE(TransformationSetLoopControl(
524                    73,
525                    (uint32_t)spv::LoopControlMask::Unroll |
526                        (uint32_t)spv::LoopControlMask::MaxIterations |
527                        (uint32_t)spv::LoopControlMask::PeelCount,
528                    2, 23)
529                    .IsApplicable(context.get(), transformation_context));
530 
531   ASSERT_TRUE(TransformationSetLoopControl(
532                   83, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
533                   .IsApplicable(context.get(), transformation_context));
534   ASSERT_TRUE(TransformationSetLoopControl(
535                   83, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
536                   .IsApplicable(context.get(), transformation_context));
537   ASSERT_TRUE(TransformationSetLoopControl(
538                   83, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
539                   .IsApplicable(context.get(), transformation_context));
540   ASSERT_FALSE(TransformationSetLoopControl(
541                    83,
542                    (uint32_t)spv::LoopControlMask::Unroll |
543                        (uint32_t)spv::LoopControlMask::MinIterations |
544                        (uint32_t)spv::LoopControlMask::PeelCount |
545                        (uint32_t)spv::LoopControlMask::PartialCount,
546                    5, 3)
547                    .IsApplicable(context.get(), transformation_context));
548   ASSERT_TRUE(TransformationSetLoopControl(
549                   83,
550                   (uint32_t)spv::LoopControlMask::Unroll |
551                       (uint32_t)spv::LoopControlMask::IterationMultiple |
552                       (uint32_t)spv::LoopControlMask::PeelCount,
553                   23, 0)
554                   .IsApplicable(context.get(), transformation_context));
555   ASSERT_FALSE(TransformationSetLoopControl(
556                    83,
557                    (uint32_t)spv::LoopControlMask::Unroll |
558                        (uint32_t)spv::LoopControlMask::IterationMultiple |
559                        (uint32_t)spv::LoopControlMask::PeelCount,
560                    2, 23)
561                    .IsApplicable(context.get(), transformation_context));
562 
563   ASSERT_TRUE(TransformationSetLoopControl(
564                   93, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
565                   .IsApplicable(context.get(), transformation_context));
566   ASSERT_TRUE(TransformationSetLoopControl(
567                   93, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
568                   .IsApplicable(context.get(), transformation_context));
569   ASSERT_TRUE(TransformationSetLoopControl(
570                   93, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
571                   .IsApplicable(context.get(), transformation_context));
572   ASSERT_TRUE(TransformationSetLoopControl(
573                   93, (uint32_t)spv::LoopControlMask::PeelCount, 8, 0)
574                   .IsApplicable(context.get(), transformation_context));
575   ASSERT_FALSE(TransformationSetLoopControl(
576                    93, (uint32_t)spv::LoopControlMask::PeelCount, 8, 8)
577                    .IsApplicable(context.get(), transformation_context));
578   ASSERT_TRUE(TransformationSetLoopControl(
579                   93, (uint32_t)spv::LoopControlMask::PartialCount, 0, 8)
580                   .IsApplicable(context.get(), transformation_context));
581   ASSERT_TRUE(TransformationSetLoopControl(
582                   93,
583                   (uint32_t)spv::LoopControlMask::PeelCount |
584                       (uint32_t)spv::LoopControlMask::PartialCount,
585                   16, 8)
586                   .IsApplicable(context.get(), transformation_context));
587 
588   ASSERT_TRUE(TransformationSetLoopControl(
589                   103, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
590                   .IsApplicable(context.get(), transformation_context));
591   ASSERT_TRUE(TransformationSetLoopControl(
592                   103, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
593                   .IsApplicable(context.get(), transformation_context));
594   ASSERT_TRUE(TransformationSetLoopControl(
595                   103, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
596                   .IsApplicable(context.get(), transformation_context));
597   ASSERT_TRUE(TransformationSetLoopControl(
598                   103, (uint32_t)spv::LoopControlMask::PartialCount, 0, 60)
599                   .IsApplicable(context.get(), transformation_context));
600   ASSERT_FALSE(TransformationSetLoopControl(
601                    103,
602                    (uint32_t)spv::LoopControlMask::DontUnroll |
603                        (uint32_t)spv::LoopControlMask::PartialCount,
604                    0, 60)
605                    .IsApplicable(context.get(), transformation_context));
606 
607   ASSERT_TRUE(TransformationSetLoopControl(
608                   113, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
609                   .IsApplicable(context.get(), transformation_context));
610   ASSERT_TRUE(TransformationSetLoopControl(
611                   113, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
612                   .IsApplicable(context.get(), transformation_context));
613   ASSERT_TRUE(TransformationSetLoopControl(
614                   113, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
615                   .IsApplicable(context.get(), transformation_context));
616   ASSERT_TRUE(TransformationSetLoopControl(
617                   113, (uint32_t)spv::LoopControlMask::PeelCount, 12, 0)
618                   .IsApplicable(context.get(), transformation_context));
619   ASSERT_FALSE(TransformationSetLoopControl(
620                    113,
621                    (uint32_t)spv::LoopControlMask::IterationMultiple |
622                        (uint32_t)spv::LoopControlMask::PeelCount,
623                    12, 0)
624                    .IsApplicable(context.get(), transformation_context));
625 
626   ASSERT_TRUE(TransformationSetLoopControl(
627                   123, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
628                   .IsApplicable(context.get(), transformation_context));
629   ASSERT_TRUE(TransformationSetLoopControl(
630                   123, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
631                   .IsApplicable(context.get(), transformation_context));
632   ASSERT_TRUE(TransformationSetLoopControl(
633                   123, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
634                   .IsApplicable(context.get(), transformation_context));
635   ASSERT_TRUE(TransformationSetLoopControl(
636                   123,
637                   (uint32_t)spv::LoopControlMask::MinIterations |
638                       (uint32_t)spv::LoopControlMask::MaxIterations |
639                       (uint32_t)spv::LoopControlMask::IterationMultiple |
640                       (uint32_t)spv::LoopControlMask::PeelCount |
641                       (uint32_t)spv::LoopControlMask::PartialCount,
642                   7, 8)
643                   .IsApplicable(context.get(), transformation_context));
644   ASSERT_TRUE(TransformationSetLoopControl(
645                   123,
646                   (uint32_t)spv::LoopControlMask::Unroll |
647                       (uint32_t)spv::LoopControlMask::MinIterations |
648                       (uint32_t)spv::LoopControlMask::MaxIterations |
649                       (uint32_t)spv::LoopControlMask::PartialCount,
650                   0, 9)
651                   .IsApplicable(context.get(), transformation_context));
652   ASSERT_FALSE(TransformationSetLoopControl(
653                    123,
654                    (uint32_t)spv::LoopControlMask::Unroll |
655                        (uint32_t)spv::LoopControlMask::MinIterations |
656                        (uint32_t)spv::LoopControlMask::MaxIterations |
657                        (uint32_t)spv::LoopControlMask::PartialCount,
658                    7, 9)
659                    .IsApplicable(context.get(), transformation_context));
660   ASSERT_FALSE(TransformationSetLoopControl(
661                    123,
662                    (uint32_t)spv::LoopControlMask::DontUnroll |
663                        (uint32_t)spv::LoopControlMask::MinIterations |
664                        (uint32_t)spv::LoopControlMask::MaxIterations |
665                        (uint32_t)spv::LoopControlMask::PartialCount,
666                    7, 9)
667                    .IsApplicable(context.get(), transformation_context));
668 
669   ApplyAndCheckFreshIds(TransformationSetLoopControl(
670                             10,
671                             (uint32_t)spv::LoopControlMask::Unroll |
672                                 (uint32_t)spv::LoopControlMask::PeelCount |
673                                 (uint32_t)spv::LoopControlMask::PartialCount,
674                             3, 3),
675                         context.get(), &transformation_context);
676   ApplyAndCheckFreshIds(
677       TransformationSetLoopControl(
678           23, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0),
679       context.get(), &transformation_context);
680   ApplyAndCheckFreshIds(TransformationSetLoopControl(
681                             33, (uint32_t)spv::LoopControlMask::Unroll, 0, 0),
682                         context.get(), &transformation_context);
683   ApplyAndCheckFreshIds(
684       TransformationSetLoopControl(
685           43,
686           (uint32_t)spv::LoopControlMask::DontUnroll |
687               (uint32_t)spv::LoopControlMask::DependencyInfinite,
688           0, 0),
689       context.get(), &transformation_context);
690   ApplyAndCheckFreshIds(TransformationSetLoopControl(
691                             53, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0),
692                         context.get(), &transformation_context);
693   ApplyAndCheckFreshIds(TransformationSetLoopControl(
694                             63,
695                             (uint32_t)spv::LoopControlMask::Unroll |
696                                 (uint32_t)spv::LoopControlMask::MinIterations |
697                                 (uint32_t)spv::LoopControlMask::PeelCount,
698                             23, 0),
699                         context.get(), &transformation_context);
700   ApplyAndCheckFreshIds(TransformationSetLoopControl(
701                             73,
702                             (uint32_t)spv::LoopControlMask::Unroll |
703                                 (uint32_t)spv::LoopControlMask::MaxIterations |
704                                 (uint32_t)spv::LoopControlMask::PeelCount,
705                             23, 0),
706                         context.get(), &transformation_context);
707   ApplyAndCheckFreshIds(
708       TransformationSetLoopControl(
709           83, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0),
710       context.get(), &transformation_context);
711   ApplyAndCheckFreshIds(TransformationSetLoopControl(
712                             93,
713                             (uint32_t)spv::LoopControlMask::PeelCount |
714                                 (uint32_t)spv::LoopControlMask::PartialCount,
715                             16, 8),
716                         context.get(), &transformation_context);
717   ApplyAndCheckFreshIds(
718       TransformationSetLoopControl(
719           103, (uint32_t)spv::LoopControlMask::PartialCount, 0, 60),
720       context.get(), &transformation_context);
721   ApplyAndCheckFreshIds(
722       TransformationSetLoopControl(
723           113, (uint32_t)spv::LoopControlMask::PeelCount, 12, 0),
724       context.get(), &transformation_context);
725   ApplyAndCheckFreshIds(TransformationSetLoopControl(
726                             123,
727                             (uint32_t)spv::LoopControlMask::Unroll |
728                                 (uint32_t)spv::LoopControlMask::MinIterations |
729                                 (uint32_t)spv::LoopControlMask::MaxIterations |
730                                 (uint32_t)spv::LoopControlMask::PartialCount,
731                             0, 9),
732                         context.get(), &transformation_context);
733 
734   std::string after_transformation = R"(
735                OpCapability Shader
736           %1 = OpExtInstImport "GLSL.std.450"
737                OpMemoryModel Logical GLSL450
738                OpEntryPoint Fragment %4 "main"
739                OpExecutionMode %4 OriginUpperLeft
740                OpSource ESSL 310
741                OpName %4 "main"
742           %2 = OpTypeVoid
743           %3 = OpTypeFunction %2
744           %6 = OpTypeInt 32 1
745           %7 = OpTypePointer Function %6
746           %9 = OpConstant %6 0
747          %16 = OpConstant %6 100
748          %17 = OpTypeBool
749          %20 = OpConstant %6 1
750           %4 = OpFunction %2 None %3
751           %5 = OpLabel
752           %8 = OpVariable %7 Function
753          %22 = OpVariable %7 Function
754          %32 = OpVariable %7 Function
755          %42 = OpVariable %7 Function
756          %52 = OpVariable %7 Function
757          %62 = OpVariable %7 Function
758          %72 = OpVariable %7 Function
759          %82 = OpVariable %7 Function
760          %92 = OpVariable %7 Function
761         %102 = OpVariable %7 Function
762         %112 = OpVariable %7 Function
763         %122 = OpVariable %7 Function
764                OpStore %8 %9
765                OpBranch %10
766          %10 = OpLabel
767         %132 = OpPhi %6 %9 %5 %21 %13
768                OpLoopMerge %12 %13 Unroll|PeelCount|PartialCount 3 3
769                OpBranch %14
770          %14 = OpLabel
771          %18 = OpSLessThan %17 %132 %16
772                OpBranchConditional %18 %11 %12
773          %11 = OpLabel
774                OpBranch %13
775          %13 = OpLabel
776          %21 = OpIAdd %6 %132 %20
777                OpStore %8 %21
778                OpBranch %10
779          %12 = OpLabel
780                OpStore %22 %9
781                OpBranch %23
782          %23 = OpLabel
783         %133 = OpPhi %6 %9 %12 %31 %26
784                OpLoopMerge %25 %26 DontUnroll
785                OpBranch %27
786          %27 = OpLabel
787          %29 = OpSLessThan %17 %133 %16
788                OpBranchConditional %29 %24 %25
789          %24 = OpLabel
790                OpBranch %26
791          %26 = OpLabel
792          %31 = OpIAdd %6 %133 %20
793                OpStore %22 %31
794                OpBranch %23
795          %25 = OpLabel
796                OpStore %32 %9
797                OpBranch %33
798          %33 = OpLabel
799         %134 = OpPhi %6 %9 %25 %41 %36
800                OpLoopMerge %35 %36 Unroll
801                OpBranch %37
802          %37 = OpLabel
803          %39 = OpSLessThan %17 %134 %16
804                OpBranchConditional %39 %34 %35
805          %34 = OpLabel
806                OpBranch %36
807          %36 = OpLabel
808          %41 = OpIAdd %6 %134 %20
809                OpStore %32 %41
810                OpBranch %33
811          %35 = OpLabel
812                OpStore %42 %9
813                OpBranch %43
814          %43 = OpLabel
815         %135 = OpPhi %6 %9 %35 %51 %46
816                OpLoopMerge %45 %46 DontUnroll|DependencyInfinite
817                OpBranch %47
818          %47 = OpLabel
819          %49 = OpSLessThan %17 %135 %16
820                OpBranchConditional %49 %44 %45
821          %44 = OpLabel
822                OpBranch %46
823          %46 = OpLabel
824          %51 = OpIAdd %6 %135 %20
825                OpStore %42 %51
826                OpBranch %43
827          %45 = OpLabel
828                OpStore %52 %9
829                OpBranch %53
830          %53 = OpLabel
831         %136 = OpPhi %6 %9 %45 %61 %56
832                OpLoopMerge %55 %56 None
833                OpBranch %57
834          %57 = OpLabel
835          %59 = OpSLessThan %17 %136 %16
836                OpBranchConditional %59 %54 %55
837          %54 = OpLabel
838                OpBranch %56
839          %56 = OpLabel
840          %61 = OpIAdd %6 %136 %20
841                OpStore %52 %61
842                OpBranch %53
843          %55 = OpLabel
844                OpStore %62 %9
845                OpBranch %63
846          %63 = OpLabel
847         %137 = OpPhi %6 %9 %55 %71 %66
848                OpLoopMerge %65 %66 Unroll|MinIterations|PeelCount 10 23
849                OpBranch %67
850          %67 = OpLabel
851          %69 = OpSLessThan %17 %137 %16
852                OpBranchConditional %69 %64 %65
853          %64 = OpLabel
854                OpBranch %66
855          %66 = OpLabel
856          %71 = OpIAdd %6 %137 %20
857                OpStore %62 %71
858                OpBranch %63
859          %65 = OpLabel
860                OpStore %72 %9
861                OpBranch %73
862          %73 = OpLabel
863         %138 = OpPhi %6 %9 %65 %81 %76
864                OpLoopMerge %75 %76 Unroll|MaxIterations|PeelCount 50 23
865                OpBranch %77
866          %77 = OpLabel
867          %79 = OpSLessThan %17 %138 %16
868                OpBranchConditional %79 %74 %75
869          %74 = OpLabel
870                OpBranch %76
871          %76 = OpLabel
872          %81 = OpIAdd %6 %138 %20
873                OpStore %72 %81
874                OpBranch %73
875          %75 = OpLabel
876                OpStore %82 %9
877                OpBranch %83
878          %83 = OpLabel
879         %139 = OpPhi %6 %9 %75 %91 %86
880                OpLoopMerge %85 %86 DontUnroll
881                OpBranch %87
882          %87 = OpLabel
883          %89 = OpSLessThan %17 %139 %16
884                OpBranchConditional %89 %84 %85
885          %84 = OpLabel
886                OpBranch %86
887          %86 = OpLabel
888          %91 = OpIAdd %6 %139 %20
889                OpStore %82 %91
890                OpBranch %83
891          %85 = OpLabel
892                OpStore %92 %9
893                OpBranch %93
894          %93 = OpLabel
895         %140 = OpPhi %6 %9 %85 %101 %96
896                OpLoopMerge %95 %96 PeelCount|PartialCount 16 8
897                OpBranch %97
898          %97 = OpLabel
899          %99 = OpSLessThan %17 %140 %16
900                OpBranchConditional %99 %94 %95
901          %94 = OpLabel
902                OpBranch %96
903          %96 = OpLabel
904         %101 = OpIAdd %6 %140 %20
905                OpStore %92 %101
906                OpBranch %93
907          %95 = OpLabel
908                OpStore %102 %9
909                OpBranch %103
910         %103 = OpLabel
911         %141 = OpPhi %6 %9 %95 %111 %106
912                OpLoopMerge %105 %106 PartialCount 60
913                OpBranch %107
914         %107 = OpLabel
915         %109 = OpSLessThan %17 %141 %16
916                OpBranchConditional %109 %104 %105
917         %104 = OpLabel
918                OpBranch %106
919         %106 = OpLabel
920         %111 = OpIAdd %6 %141 %20
921                OpStore %102 %111
922                OpBranch %103
923         %105 = OpLabel
924                OpStore %112 %9
925                OpBranch %113
926         %113 = OpLabel
927         %142 = OpPhi %6 %9 %105 %121 %116
928                OpLoopMerge %115 %116 PeelCount 12
929                OpBranch %117
930         %117 = OpLabel
931         %119 = OpSLessThan %17 %142 %16
932                OpBranchConditional %119 %114 %115
933         %114 = OpLabel
934                OpBranch %116
935         %116 = OpLabel
936         %121 = OpIAdd %6 %142 %20
937                OpStore %112 %121
938                OpBranch %113
939         %115 = OpLabel
940                OpStore %122 %9
941                OpBranch %123
942         %123 = OpLabel
943         %143 = OpPhi %6 %9 %115 %131 %126
944                OpLoopMerge %125 %126 Unroll|MinIterations|MaxIterations|PartialCount 5 90 9
945                OpBranch %127
946         %127 = OpLabel
947         %129 = OpSLessThan %17 %143 %16
948                OpBranchConditional %129 %124 %125
949         %124 = OpLabel
950                OpBranch %126
951         %126 = OpLabel
952         %131 = OpIAdd %6 %143 %20
953                OpStore %122 %131
954                OpBranch %123
955         %125 = OpLabel
956                OpReturn
957                OpFunctionEnd
958   )";
959   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
960 }
961 
TEST(TransformationSetLoopControlTest,CheckSPIRVVersionsRespected)962 TEST(TransformationSetLoopControlTest, CheckSPIRVVersionsRespected) {
963   // This test checks that we do not allow introducing PeelCount and
964   // PartialCount loop controls if the SPIR-V version being used does not
965   // support them.
966 
967   std::string shader = R"(
968                OpCapability Shader
969           %1 = OpExtInstImport "GLSL.std.450"
970                OpMemoryModel Logical GLSL450
971                OpEntryPoint Fragment %4 "main"
972                OpExecutionMode %4 OriginUpperLeft
973                OpSource ESSL 310
974                OpName %4 "main"
975                OpName %8 "i"
976           %2 = OpTypeVoid
977           %3 = OpTypeFunction %2
978           %6 = OpTypeInt 32 1
979           %7 = OpTypePointer Function %6
980           %9 = OpConstant %6 0
981          %16 = OpConstant %6 10
982          %17 = OpTypeBool
983          %20 = OpConstant %6 1
984           %4 = OpFunction %2 None %3
985           %5 = OpLabel
986           %8 = OpVariable %7 Function
987                OpStore %8 %9
988                OpBranch %10
989          %10 = OpLabel
990                OpLoopMerge %12 %13 None
991                OpBranch %14
992          %14 = OpLabel
993          %15 = OpLoad %6 %8
994          %18 = OpSLessThan %17 %15 %16
995                OpBranchConditional %18 %11 %12
996          %11 = OpLabel
997                OpBranch %13
998          %13 = OpLabel
999          %19 = OpLoad %6 %8
1000          %21 = OpIAdd %6 %19 %20
1001                OpStore %8 %21
1002                OpBranch %10
1003          %12 = OpLabel
1004                OpReturn
1005                OpFunctionEnd
1006   )";
1007 
1008   for (auto env :
1009        {SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2,
1010         SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5,
1011         SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_1_SPIRV_1_4,
1012         SPV_ENV_VULKAN_1_2}) {
1013     const auto consumer = nullptr;
1014     const auto context =
1015         BuildModule(env, consumer, shader, kFuzzAssembleOption);
1016     spvtools::ValidatorOptions validator_options;
1017     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1018         context.get(), validator_options, kConsoleMessageConsumer));
1019     TransformationContext transformation_context(
1020         MakeUnique<FactManager>(context.get()), validator_options);
1021     TransformationSetLoopControl peel_count(
1022         10, (uint32_t)spv::LoopControlMask::PeelCount, 4, 0);
1023     TransformationSetLoopControl partial_count(
1024         10, (uint32_t)spv::LoopControlMask::PartialCount, 0, 4);
1025 
1026     switch (env) {
1027       case SPV_ENV_UNIVERSAL_1_0:
1028       case SPV_ENV_UNIVERSAL_1_1:
1029       case SPV_ENV_UNIVERSAL_1_2:
1030       case SPV_ENV_UNIVERSAL_1_3:
1031       case SPV_ENV_VULKAN_1_0:
1032       case SPV_ENV_VULKAN_1_1:
1033         // PeelCount and PartialCount were introduced in SPIRV 1.4, so are not
1034         // valid in the context of older versions.
1035         ASSERT_FALSE(
1036             peel_count.IsApplicable(context.get(), transformation_context));
1037         ASSERT_FALSE(
1038             partial_count.IsApplicable(context.get(), transformation_context));
1039         break;
1040       case SPV_ENV_UNIVERSAL_1_4:
1041       case SPV_ENV_UNIVERSAL_1_5:
1042       case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
1043       case SPV_ENV_VULKAN_1_2:
1044         ASSERT_TRUE(
1045             peel_count.IsApplicable(context.get(), transformation_context));
1046         ASSERT_TRUE(
1047             partial_count.IsApplicable(context.get(), transformation_context));
1048         break;
1049       default:
1050         assert(false && "Unhandled environment");
1051         break;
1052     }
1053   }
1054 }
1055 
1056 }  // namespace
1057 }  // namespace fuzz
1058 }  // namespace spvtools
1059