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
26namespace spvtools {
27namespace fuzz {
28namespace {
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
58const 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
247const 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
543const 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.
892class 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.
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.
911class AlwaysInteresting : public InterestingnessTest {
912 public:
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.
920class OnlyInterestingFirstTime : public InterestingnessTest {
921 public:
922  explicit OnlyInterestingFirstTime() : first_time_(true) {}
923
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.
938class PingPong : public InterestingnessTest {
939 public:
940  explicit PingPong() : interesting_(false) {}
941
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.
954class InterestingThenRandom : public InterestingnessTest {
955 public:
956  InterestingThenRandom(const PseudoRandomGenerator& random_generator)
957      : first_time_(true), random_generator_(random_generator) {}
958
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.
986void 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
1021void 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
1113TEST(FuzzerShrinkerTest, Miscellaneous1) {
1114  RunFuzzerAndShrinker(kTestShader1, protobufs::FactSequence(), 2);
1115}
1116
1117TEST(FuzzerShrinkerTest, Miscellaneous2) {
1118  RunFuzzerAndShrinker(kTestShader2, protobufs::FactSequence(), 19);
1119}
1120
1121TEST(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