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