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/fuzzer.h"
16 #include "source/fuzz/shrinker.h"
17 
18 #include <functional>
19 #include <vector>
20 
21 #include "gtest/gtest.h"
22 #include "source/fuzz/fuzzer_util.h"
23 #include "source/fuzz/pseudo_random_generator.h"
24 #include "source/fuzz/uniform_buffer_element_descriptor.h"
25 #include "test/fuzz/fuzz_test_util.h"
26 
27 namespace spvtools {
28 namespace fuzz {
29 namespace {
30 
31 // The following SPIR-V came from this GLSL:
32 //
33 // #version 310 es
34 //
35 // void foo() {
36 //   int x;
37 //   x = 2;
38 //   for (int i = 0; i < 100; i++) {
39 //     x += i;
40 //     x = x * 2;
41 //   }
42 //   return;
43 // }
44 //
45 // void main() {
46 //   foo();
47 //   for (int i = 0; i < 10; i++) {
48 //     int j = 20;
49 //     while(j > 0) {
50 //       foo();
51 //       j--;
52 //     }
53 //     do {
54 //       i++;
55 //     } while(i < 4);
56 //   }
57 // }
58 
59 const std::string kTestShader1 = R"(
60                OpCapability Shader
61           %1 = OpExtInstImport "GLSL.std.450"
62                OpMemoryModel Logical GLSL450
63                OpEntryPoint Fragment %4 "main"
64                OpExecutionMode %4 OriginUpperLeft
65                OpSource ESSL 310
66                OpName %4 "main"
67                OpName %6 "foo("
68                OpName %10 "x"
69                OpName %12 "i"
70                OpName %33 "i"
71                OpName %42 "j"
72                OpDecorate %10 RelaxedPrecision
73                OpDecorate %12 RelaxedPrecision
74                OpDecorate %19 RelaxedPrecision
75                OpDecorate %23 RelaxedPrecision
76                OpDecorate %24 RelaxedPrecision
77                OpDecorate %25 RelaxedPrecision
78                OpDecorate %26 RelaxedPrecision
79                OpDecorate %27 RelaxedPrecision
80                OpDecorate %28 RelaxedPrecision
81                OpDecorate %30 RelaxedPrecision
82                OpDecorate %33 RelaxedPrecision
83                OpDecorate %39 RelaxedPrecision
84                OpDecorate %42 RelaxedPrecision
85                OpDecorate %49 RelaxedPrecision
86                OpDecorate %52 RelaxedPrecision
87                OpDecorate %53 RelaxedPrecision
88                OpDecorate %58 RelaxedPrecision
89                OpDecorate %59 RelaxedPrecision
90                OpDecorate %60 RelaxedPrecision
91                OpDecorate %63 RelaxedPrecision
92                OpDecorate %64 RelaxedPrecision
93           %2 = OpTypeVoid
94           %3 = OpTypeFunction %2
95           %8 = OpTypeInt 32 1
96           %9 = OpTypePointer Function %8
97          %11 = OpConstant %8 2
98          %13 = OpConstant %8 0
99          %20 = OpConstant %8 100
100          %21 = OpTypeBool
101          %29 = OpConstant %8 1
102          %40 = OpConstant %8 10
103          %43 = OpConstant %8 20
104          %61 = OpConstant %8 4
105           %4 = OpFunction %2 None %3
106           %5 = OpLabel
107          %33 = OpVariable %9 Function
108          %42 = OpVariable %9 Function
109          %32 = OpFunctionCall %2 %6
110                OpStore %33 %13
111                OpBranch %34
112          %34 = OpLabel
113                OpLoopMerge %36 %37 None
114                OpBranch %38
115          %38 = OpLabel
116          %39 = OpLoad %8 %33
117          %41 = OpSLessThan %21 %39 %40
118                OpBranchConditional %41 %35 %36
119          %35 = OpLabel
120                OpStore %42 %43
121                OpBranch %44
122          %44 = OpLabel
123                OpLoopMerge %46 %47 None
124                OpBranch %48
125          %48 = OpLabel
126          %49 = OpLoad %8 %42
127          %50 = OpSGreaterThan %21 %49 %13
128                OpBranchConditional %50 %45 %46
129          %45 = OpLabel
130          %51 = OpFunctionCall %2 %6
131          %52 = OpLoad %8 %42
132          %53 = OpISub %8 %52 %29
133                OpStore %42 %53
134                OpBranch %47
135          %47 = OpLabel
136                OpBranch %44
137          %46 = OpLabel
138                OpBranch %54
139          %54 = OpLabel
140                OpLoopMerge %56 %57 None
141                OpBranch %55
142          %55 = OpLabel
143          %58 = OpLoad %8 %33
144          %59 = OpIAdd %8 %58 %29
145                OpStore %33 %59
146                OpBranch %57
147          %57 = OpLabel
148          %60 = OpLoad %8 %33
149          %62 = OpSLessThan %21 %60 %61
150                OpBranchConditional %62 %54 %56
151          %56 = OpLabel
152                OpBranch %37
153          %37 = OpLabel
154          %63 = OpLoad %8 %33
155          %64 = OpIAdd %8 %63 %29
156                OpStore %33 %64
157                OpBranch %34
158          %36 = OpLabel
159                OpReturn
160                OpFunctionEnd
161           %6 = OpFunction %2 None %3
162           %7 = OpLabel
163          %10 = OpVariable %9 Function
164          %12 = OpVariable %9 Function
165                OpStore %10 %11
166                OpStore %12 %13
167                OpBranch %14
168          %14 = OpLabel
169                OpLoopMerge %16 %17 None
170                OpBranch %18
171          %18 = OpLabel
172          %19 = OpLoad %8 %12
173          %22 = OpSLessThan %21 %19 %20
174                OpBranchConditional %22 %15 %16
175          %15 = OpLabel
176          %23 = OpLoad %8 %12
177          %24 = OpLoad %8 %10
178          %25 = OpIAdd %8 %24 %23
179                OpStore %10 %25
180          %26 = OpLoad %8 %10
181          %27 = OpIMul %8 %26 %11
182                OpStore %10 %27
183                OpBranch %17
184          %17 = OpLabel
185          %28 = OpLoad %8 %12
186          %30 = OpIAdd %8 %28 %29
187                OpStore %12 %30
188                OpBranch %14
189          %16 = OpLabel
190                OpReturn
191                OpFunctionEnd
192 
193   )";
194 
195 // The following SPIR-V came from this GLSL, which was then optimized using
196 // spirv-opt with the -O argument:
197 //
198 // #version 310 es
199 //
200 // precision highp float;
201 //
202 // layout(location = 0) out vec4 _GLF_color;
203 //
204 // layout(set = 0, binding = 0) uniform buf0 {
205 //  vec2 injectionSwitch;
206 // };
207 // layout(set = 0, binding = 1) uniform buf1 {
208 //  vec2 resolution;
209 // };
210 // bool checkSwap(float a, float b)
211 // {
212 //  return gl_FragCoord.y < resolution.y / 2.0 ? a > b : a < b;
213 // }
214 // void main()
215 // {
216 //  float data[10];
217 //  for(int i = 0; i < 10; i++)
218 //   {
219 //    data[i] = float(10 - i) * injectionSwitch.y;
220 //   }
221 //  for(int i = 0; i < 9; i++)
222 //   {
223 //    for(int j = 0; j < 10; j++)
224 //     {
225 //      if(j < i + 1)
226 //       {
227 //        continue;
228 //       }
229 //      bool doSwap = checkSwap(data[i], data[j]);
230 //      if(doSwap)
231 //       {
232 //        float temp = data[i];
233 //        data[i] = data[j];
234 //        data[j] = temp;
235 //       }
236 //     }
237 //   }
238 //  if(gl_FragCoord.x < resolution.x / 2.0)
239 //   {
240 //    _GLF_color = vec4(data[0] / 10.0, data[5] / 10.0, data[9] / 10.0, 1.0);
241 //   }
242 //  else
243 //   {
244 //    _GLF_color = vec4(data[5] / 10.0, data[9] / 10.0, data[0] / 10.0, 1.0);
245 //   }
246 // }
247 
248 const std::string kTestShader2 = R"(
249                OpCapability Shader
250           %1 = OpExtInstImport "GLSL.std.450"
251                OpMemoryModel Logical GLSL450
252                OpEntryPoint Fragment %4 "main" %16 %139 %25 %68
253                OpExecutionMode %4 OriginUpperLeft
254                OpSource ESSL 310
255                OpName %4 "main"
256                OpName %16 "gl_FragCoord"
257                OpName %23 "buf1"
258                OpMemberName %23 0 "resolution"
259                OpName %25 ""
260                OpName %61 "data"
261                OpName %66 "buf0"
262                OpMemberName %66 0 "injectionSwitch"
263                OpName %68 ""
264                OpName %139 "_GLF_color"
265                OpDecorate %16 BuiltIn FragCoord
266                OpMemberDecorate %23 0 Offset 0
267                OpDecorate %23 Block
268                OpDecorate %25 DescriptorSet 0
269                OpDecorate %25 Binding 1
270                OpDecorate %64 RelaxedPrecision
271                OpMemberDecorate %66 0 Offset 0
272                OpDecorate %66 Block
273                OpDecorate %68 DescriptorSet 0
274                OpDecorate %68 Binding 0
275                OpDecorate %75 RelaxedPrecision
276                OpDecorate %95 RelaxedPrecision
277                OpDecorate %126 RelaxedPrecision
278                OpDecorate %128 RelaxedPrecision
279                OpDecorate %139 Location 0
280                OpDecorate %182 RelaxedPrecision
281                OpDecorate %183 RelaxedPrecision
282                OpDecorate %184 RelaxedPrecision
283           %2 = OpTypeVoid
284           %3 = OpTypeFunction %2
285           %6 = OpTypeFloat 32
286           %7 = OpTypePointer Function %6
287           %8 = OpTypeBool
288          %14 = OpTypeVector %6 4
289          %15 = OpTypePointer Input %14
290          %16 = OpVariable %15 Input
291          %17 = OpTypeInt 32 0
292          %18 = OpConstant %17 1
293          %19 = OpTypePointer Input %6
294          %22 = OpTypeVector %6 2
295          %23 = OpTypeStruct %22
296          %24 = OpTypePointer Uniform %23
297          %25 = OpVariable %24 Uniform
298          %26 = OpTypeInt 32 1
299          %27 = OpConstant %26 0
300          %28 = OpTypePointer Uniform %6
301          %56 = OpConstant %26 10
302          %58 = OpConstant %17 10
303          %59 = OpTypeArray %6 %58
304          %60 = OpTypePointer Function %59
305          %66 = OpTypeStruct %22
306          %67 = OpTypePointer Uniform %66
307          %68 = OpVariable %67 Uniform
308          %74 = OpConstant %26 1
309          %83 = OpConstant %26 9
310         %129 = OpConstant %17 0
311         %138 = OpTypePointer Output %14
312         %139 = OpVariable %138 Output
313         %144 = OpConstant %26 5
314         %151 = OpConstant %6 1
315         %194 = OpConstant %6 0.5
316         %195 = OpConstant %6 0.100000001
317           %4 = OpFunction %2 None %3
318           %5 = OpLabel
319          %61 = OpVariable %60 Function
320                OpBranch %50
321          %50 = OpLabel
322         %182 = OpPhi %26 %27 %5 %75 %51
323          %57 = OpSLessThan %8 %182 %56
324                OpLoopMerge %52 %51 None
325                OpBranchConditional %57 %51 %52
326          %51 = OpLabel
327          %64 = OpISub %26 %56 %182
328          %65 = OpConvertSToF %6 %64
329          %69 = OpAccessChain %28 %68 %27 %18
330          %70 = OpLoad %6 %69
331          %71 = OpFMul %6 %65 %70
332          %72 = OpAccessChain %7 %61 %182
333                OpStore %72 %71
334          %75 = OpIAdd %26 %182 %74
335                OpBranch %50
336          %52 = OpLabel
337                OpBranch %77
338          %77 = OpLabel
339         %183 = OpPhi %26 %27 %52 %128 %88
340          %84 = OpSLessThan %8 %183 %83
341                OpLoopMerge %79 %88 None
342                OpBranchConditional %84 %78 %79
343          %78 = OpLabel
344                OpBranch %86
345          %86 = OpLabel
346         %184 = OpPhi %26 %27 %78 %126 %89
347          %92 = OpSLessThan %8 %184 %56
348                OpLoopMerge %1000 %89 None
349                OpBranchConditional %92 %87 %1000
350          %87 = OpLabel
351          %95 = OpIAdd %26 %183 %74
352          %96 = OpSLessThan %8 %184 %95
353                OpSelectionMerge %98 None
354                OpBranchConditional %96 %97 %98
355          %97 = OpLabel
356                OpBranch %89
357          %98 = OpLabel
358         %104 = OpAccessChain %7 %61 %183
359         %105 = OpLoad %6 %104
360         %107 = OpAccessChain %7 %61 %184
361         %108 = OpLoad %6 %107
362         %166 = OpAccessChain %19 %16 %18
363         %167 = OpLoad %6 %166
364         %168 = OpAccessChain %28 %25 %27 %18
365         %169 = OpLoad %6 %168
366         %170 = OpFMul %6 %169 %194
367         %171 = OpFOrdLessThan %8 %167 %170
368                OpSelectionMerge %172 None
369                OpBranchConditional %171 %173 %174
370         %173 = OpLabel
371         %177 = OpFOrdGreaterThan %8 %105 %108
372                OpBranch %172
373         %174 = OpLabel
374         %180 = OpFOrdLessThan %8 %105 %108
375                OpBranch %172
376         %172 = OpLabel
377         %186 = OpPhi %8 %177 %173 %180 %174
378                OpSelectionMerge %112 None
379                OpBranchConditional %186 %111 %112
380         %111 = OpLabel
381         %116 = OpLoad %6 %104
382         %120 = OpLoad %6 %107
383                OpStore %104 %120
384                OpStore %107 %116
385                OpBranch %112
386         %112 = OpLabel
387                OpBranch %89
388          %89 = OpLabel
389         %126 = OpIAdd %26 %184 %74
390                OpBranch %86
391        %1000 = OpLabel
392                OpBranch %88
393          %88 = OpLabel
394         %128 = OpIAdd %26 %183 %74
395                OpBranch %77
396          %79 = OpLabel
397         %130 = OpAccessChain %19 %16 %129
398         %131 = OpLoad %6 %130
399         %132 = OpAccessChain %28 %25 %27 %129
400         %133 = OpLoad %6 %132
401         %134 = OpFMul %6 %133 %194
402         %135 = OpFOrdLessThan %8 %131 %134
403                OpSelectionMerge %137 None
404                OpBranchConditional %135 %136 %153
405         %136 = OpLabel
406         %140 = OpAccessChain %7 %61 %27
407         %141 = OpLoad %6 %140
408         %143 = OpFMul %6 %141 %195
409         %145 = OpAccessChain %7 %61 %144
410         %146 = OpLoad %6 %145
411         %147 = OpFMul %6 %146 %195
412         %148 = OpAccessChain %7 %61 %83
413         %149 = OpLoad %6 %148
414         %150 = OpFMul %6 %149 %195
415         %152 = OpCompositeConstruct %14 %143 %147 %150 %151
416                OpStore %139 %152
417                OpBranch %137
418         %153 = OpLabel
419         %154 = OpAccessChain %7 %61 %144
420         %155 = OpLoad %6 %154
421         %156 = OpFMul %6 %155 %195
422         %157 = OpAccessChain %7 %61 %83
423         %158 = OpLoad %6 %157
424         %159 = OpFMul %6 %158 %195
425         %160 = OpAccessChain %7 %61 %27
426         %161 = OpLoad %6 %160
427         %162 = OpFMul %6 %161 %195
428         %163 = OpCompositeConstruct %14 %156 %159 %162 %151
429                OpStore %139 %163
430                OpBranch %137
431         %137 = OpLabel
432                OpReturn
433                OpFunctionEnd
434   )";
435 
436 // The following SPIR-V came from this GLSL, which was then optimized using
437 // spirv-opt with the -O argument:
438 //
439 // #version 310 es
440 //
441 // precision highp float;
442 //
443 // layout(location = 0) out vec4 _GLF_color;
444 //
445 // layout(set = 0, binding = 0) uniform buf0 {
446 //  vec2 resolution;
447 // };
448 // void main(void)
449 // {
450 //  float A[50];
451 //  for(
452 //      int i = 0;
453 //      i < 200;
454 //      i ++
455 //  )
456 //   {
457 //    if(i >= int(resolution.x))
458 //     {
459 //      break;
460 //     }
461 //    if((4 * (i / 4)) == i)
462 //     {
463 //      A[i / 4] = float(i);
464 //     }
465 //   }
466 //  for(
467 //      int i = 0;
468 //      i < 50;
469 //      i ++
470 //  )
471 //   {
472 //    if(i < int(gl_FragCoord.x))
473 //     {
474 //      break;
475 //     }
476 //    if(i > 0)
477 //     {
478 //      A[i] += A[i - 1];
479 //     }
480 //   }
481 //  if(int(gl_FragCoord.x) < 20)
482 //   {
483 //    _GLF_color = vec4(A[0] / resolution.x, A[4] / resolution.y, 1.0, 1.0);
484 //   }
485 //  else
486 //   if(int(gl_FragCoord.x) < 40)
487 //    {
488 //     _GLF_color = vec4(A[5] / resolution.x, A[9] / resolution.y, 1.0, 1.0);
489 //    }
490 //   else
491 //    if(int(gl_FragCoord.x) < 60)
492 //     {
493 //      _GLF_color = vec4(A[10] / resolution.x, A[14] / resolution.y,
494 //      1.0, 1.0);
495 //     }
496 //    else
497 //     if(int(gl_FragCoord.x) < 80)
498 //      {
499 //       _GLF_color = vec4(A[15] / resolution.x, A[19] / resolution.y,
500 //       1.0, 1.0);
501 //      }
502 //     else
503 //      if(int(gl_FragCoord.x) < 100)
504 //       {
505 //        _GLF_color = vec4(A[20] / resolution.x, A[24] / resolution.y,
506 //        1.0, 1.0);
507 //       }
508 //      else
509 //       if(int(gl_FragCoord.x) < 120)
510 //        {
511 //         _GLF_color = vec4(A[25] / resolution.x, A[29] / resolution.y,
512 //         1.0, 1.0);
513 //        }
514 //       else
515 //        if(int(gl_FragCoord.x) < 140)
516 //         {
517 //          _GLF_color = vec4(A[30] / resolution.x, A[34] / resolution.y,
518 //          1.0, 1.0);
519 //         }
520 //        else
521 //         if(int(gl_FragCoord.x) < 160)
522 //          {
523 //           _GLF_color = vec4(A[35] / resolution.x, A[39] /
524 //           resolution.y, 1.0, 1.0);
525 //          }
526 //         else
527 //          if(int(gl_FragCoord.x) < 180)
528 //           {
529 //            _GLF_color = vec4(A[40] / resolution.x, A[44] /
530 //            resolution.y, 1.0, 1.0);
531 //           }
532 //          else
533 //           if(int(gl_FragCoord.x) < 180)
534 //            {
535 //             _GLF_color = vec4(A[45] / resolution.x, A[49] /
536 //             resolution.y, 1.0, 1.0);
537 //            }
538 //           else
539 //            {
540 //             discard;
541 //            }
542 // }
543 
544 const std::string kTestShader3 = R"(
545                OpCapability Shader
546           %1 = OpExtInstImport "GLSL.std.450"
547                OpMemoryModel Logical GLSL450
548                OpEntryPoint Fragment %4 "main" %68 %100 %24
549                OpExecutionMode %4 OriginUpperLeft
550                OpSource ESSL 310
551                OpName %4 "main"
552                OpName %22 "buf0"
553                OpMemberName %22 0 "resolution"
554                OpName %24 ""
555                OpName %46 "A"
556                OpName %68 "gl_FragCoord"
557                OpName %100 "_GLF_color"
558                OpMemberDecorate %22 0 Offset 0
559                OpDecorate %22 Block
560                OpDecorate %24 DescriptorSet 0
561                OpDecorate %24 Binding 0
562                OpDecorate %37 RelaxedPrecision
563                OpDecorate %38 RelaxedPrecision
564                OpDecorate %55 RelaxedPrecision
565                OpDecorate %68 BuiltIn FragCoord
566                OpDecorate %83 RelaxedPrecision
567                OpDecorate %91 RelaxedPrecision
568                OpDecorate %100 Location 0
569                OpDecorate %302 RelaxedPrecision
570                OpDecorate %304 RelaxedPrecision
571           %2 = OpTypeVoid
572           %3 = OpTypeFunction %2
573           %6 = OpTypeInt 32 1
574           %9 = OpConstant %6 0
575          %16 = OpConstant %6 200
576          %17 = OpTypeBool
577          %20 = OpTypeFloat 32
578          %21 = OpTypeVector %20 2
579          %22 = OpTypeStruct %21
580          %23 = OpTypePointer Uniform %22
581          %24 = OpVariable %23 Uniform
582          %25 = OpTypeInt 32 0
583          %26 = OpConstant %25 0
584          %27 = OpTypePointer Uniform %20
585          %35 = OpConstant %6 4
586          %43 = OpConstant %25 50
587          %44 = OpTypeArray %20 %43
588          %45 = OpTypePointer Function %44
589          %51 = OpTypePointer Function %20
590          %54 = OpConstant %6 1
591          %63 = OpConstant %6 50
592          %66 = OpTypeVector %20 4
593          %67 = OpTypePointer Input %66
594          %68 = OpVariable %67 Input
595          %69 = OpTypePointer Input %20
596          %95 = OpConstant %6 20
597          %99 = OpTypePointer Output %66
598         %100 = OpVariable %99 Output
599         %108 = OpConstant %25 1
600         %112 = OpConstant %20 1
601         %118 = OpConstant %6 40
602         %122 = OpConstant %6 5
603         %128 = OpConstant %6 9
604         %139 = OpConstant %6 60
605         %143 = OpConstant %6 10
606         %149 = OpConstant %6 14
607         %160 = OpConstant %6 80
608         %164 = OpConstant %6 15
609         %170 = OpConstant %6 19
610         %181 = OpConstant %6 100
611         %190 = OpConstant %6 24
612         %201 = OpConstant %6 120
613         %205 = OpConstant %6 25
614         %211 = OpConstant %6 29
615         %222 = OpConstant %6 140
616         %226 = OpConstant %6 30
617         %232 = OpConstant %6 34
618         %243 = OpConstant %6 160
619         %247 = OpConstant %6 35
620         %253 = OpConstant %6 39
621         %264 = OpConstant %6 180
622         %273 = OpConstant %6 44
623         %287 = OpConstant %6 45
624         %293 = OpConstant %6 49
625           %4 = OpFunction %2 None %3
626           %5 = OpLabel
627          %46 = OpVariable %45 Function
628                OpBranch %10
629          %10 = OpLabel
630         %302 = OpPhi %6 %9 %5 %55 %42
631          %18 = OpSLessThan %17 %302 %16
632                OpLoopMerge %12 %42 None
633                OpBranchConditional %18 %11 %12
634          %11 = OpLabel
635          %28 = OpAccessChain %27 %24 %9 %26
636          %29 = OpLoad %20 %28
637          %30 = OpConvertFToS %6 %29
638          %31 = OpSGreaterThanEqual %17 %302 %30
639                OpSelectionMerge %33 None
640                OpBranchConditional %31 %32 %33
641          %32 = OpLabel
642                OpBranch %12
643          %33 = OpLabel
644          %37 = OpSDiv %6 %302 %35
645          %38 = OpIMul %6 %35 %37
646          %40 = OpIEqual %17 %38 %302
647                OpBranchConditional %40 %41 %42
648          %41 = OpLabel
649          %50 = OpConvertSToF %20 %302
650          %52 = OpAccessChain %51 %46 %37
651                OpStore %52 %50
652                OpBranch %42
653          %42 = OpLabel
654          %55 = OpIAdd %6 %302 %54
655                OpBranch %10
656          %12 = OpLabel
657                OpBranch %57
658          %57 = OpLabel
659         %304 = OpPhi %6 %9 %12 %91 %80
660          %64 = OpSLessThan %17 %304 %63
661                OpLoopMerge %59 %80 None
662                OpBranchConditional %64 %58 %59
663          %58 = OpLabel
664          %70 = OpAccessChain %69 %68 %26
665          %71 = OpLoad %20 %70
666          %72 = OpConvertFToS %6 %71
667          %73 = OpSLessThan %17 %304 %72
668                OpSelectionMerge %75 None
669                OpBranchConditional %73 %74 %75
670          %74 = OpLabel
671                OpBranch %59
672          %75 = OpLabel
673          %78 = OpSGreaterThan %17 %304 %9
674                OpBranchConditional %78 %79 %80
675          %79 = OpLabel
676          %83 = OpISub %6 %304 %54
677          %84 = OpAccessChain %51 %46 %83
678          %85 = OpLoad %20 %84
679          %86 = OpAccessChain %51 %46 %304
680          %87 = OpLoad %20 %86
681          %88 = OpFAdd %20 %87 %85
682                OpStore %86 %88
683                OpBranch %80
684          %80 = OpLabel
685          %91 = OpIAdd %6 %304 %54
686                OpBranch %57
687          %59 = OpLabel
688          %92 = OpAccessChain %69 %68 %26
689          %93 = OpLoad %20 %92
690          %94 = OpConvertFToS %6 %93
691          %96 = OpSLessThan %17 %94 %95
692                OpSelectionMerge %98 None
693                OpBranchConditional %96 %97 %114
694          %97 = OpLabel
695         %101 = OpAccessChain %51 %46 %9
696         %102 = OpLoad %20 %101
697         %103 = OpAccessChain %27 %24 %9 %26
698         %104 = OpLoad %20 %103
699         %105 = OpFDiv %20 %102 %104
700         %106 = OpAccessChain %51 %46 %35
701         %107 = OpLoad %20 %106
702         %109 = OpAccessChain %27 %24 %9 %108
703         %110 = OpLoad %20 %109
704         %111 = OpFDiv %20 %107 %110
705         %113 = OpCompositeConstruct %66 %105 %111 %112 %112
706                OpStore %100 %113
707                OpBranch %98
708         %114 = OpLabel
709         %119 = OpSLessThan %17 %94 %118
710                OpSelectionMerge %121 None
711                OpBranchConditional %119 %120 %135
712         %120 = OpLabel
713         %123 = OpAccessChain %51 %46 %122
714         %124 = OpLoad %20 %123
715         %125 = OpAccessChain %27 %24 %9 %26
716         %126 = OpLoad %20 %125
717         %127 = OpFDiv %20 %124 %126
718         %129 = OpAccessChain %51 %46 %128
719         %130 = OpLoad %20 %129
720         %131 = OpAccessChain %27 %24 %9 %108
721         %132 = OpLoad %20 %131
722         %133 = OpFDiv %20 %130 %132
723         %134 = OpCompositeConstruct %66 %127 %133 %112 %112
724                OpStore %100 %134
725                OpBranch %121
726         %135 = OpLabel
727         %140 = OpSLessThan %17 %94 %139
728                OpSelectionMerge %142 None
729                OpBranchConditional %140 %141 %156
730         %141 = OpLabel
731         %144 = OpAccessChain %51 %46 %143
732         %145 = OpLoad %20 %144
733         %146 = OpAccessChain %27 %24 %9 %26
734         %147 = OpLoad %20 %146
735         %148 = OpFDiv %20 %145 %147
736         %150 = OpAccessChain %51 %46 %149
737         %151 = OpLoad %20 %150
738         %152 = OpAccessChain %27 %24 %9 %108
739         %153 = OpLoad %20 %152
740         %154 = OpFDiv %20 %151 %153
741         %155 = OpCompositeConstruct %66 %148 %154 %112 %112
742                OpStore %100 %155
743                OpBranch %142
744         %156 = OpLabel
745         %161 = OpSLessThan %17 %94 %160
746                OpSelectionMerge %163 None
747                OpBranchConditional %161 %162 %177
748         %162 = OpLabel
749         %165 = OpAccessChain %51 %46 %164
750         %166 = OpLoad %20 %165
751         %167 = OpAccessChain %27 %24 %9 %26
752         %168 = OpLoad %20 %167
753         %169 = OpFDiv %20 %166 %168
754         %171 = OpAccessChain %51 %46 %170
755         %172 = OpLoad %20 %171
756         %173 = OpAccessChain %27 %24 %9 %108
757         %174 = OpLoad %20 %173
758         %175 = OpFDiv %20 %172 %174
759         %176 = OpCompositeConstruct %66 %169 %175 %112 %112
760                OpStore %100 %176
761                OpBranch %163
762         %177 = OpLabel
763         %182 = OpSLessThan %17 %94 %181
764                OpSelectionMerge %184 None
765                OpBranchConditional %182 %183 %197
766         %183 = OpLabel
767         %185 = OpAccessChain %51 %46 %95
768         %186 = OpLoad %20 %185
769         %187 = OpAccessChain %27 %24 %9 %26
770         %188 = OpLoad %20 %187
771         %189 = OpFDiv %20 %186 %188
772         %191 = OpAccessChain %51 %46 %190
773         %192 = OpLoad %20 %191
774         %193 = OpAccessChain %27 %24 %9 %108
775         %194 = OpLoad %20 %193
776         %195 = OpFDiv %20 %192 %194
777         %196 = OpCompositeConstruct %66 %189 %195 %112 %112
778                OpStore %100 %196
779                OpBranch %184
780         %197 = OpLabel
781         %202 = OpSLessThan %17 %94 %201
782                OpSelectionMerge %204 None
783                OpBranchConditional %202 %203 %218
784         %203 = OpLabel
785         %206 = OpAccessChain %51 %46 %205
786         %207 = OpLoad %20 %206
787         %208 = OpAccessChain %27 %24 %9 %26
788         %209 = OpLoad %20 %208
789         %210 = OpFDiv %20 %207 %209
790         %212 = OpAccessChain %51 %46 %211
791         %213 = OpLoad %20 %212
792         %214 = OpAccessChain %27 %24 %9 %108
793         %215 = OpLoad %20 %214
794         %216 = OpFDiv %20 %213 %215
795         %217 = OpCompositeConstruct %66 %210 %216 %112 %112
796                OpStore %100 %217
797                OpBranch %204
798         %218 = OpLabel
799         %223 = OpSLessThan %17 %94 %222
800                OpSelectionMerge %225 None
801                OpBranchConditional %223 %224 %239
802         %224 = OpLabel
803         %227 = OpAccessChain %51 %46 %226
804         %228 = OpLoad %20 %227
805         %229 = OpAccessChain %27 %24 %9 %26
806         %230 = OpLoad %20 %229
807         %231 = OpFDiv %20 %228 %230
808         %233 = OpAccessChain %51 %46 %232
809         %234 = OpLoad %20 %233
810         %235 = OpAccessChain %27 %24 %9 %108
811         %236 = OpLoad %20 %235
812         %237 = OpFDiv %20 %234 %236
813         %238 = OpCompositeConstruct %66 %231 %237 %112 %112
814                OpStore %100 %238
815                OpBranch %225
816         %239 = OpLabel
817         %244 = OpSLessThan %17 %94 %243
818                OpSelectionMerge %246 None
819                OpBranchConditional %244 %245 %260
820         %245 = OpLabel
821         %248 = OpAccessChain %51 %46 %247
822         %249 = OpLoad %20 %248
823         %250 = OpAccessChain %27 %24 %9 %26
824         %251 = OpLoad %20 %250
825         %252 = OpFDiv %20 %249 %251
826         %254 = OpAccessChain %51 %46 %253
827         %255 = OpLoad %20 %254
828         %256 = OpAccessChain %27 %24 %9 %108
829         %257 = OpLoad %20 %256
830         %258 = OpFDiv %20 %255 %257
831         %259 = OpCompositeConstruct %66 %252 %258 %112 %112
832                OpStore %100 %259
833                OpBranch %246
834         %260 = OpLabel
835         %265 = OpSLessThan %17 %94 %264
836                OpSelectionMerge %267 None
837                OpBranchConditional %265 %266 %280
838         %266 = OpLabel
839         %268 = OpAccessChain %51 %46 %118
840         %269 = OpLoad %20 %268
841         %270 = OpAccessChain %27 %24 %9 %26
842         %271 = OpLoad %20 %270
843         %272 = OpFDiv %20 %269 %271
844         %274 = OpAccessChain %51 %46 %273
845         %275 = OpLoad %20 %274
846         %276 = OpAccessChain %27 %24 %9 %108
847         %277 = OpLoad %20 %276
848         %278 = OpFDiv %20 %275 %277
849         %279 = OpCompositeConstruct %66 %272 %278 %112 %112
850                OpStore %100 %279
851                OpBranch %267
852         %280 = OpLabel
853                OpSelectionMerge %285 None
854                OpBranchConditional %265 %285 %300
855         %285 = OpLabel
856         %288 = OpAccessChain %51 %46 %287
857         %289 = OpLoad %20 %288
858         %290 = OpAccessChain %27 %24 %9 %26
859         %291 = OpLoad %20 %290
860         %292 = OpFDiv %20 %289 %291
861         %294 = OpAccessChain %51 %46 %293
862         %295 = OpLoad %20 %294
863         %296 = OpAccessChain %27 %24 %9 %108
864         %297 = OpLoad %20 %296
865         %298 = OpFDiv %20 %295 %297
866         %299 = OpCompositeConstruct %66 %292 %298 %112 %112
867                OpStore %100 %299
868                OpBranch %267
869         %300 = OpLabel
870                OpKill
871         %267 = OpLabel
872                OpBranch %246
873         %246 = OpLabel
874                OpBranch %225
875         %225 = OpLabel
876                OpBranch %204
877         %204 = OpLabel
878                OpBranch %184
879         %184 = OpLabel
880                OpBranch %163
881         %163 = OpLabel
882                OpBranch %142
883         %142 = OpLabel
884                OpBranch %121
885         %121 = OpLabel
886                OpBranch %98
887          %98 = OpLabel
888                OpReturn
889                OpFunctionEnd
890   )";
891 
892 // Abstract class exposing an interestingness function as a virtual method.
893 class InterestingnessTest {
894  public:
895   virtual ~InterestingnessTest() = default;
896 
897   // Abstract method that subclasses should implement for specific notions of
898   // interestingness. Its signature matches Shrinker::InterestingnessFunction.
899   // Argument |binary| is the SPIR-V binary to be checked; |counter| is used for
900   // debugging purposes.
901   virtual bool Interesting(const std::vector<uint32_t>& binary,
902                            uint32_t counter) = 0;
903 
904   // Yields the Interesting instance method wrapped in a function object.
AsFunction()905   Shrinker::InterestingnessFunction AsFunction() {
906     return std::bind(&InterestingnessTest::Interesting, this,
907                      std::placeholders::_1, std::placeholders::_2);
908   }
909 };
910 
911 // A test that says all binaries are interesting.
912 class AlwaysInteresting : public InterestingnessTest {
913  public:
Interesting(const std::vector<uint32_t> &,uint32_t)914   bool Interesting(const std::vector<uint32_t>&, uint32_t) override {
915     return true;
916   }
917 };
918 
919 // A test that says a binary is interesting first time round, and uninteresting
920 // thereafter.
921 class OnlyInterestingFirstTime : public InterestingnessTest {
922  public:
OnlyInterestingFirstTime()923   explicit OnlyInterestingFirstTime() : first_time_(true) {}
924 
Interesting(const std::vector<uint32_t> &,uint32_t)925   bool Interesting(const std::vector<uint32_t>&, uint32_t) override {
926     if (first_time_) {
927       first_time_ = false;
928       return true;
929     }
930     return false;
931   }
932 
933  private:
934   bool first_time_;
935 };
936 
937 // A test that says a binary is interesting first time round, after which
938 // interestingness ping pongs between false and true.
939 class PingPong : public InterestingnessTest {
940  public:
PingPong()941   explicit PingPong() : interesting_(false) {}
942 
Interesting(const std::vector<uint32_t> &,uint32_t)943   bool Interesting(const std::vector<uint32_t>&, uint32_t) override {
944     interesting_ = !interesting_;
945     return interesting_;
946   }
947 
948  private:
949   bool interesting_;
950 };
951 
952 // A test that says a binary is interesting first time round, thereafter
953 // decides at random whether it is interesting.  This allows the logic of the
954 // shrinker to be exercised quite a bit.
955 class InterestingThenRandom : public InterestingnessTest {
956  public:
InterestingThenRandom(const PseudoRandomGenerator & random_generator)957   InterestingThenRandom(const PseudoRandomGenerator& random_generator)
958       : first_time_(true), random_generator_(random_generator) {}
959 
Interesting(const std::vector<uint32_t> &,uint32_t)960   bool Interesting(const std::vector<uint32_t>&, uint32_t) override {
961     if (first_time_) {
962       first_time_ = false;
963       return true;
964     }
965     return random_generator_.RandomBool();
966   }
967 
968  private:
969   bool first_time_;
970   PseudoRandomGenerator random_generator_;
971 };
972 
973 // |binary_in| and |initial_facts| are a SPIR-V binary and sequence of facts to
974 // which |transformation_sequence_in| can be applied.  Shrinking of
975 // |transformation_sequence_in| gets performed with respect to
976 // |interestingness_function|.  If |expected_binary_out| is non-empty, it must
977 // match the binary obtained by applying the final shrunk set of
978 // transformations, in which case the number of such transformations should
979 // equal |expected_transformations_out_size|.
980 //
981 // The |step_limit| parameter restricts the number of steps that the shrinker
982 // will try; it can be set to something small for a faster (but less thorough)
983 // test.
984 //
985 // The |validator_options| parameter provides validator options that should be
986 // used during shrinking.
RunAndCheckShrinker(const spv_target_env & target_env,const std::vector<uint32_t> & binary_in,const protobufs::FactSequence & initial_facts,const protobufs::TransformationSequence & transformation_sequence_in,const Shrinker::InterestingnessFunction & interestingness_function,const std::vector<uint32_t> & expected_binary_out,uint32_t expected_transformations_out_size,uint32_t step_limit,spv_validator_options validator_options)987 void RunAndCheckShrinker(
988     const spv_target_env& target_env, const std::vector<uint32_t>& binary_in,
989     const protobufs::FactSequence& initial_facts,
990     const protobufs::TransformationSequence& transformation_sequence_in,
991     const Shrinker::InterestingnessFunction& interestingness_function,
992     const std::vector<uint32_t>& expected_binary_out,
993     uint32_t expected_transformations_out_size, uint32_t step_limit,
994     spv_validator_options validator_options) {
995   // Run the shrinker.
996   auto shrinker_result =
997       Shrinker(target_env, kConsoleMessageConsumer, binary_in, initial_facts,
998                transformation_sequence_in, interestingness_function, step_limit,
999                false, validator_options)
1000           .Run();
1001 
1002   ASSERT_TRUE(Shrinker::ShrinkerResultStatus::kComplete ==
1003                   shrinker_result.status ||
1004               Shrinker::ShrinkerResultStatus::kStepLimitReached ==
1005                   shrinker_result.status);
1006 
1007   // If a non-empty expected binary was provided, check that it matches the
1008   // result of shrinking and that the expected number of transformations remain.
1009   if (!expected_binary_out.empty()) {
1010     ASSERT_EQ(expected_binary_out, shrinker_result.transformed_binary);
1011     ASSERT_EQ(
1012         expected_transformations_out_size,
1013         static_cast<uint32_t>(
1014             shrinker_result.applied_transformations.transformation_size()));
1015   }
1016 }
1017 
1018 // Assembles the given |shader| text, and then:
1019 // - Runs the fuzzer with |seed| to yield a set of transformations
1020 // - Shrinks the transformation with various interestingness functions,
1021 //   asserting some properties about the result each time
RunFuzzerAndShrinker(const std::string & shader,const protobufs::FactSequence & initial_facts,uint32_t seed)1022 void RunFuzzerAndShrinker(const std::string& shader,
1023                           const protobufs::FactSequence& initial_facts,
1024                           uint32_t seed) {
1025   const auto env = SPV_ENV_UNIVERSAL_1_5;
1026 
1027   std::vector<uint32_t> binary_in;
1028   SpirvTools t(env);
1029   t.SetMessageConsumer(kConsoleMessageConsumer);
1030   ASSERT_TRUE(t.Assemble(shader, &binary_in, kFuzzAssembleOption));
1031   ASSERT_TRUE(t.Validate(binary_in));
1032 
1033   std::vector<fuzzerutil::ModuleSupplier> donor_suppliers;
1034   for (auto donor : {&kTestShader1, &kTestShader2, &kTestShader3}) {
1035     donor_suppliers.emplace_back([donor]() {
1036       return BuildModule(env, kConsoleMessageConsumer, *donor,
1037                          kFuzzAssembleOption);
1038     });
1039   }
1040 
1041   // Run the fuzzer and check that it successfully yields a valid binary.
1042   spvtools::ValidatorOptions validator_options;
1043 
1044   // Depending on the seed, decide whether to enable all passes and which
1045   // repeated pass manager to use.
1046   bool enable_all_passes = (seed % 4) == 0;
1047   Fuzzer::RepeatedPassStrategy repeated_pass_strategy;
1048   if ((seed % 3) == 0) {
1049     repeated_pass_strategy = Fuzzer::RepeatedPassStrategy::kSimple;
1050   } else if ((seed % 3) == 1) {
1051     repeated_pass_strategy =
1052         Fuzzer::RepeatedPassStrategy::kLoopedWithRecommendations;
1053   } else {
1054     repeated_pass_strategy =
1055         Fuzzer::RepeatedPassStrategy::kRandomWithRecommendations;
1056   }
1057 
1058   auto fuzzer_result =
1059       Fuzzer(env, kConsoleMessageConsumer, binary_in, initial_facts,
1060              donor_suppliers, MakeUnique<PseudoRandomGenerator>(seed),
1061              enable_all_passes, repeated_pass_strategy, true, validator_options)
1062           .Run();
1063   ASSERT_EQ(Fuzzer::FuzzerResultStatus::kComplete, fuzzer_result.status);
1064   ASSERT_TRUE(t.Validate(fuzzer_result.transformed_binary));
1065 
1066   const uint32_t kReasonableStepLimit = 50;
1067   const uint32_t kSmallStepLimit = 20;
1068 
1069   // With the AlwaysInteresting test, we should quickly shrink to the original
1070   // binary with no transformations remaining.
1071   RunAndCheckShrinker(env, binary_in, initial_facts,
1072                       fuzzer_result.applied_transformations,
1073                       AlwaysInteresting().AsFunction(), binary_in, 0,
1074                       kReasonableStepLimit, validator_options);
1075 
1076   // With the OnlyInterestingFirstTime test, no shrinking should be achieved.
1077   RunAndCheckShrinker(
1078       env, binary_in, initial_facts, fuzzer_result.applied_transformations,
1079       OnlyInterestingFirstTime().AsFunction(), fuzzer_result.transformed_binary,
1080       static_cast<uint32_t>(
1081           fuzzer_result.applied_transformations.transformation_size()),
1082       kReasonableStepLimit, validator_options);
1083 
1084   // The PingPong test is unpredictable; passing an empty expected binary
1085   // means that we don't check anything beyond that shrinking completes
1086   // successfully.
1087   RunAndCheckShrinker(
1088       env, binary_in, initial_facts, fuzzer_result.applied_transformations,
1089       PingPong().AsFunction(), {}, 0, kSmallStepLimit, validator_options);
1090 
1091   // The InterestingThenRandom test is unpredictable; passing an empty
1092   // expected binary means that we do not check anything about shrinking
1093   // results.
1094   RunAndCheckShrinker(
1095       env, binary_in, initial_facts, fuzzer_result.applied_transformations,
1096       InterestingThenRandom(PseudoRandomGenerator(seed)).AsFunction(), {}, 0,
1097       kSmallStepLimit, validator_options);
1098 }
1099 
TEST(FuzzerShrinkerTest,Miscellaneous1)1100 TEST(FuzzerShrinkerTest, Miscellaneous1) {
1101   RunFuzzerAndShrinker(kTestShader1, protobufs::FactSequence(), 2);
1102 }
1103 
TEST(FuzzerShrinkerTest,Miscellaneous2)1104 TEST(FuzzerShrinkerTest, Miscellaneous2) {
1105   RunFuzzerAndShrinker(kTestShader2, protobufs::FactSequence(), 19);
1106 }
1107 
TEST(FuzzerShrinkerTest,Miscellaneous3)1108 TEST(FuzzerShrinkerTest, Miscellaneous3) {
1109   // Add the facts "resolution.x == 250" and "resolution.y == 100".
1110   protobufs::FactSequence facts;
1111   {
1112     protobufs::FactConstantUniform resolution_x_eq_250;
1113     *resolution_x_eq_250.mutable_uniform_buffer_element_descriptor() =
1114         MakeUniformBufferElementDescriptor(0, 0, {0, 0});
1115     *resolution_x_eq_250.mutable_constant_word()->Add() = 250;
1116     protobufs::Fact temp;
1117     *temp.mutable_constant_uniform_fact() = resolution_x_eq_250;
1118     *facts.mutable_fact()->Add() = temp;
1119   }
1120   {
1121     protobufs::FactConstantUniform resolution_y_eq_100;
1122     *resolution_y_eq_100.mutable_uniform_buffer_element_descriptor() =
1123         MakeUniformBufferElementDescriptor(0, 0, {0, 1});
1124     *resolution_y_eq_100.mutable_constant_word()->Add() = 100;
1125     protobufs::Fact temp;
1126     *temp.mutable_constant_uniform_fact() = resolution_y_eq_100;
1127     *facts.mutable_fact()->Add() = temp;
1128   }
1129   // Also add an invalid fact, which should be ignored.
1130   {
1131     protobufs::FactConstantUniform bad_fact;
1132     // The descriptor set, binding and indices used here deliberately make no
1133     // sense.
1134     *bad_fact.mutable_uniform_buffer_element_descriptor() =
1135         MakeUniformBufferElementDescriptor(22, 33, {44, 55});
1136     *bad_fact.mutable_constant_word()->Add() = 100;
1137     protobufs::Fact temp;
1138     *temp.mutable_constant_uniform_fact() = bad_fact;
1139     *facts.mutable_fact()->Add() = temp;
1140   }
1141 
1142   // Do 2 fuzzer runs, starting from an initial seed of 194 (seed value chosen
1143   // arbitrarily).
1144   RunFuzzerAndShrinker(kTestShader3, facts, 194);
1145 }
1146 
1147 }  // namespace
1148 }  // namespace fuzz
1149 }  // namespace spvtools
1150