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