| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149 |
- // Copyright (c) 2019 Google LLC
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #include "source/fuzz/fuzzer.h"
- #include "source/fuzz/shrinker.h"
- #include <functional>
- #include <vector>
- #include "gtest/gtest.h"
- #include "source/fuzz/fuzzer_util.h"
- #include "source/fuzz/pseudo_random_generator.h"
- #include "source/fuzz/uniform_buffer_element_descriptor.h"
- #include "test/fuzz/fuzz_test_util.h"
- namespace spvtools {
- namespace fuzz {
- namespace {
- // The following SPIR-V came from this GLSL:
- //
- // #version 310 es
- //
- // void foo() {
- // int x;
- // x = 2;
- // for (int i = 0; i < 100; i++) {
- // x += i;
- // x = x * 2;
- // }
- // return;
- // }
- //
- // void main() {
- // foo();
- // for (int i = 0; i < 10; i++) {
- // int j = 20;
- // while(j > 0) {
- // foo();
- // j--;
- // }
- // do {
- // i++;
- // } while(i < 4);
- // }
- // }
- const std::string kTestShader1 = R"(
- OpCapability Shader
- %1 = OpExtInstImport "GLSL.std.450"
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %4 "main"
- OpExecutionMode %4 OriginUpperLeft
- OpSource ESSL 310
- OpName %4 "main"
- OpName %6 "foo("
- OpName %10 "x"
- OpName %12 "i"
- OpName %33 "i"
- OpName %42 "j"
- OpDecorate %10 RelaxedPrecision
- OpDecorate %12 RelaxedPrecision
- OpDecorate %19 RelaxedPrecision
- OpDecorate %23 RelaxedPrecision
- OpDecorate %24 RelaxedPrecision
- OpDecorate %25 RelaxedPrecision
- OpDecorate %26 RelaxedPrecision
- OpDecorate %27 RelaxedPrecision
- OpDecorate %28 RelaxedPrecision
- OpDecorate %30 RelaxedPrecision
- OpDecorate %33 RelaxedPrecision
- OpDecorate %39 RelaxedPrecision
- OpDecorate %42 RelaxedPrecision
- OpDecorate %49 RelaxedPrecision
- OpDecorate %52 RelaxedPrecision
- OpDecorate %53 RelaxedPrecision
- OpDecorate %58 RelaxedPrecision
- OpDecorate %59 RelaxedPrecision
- OpDecorate %60 RelaxedPrecision
- OpDecorate %63 RelaxedPrecision
- OpDecorate %64 RelaxedPrecision
- %2 = OpTypeVoid
- %3 = OpTypeFunction %2
- %8 = OpTypeInt 32 1
- %9 = OpTypePointer Function %8
- %11 = OpConstant %8 2
- %13 = OpConstant %8 0
- %20 = OpConstant %8 100
- %21 = OpTypeBool
- %29 = OpConstant %8 1
- %40 = OpConstant %8 10
- %43 = OpConstant %8 20
- %61 = OpConstant %8 4
- %4 = OpFunction %2 None %3
- %5 = OpLabel
- %33 = OpVariable %9 Function
- %42 = OpVariable %9 Function
- %32 = OpFunctionCall %2 %6
- OpStore %33 %13
- OpBranch %34
- %34 = OpLabel
- OpLoopMerge %36 %37 None
- OpBranch %38
- %38 = OpLabel
- %39 = OpLoad %8 %33
- %41 = OpSLessThan %21 %39 %40
- OpBranchConditional %41 %35 %36
- %35 = OpLabel
- OpStore %42 %43
- OpBranch %44
- %44 = OpLabel
- OpLoopMerge %46 %47 None
- OpBranch %48
- %48 = OpLabel
- %49 = OpLoad %8 %42
- %50 = OpSGreaterThan %21 %49 %13
- OpBranchConditional %50 %45 %46
- %45 = OpLabel
- %51 = OpFunctionCall %2 %6
- %52 = OpLoad %8 %42
- %53 = OpISub %8 %52 %29
- OpStore %42 %53
- OpBranch %47
- %47 = OpLabel
- OpBranch %44
- %46 = OpLabel
- OpBranch %54
- %54 = OpLabel
- OpLoopMerge %56 %57 None
- OpBranch %55
- %55 = OpLabel
- %58 = OpLoad %8 %33
- %59 = OpIAdd %8 %58 %29
- OpStore %33 %59
- OpBranch %57
- %57 = OpLabel
- %60 = OpLoad %8 %33
- %62 = OpSLessThan %21 %60 %61
- OpBranchConditional %62 %54 %56
- %56 = OpLabel
- OpBranch %37
- %37 = OpLabel
- %63 = OpLoad %8 %33
- %64 = OpIAdd %8 %63 %29
- OpStore %33 %64
- OpBranch %34
- %36 = OpLabel
- OpReturn
- OpFunctionEnd
- %6 = OpFunction %2 None %3
- %7 = OpLabel
- %10 = OpVariable %9 Function
- %12 = OpVariable %9 Function
- OpStore %10 %11
- OpStore %12 %13
- OpBranch %14
- %14 = OpLabel
- OpLoopMerge %16 %17 None
- OpBranch %18
- %18 = OpLabel
- %19 = OpLoad %8 %12
- %22 = OpSLessThan %21 %19 %20
- OpBranchConditional %22 %15 %16
- %15 = OpLabel
- %23 = OpLoad %8 %12
- %24 = OpLoad %8 %10
- %25 = OpIAdd %8 %24 %23
- OpStore %10 %25
- %26 = OpLoad %8 %10
- %27 = OpIMul %8 %26 %11
- OpStore %10 %27
- OpBranch %17
- %17 = OpLabel
- %28 = OpLoad %8 %12
- %30 = OpIAdd %8 %28 %29
- OpStore %12 %30
- OpBranch %14
- %16 = OpLabel
- OpReturn
- OpFunctionEnd
- )";
- // The following SPIR-V came from this GLSL, which was then optimized using
- // spirv-opt with the -O argument:
- //
- // #version 310 es
- //
- // precision highp float;
- //
- // layout(location = 0) out vec4 _GLF_color;
- //
- // layout(set = 0, binding = 0) uniform buf0 {
- // vec2 injectionSwitch;
- // };
- // layout(set = 0, binding = 1) uniform buf1 {
- // vec2 resolution;
- // };
- // bool checkSwap(float a, float b)
- // {
- // return gl_FragCoord.y < resolution.y / 2.0 ? a > b : a < b;
- // }
- // void main()
- // {
- // float data[10];
- // for(int i = 0; i < 10; i++)
- // {
- // data[i] = float(10 - i) * injectionSwitch.y;
- // }
- // for(int i = 0; i < 9; i++)
- // {
- // for(int j = 0; j < 10; j++)
- // {
- // if(j < i + 1)
- // {
- // continue;
- // }
- // bool doSwap = checkSwap(data[i], data[j]);
- // if(doSwap)
- // {
- // float temp = data[i];
- // data[i] = data[j];
- // data[j] = temp;
- // }
- // }
- // }
- // if(gl_FragCoord.x < resolution.x / 2.0)
- // {
- // _GLF_color = vec4(data[0] / 10.0, data[5] / 10.0, data[9] / 10.0, 1.0);
- // }
- // else
- // {
- // _GLF_color = vec4(data[5] / 10.0, data[9] / 10.0, data[0] / 10.0, 1.0);
- // }
- // }
- const std::string kTestShader2 = R"(
- OpCapability Shader
- %1 = OpExtInstImport "GLSL.std.450"
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %4 "main" %16 %139 %25 %68
- OpExecutionMode %4 OriginUpperLeft
- OpSource ESSL 310
- OpName %4 "main"
- OpName %16 "gl_FragCoord"
- OpName %23 "buf1"
- OpMemberName %23 0 "resolution"
- OpName %25 ""
- OpName %61 "data"
- OpName %66 "buf0"
- OpMemberName %66 0 "injectionSwitch"
- OpName %68 ""
- OpName %139 "_GLF_color"
- OpDecorate %16 BuiltIn FragCoord
- OpMemberDecorate %23 0 Offset 0
- OpDecorate %23 Block
- OpDecorate %25 DescriptorSet 0
- OpDecorate %25 Binding 1
- OpDecorate %64 RelaxedPrecision
- OpMemberDecorate %66 0 Offset 0
- OpDecorate %66 Block
- OpDecorate %68 DescriptorSet 0
- OpDecorate %68 Binding 0
- OpDecorate %75 RelaxedPrecision
- OpDecorate %95 RelaxedPrecision
- OpDecorate %126 RelaxedPrecision
- OpDecorate %128 RelaxedPrecision
- OpDecorate %139 Location 0
- OpDecorate %182 RelaxedPrecision
- OpDecorate %183 RelaxedPrecision
- OpDecorate %184 RelaxedPrecision
- %2 = OpTypeVoid
- %3 = OpTypeFunction %2
- %6 = OpTypeFloat 32
- %7 = OpTypePointer Function %6
- %8 = OpTypeBool
- %14 = OpTypeVector %6 4
- %15 = OpTypePointer Input %14
- %16 = OpVariable %15 Input
- %17 = OpTypeInt 32 0
- %18 = OpConstant %17 1
- %19 = OpTypePointer Input %6
- %22 = OpTypeVector %6 2
- %23 = OpTypeStruct %22
- %24 = OpTypePointer Uniform %23
- %25 = OpVariable %24 Uniform
- %26 = OpTypeInt 32 1
- %27 = OpConstant %26 0
- %28 = OpTypePointer Uniform %6
- %56 = OpConstant %26 10
- %58 = OpConstant %17 10
- %59 = OpTypeArray %6 %58
- %60 = OpTypePointer Function %59
- %66 = OpTypeStruct %22
- %67 = OpTypePointer Uniform %66
- %68 = OpVariable %67 Uniform
- %74 = OpConstant %26 1
- %83 = OpConstant %26 9
- %129 = OpConstant %17 0
- %138 = OpTypePointer Output %14
- %139 = OpVariable %138 Output
- %144 = OpConstant %26 5
- %151 = OpConstant %6 1
- %194 = OpConstant %6 0.5
- %195 = OpConstant %6 0.100000001
- %4 = OpFunction %2 None %3
- %5 = OpLabel
- %61 = OpVariable %60 Function
- OpBranch %50
- %50 = OpLabel
- %182 = OpPhi %26 %27 %5 %75 %51
- %57 = OpSLessThan %8 %182 %56
- OpLoopMerge %52 %51 None
- OpBranchConditional %57 %51 %52
- %51 = OpLabel
- %64 = OpISub %26 %56 %182
- %65 = OpConvertSToF %6 %64
- %69 = OpAccessChain %28 %68 %27 %18
- %70 = OpLoad %6 %69
- %71 = OpFMul %6 %65 %70
- %72 = OpAccessChain %7 %61 %182
- OpStore %72 %71
- %75 = OpIAdd %26 %182 %74
- OpBranch %50
- %52 = OpLabel
- OpBranch %77
- %77 = OpLabel
- %183 = OpPhi %26 %27 %52 %128 %88
- %84 = OpSLessThan %8 %183 %83
- OpLoopMerge %79 %88 None
- OpBranchConditional %84 %78 %79
- %78 = OpLabel
- OpBranch %86
- %86 = OpLabel
- %184 = OpPhi %26 %27 %78 %126 %89
- %92 = OpSLessThan %8 %184 %56
- OpLoopMerge %1000 %89 None
- OpBranchConditional %92 %87 %1000
- %87 = OpLabel
- %95 = OpIAdd %26 %183 %74
- %96 = OpSLessThan %8 %184 %95
- OpSelectionMerge %98 None
- OpBranchConditional %96 %97 %98
- %97 = OpLabel
- OpBranch %89
- %98 = OpLabel
- %104 = OpAccessChain %7 %61 %183
- %105 = OpLoad %6 %104
- %107 = OpAccessChain %7 %61 %184
- %108 = OpLoad %6 %107
- %166 = OpAccessChain %19 %16 %18
- %167 = OpLoad %6 %166
- %168 = OpAccessChain %28 %25 %27 %18
- %169 = OpLoad %6 %168
- %170 = OpFMul %6 %169 %194
- %171 = OpFOrdLessThan %8 %167 %170
- OpSelectionMerge %172 None
- OpBranchConditional %171 %173 %174
- %173 = OpLabel
- %177 = OpFOrdGreaterThan %8 %105 %108
- OpBranch %172
- %174 = OpLabel
- %180 = OpFOrdLessThan %8 %105 %108
- OpBranch %172
- %172 = OpLabel
- %186 = OpPhi %8 %177 %173 %180 %174
- OpSelectionMerge %112 None
- OpBranchConditional %186 %111 %112
- %111 = OpLabel
- %116 = OpLoad %6 %104
- %120 = OpLoad %6 %107
- OpStore %104 %120
- OpStore %107 %116
- OpBranch %112
- %112 = OpLabel
- OpBranch %89
- %89 = OpLabel
- %126 = OpIAdd %26 %184 %74
- OpBranch %86
- %1000 = OpLabel
- OpBranch %88
- %88 = OpLabel
- %128 = OpIAdd %26 %183 %74
- OpBranch %77
- %79 = OpLabel
- %130 = OpAccessChain %19 %16 %129
- %131 = OpLoad %6 %130
- %132 = OpAccessChain %28 %25 %27 %129
- %133 = OpLoad %6 %132
- %134 = OpFMul %6 %133 %194
- %135 = OpFOrdLessThan %8 %131 %134
- OpSelectionMerge %137 None
- OpBranchConditional %135 %136 %153
- %136 = OpLabel
- %140 = OpAccessChain %7 %61 %27
- %141 = OpLoad %6 %140
- %143 = OpFMul %6 %141 %195
- %145 = OpAccessChain %7 %61 %144
- %146 = OpLoad %6 %145
- %147 = OpFMul %6 %146 %195
- %148 = OpAccessChain %7 %61 %83
- %149 = OpLoad %6 %148
- %150 = OpFMul %6 %149 %195
- %152 = OpCompositeConstruct %14 %143 %147 %150 %151
- OpStore %139 %152
- OpBranch %137
- %153 = OpLabel
- %154 = OpAccessChain %7 %61 %144
- %155 = OpLoad %6 %154
- %156 = OpFMul %6 %155 %195
- %157 = OpAccessChain %7 %61 %83
- %158 = OpLoad %6 %157
- %159 = OpFMul %6 %158 %195
- %160 = OpAccessChain %7 %61 %27
- %161 = OpLoad %6 %160
- %162 = OpFMul %6 %161 %195
- %163 = OpCompositeConstruct %14 %156 %159 %162 %151
- OpStore %139 %163
- OpBranch %137
- %137 = OpLabel
- OpReturn
- OpFunctionEnd
- )";
- // The following SPIR-V came from this GLSL, which was then optimized using
- // spirv-opt with the -O argument:
- //
- // #version 310 es
- //
- // precision highp float;
- //
- // layout(location = 0) out vec4 _GLF_color;
- //
- // layout(set = 0, binding = 0) uniform buf0 {
- // vec2 resolution;
- // };
- // void main(void)
- // {
- // float A[50];
- // for(
- // int i = 0;
- // i < 200;
- // i ++
- // )
- // {
- // if(i >= int(resolution.x))
- // {
- // break;
- // }
- // if((4 * (i / 4)) == i)
- // {
- // A[i / 4] = float(i);
- // }
- // }
- // for(
- // int i = 0;
- // i < 50;
- // i ++
- // )
- // {
- // if(i < int(gl_FragCoord.x))
- // {
- // break;
- // }
- // if(i > 0)
- // {
- // A[i] += A[i - 1];
- // }
- // }
- // if(int(gl_FragCoord.x) < 20)
- // {
- // _GLF_color = vec4(A[0] / resolution.x, A[4] / resolution.y, 1.0, 1.0);
- // }
- // else
- // if(int(gl_FragCoord.x) < 40)
- // {
- // _GLF_color = vec4(A[5] / resolution.x, A[9] / resolution.y, 1.0, 1.0);
- // }
- // else
- // if(int(gl_FragCoord.x) < 60)
- // {
- // _GLF_color = vec4(A[10] / resolution.x, A[14] / resolution.y,
- // 1.0, 1.0);
- // }
- // else
- // if(int(gl_FragCoord.x) < 80)
- // {
- // _GLF_color = vec4(A[15] / resolution.x, A[19] / resolution.y,
- // 1.0, 1.0);
- // }
- // else
- // if(int(gl_FragCoord.x) < 100)
- // {
- // _GLF_color = vec4(A[20] / resolution.x, A[24] / resolution.y,
- // 1.0, 1.0);
- // }
- // else
- // if(int(gl_FragCoord.x) < 120)
- // {
- // _GLF_color = vec4(A[25] / resolution.x, A[29] / resolution.y,
- // 1.0, 1.0);
- // }
- // else
- // if(int(gl_FragCoord.x) < 140)
- // {
- // _GLF_color = vec4(A[30] / resolution.x, A[34] / resolution.y,
- // 1.0, 1.0);
- // }
- // else
- // if(int(gl_FragCoord.x) < 160)
- // {
- // _GLF_color = vec4(A[35] / resolution.x, A[39] /
- // resolution.y, 1.0, 1.0);
- // }
- // else
- // if(int(gl_FragCoord.x) < 180)
- // {
- // _GLF_color = vec4(A[40] / resolution.x, A[44] /
- // resolution.y, 1.0, 1.0);
- // }
- // else
- // if(int(gl_FragCoord.x) < 180)
- // {
- // _GLF_color = vec4(A[45] / resolution.x, A[49] /
- // resolution.y, 1.0, 1.0);
- // }
- // else
- // {
- // discard;
- // }
- // }
- const std::string kTestShader3 = R"(
- OpCapability Shader
- %1 = OpExtInstImport "GLSL.std.450"
- OpMemoryModel Logical GLSL450
- OpEntryPoint Fragment %4 "main" %68 %100 %24
- OpExecutionMode %4 OriginUpperLeft
- OpSource ESSL 310
- OpName %4 "main"
- OpName %22 "buf0"
- OpMemberName %22 0 "resolution"
- OpName %24 ""
- OpName %46 "A"
- OpName %68 "gl_FragCoord"
- OpName %100 "_GLF_color"
- OpMemberDecorate %22 0 Offset 0
- OpDecorate %22 Block
- OpDecorate %24 DescriptorSet 0
- OpDecorate %24 Binding 0
- OpDecorate %37 RelaxedPrecision
- OpDecorate %38 RelaxedPrecision
- OpDecorate %55 RelaxedPrecision
- OpDecorate %68 BuiltIn FragCoord
- OpDecorate %83 RelaxedPrecision
- OpDecorate %91 RelaxedPrecision
- OpDecorate %100 Location 0
- OpDecorate %302 RelaxedPrecision
- OpDecorate %304 RelaxedPrecision
- %2 = OpTypeVoid
- %3 = OpTypeFunction %2
- %6 = OpTypeInt 32 1
- %9 = OpConstant %6 0
- %16 = OpConstant %6 200
- %17 = OpTypeBool
- %20 = OpTypeFloat 32
- %21 = OpTypeVector %20 2
- %22 = OpTypeStruct %21
- %23 = OpTypePointer Uniform %22
- %24 = OpVariable %23 Uniform
- %25 = OpTypeInt 32 0
- %26 = OpConstant %25 0
- %27 = OpTypePointer Uniform %20
- %35 = OpConstant %6 4
- %43 = OpConstant %25 50
- %44 = OpTypeArray %20 %43
- %45 = OpTypePointer Function %44
- %51 = OpTypePointer Function %20
- %54 = OpConstant %6 1
- %63 = OpConstant %6 50
- %66 = OpTypeVector %20 4
- %67 = OpTypePointer Input %66
- %68 = OpVariable %67 Input
- %69 = OpTypePointer Input %20
- %95 = OpConstant %6 20
- %99 = OpTypePointer Output %66
- %100 = OpVariable %99 Output
- %108 = OpConstant %25 1
- %112 = OpConstant %20 1
- %118 = OpConstant %6 40
- %122 = OpConstant %6 5
- %128 = OpConstant %6 9
- %139 = OpConstant %6 60
- %143 = OpConstant %6 10
- %149 = OpConstant %6 14
- %160 = OpConstant %6 80
- %164 = OpConstant %6 15
- %170 = OpConstant %6 19
- %181 = OpConstant %6 100
- %190 = OpConstant %6 24
- %201 = OpConstant %6 120
- %205 = OpConstant %6 25
- %211 = OpConstant %6 29
- %222 = OpConstant %6 140
- %226 = OpConstant %6 30
- %232 = OpConstant %6 34
- %243 = OpConstant %6 160
- %247 = OpConstant %6 35
- %253 = OpConstant %6 39
- %264 = OpConstant %6 180
- %273 = OpConstant %6 44
- %287 = OpConstant %6 45
- %293 = OpConstant %6 49
- %4 = OpFunction %2 None %3
- %5 = OpLabel
- %46 = OpVariable %45 Function
- OpBranch %10
- %10 = OpLabel
- %302 = OpPhi %6 %9 %5 %55 %42
- %18 = OpSLessThan %17 %302 %16
- OpLoopMerge %12 %42 None
- OpBranchConditional %18 %11 %12
- %11 = OpLabel
- %28 = OpAccessChain %27 %24 %9 %26
- %29 = OpLoad %20 %28
- %30 = OpConvertFToS %6 %29
- %31 = OpSGreaterThanEqual %17 %302 %30
- OpSelectionMerge %33 None
- OpBranchConditional %31 %32 %33
- %32 = OpLabel
- OpBranch %12
- %33 = OpLabel
- %37 = OpSDiv %6 %302 %35
- %38 = OpIMul %6 %35 %37
- %40 = OpIEqual %17 %38 %302
- OpBranchConditional %40 %41 %42
- %41 = OpLabel
- %50 = OpConvertSToF %20 %302
- %52 = OpAccessChain %51 %46 %37
- OpStore %52 %50
- OpBranch %42
- %42 = OpLabel
- %55 = OpIAdd %6 %302 %54
- OpBranch %10
- %12 = OpLabel
- OpBranch %57
- %57 = OpLabel
- %304 = OpPhi %6 %9 %12 %91 %80
- %64 = OpSLessThan %17 %304 %63
- OpLoopMerge %59 %80 None
- OpBranchConditional %64 %58 %59
- %58 = OpLabel
- %70 = OpAccessChain %69 %68 %26
- %71 = OpLoad %20 %70
- %72 = OpConvertFToS %6 %71
- %73 = OpSLessThan %17 %304 %72
- OpSelectionMerge %75 None
- OpBranchConditional %73 %74 %75
- %74 = OpLabel
- OpBranch %59
- %75 = OpLabel
- %78 = OpSGreaterThan %17 %304 %9
- OpBranchConditional %78 %79 %80
- %79 = OpLabel
- %83 = OpISub %6 %304 %54
- %84 = OpAccessChain %51 %46 %83
- %85 = OpLoad %20 %84
- %86 = OpAccessChain %51 %46 %304
- %87 = OpLoad %20 %86
- %88 = OpFAdd %20 %87 %85
- OpStore %86 %88
- OpBranch %80
- %80 = OpLabel
- %91 = OpIAdd %6 %304 %54
- OpBranch %57
- %59 = OpLabel
- %92 = OpAccessChain %69 %68 %26
- %93 = OpLoad %20 %92
- %94 = OpConvertFToS %6 %93
- %96 = OpSLessThan %17 %94 %95
- OpSelectionMerge %98 None
- OpBranchConditional %96 %97 %114
- %97 = OpLabel
- %101 = OpAccessChain %51 %46 %9
- %102 = OpLoad %20 %101
- %103 = OpAccessChain %27 %24 %9 %26
- %104 = OpLoad %20 %103
- %105 = OpFDiv %20 %102 %104
- %106 = OpAccessChain %51 %46 %35
- %107 = OpLoad %20 %106
- %109 = OpAccessChain %27 %24 %9 %108
- %110 = OpLoad %20 %109
- %111 = OpFDiv %20 %107 %110
- %113 = OpCompositeConstruct %66 %105 %111 %112 %112
- OpStore %100 %113
- OpBranch %98
- %114 = OpLabel
- %119 = OpSLessThan %17 %94 %118
- OpSelectionMerge %121 None
- OpBranchConditional %119 %120 %135
- %120 = OpLabel
- %123 = OpAccessChain %51 %46 %122
- %124 = OpLoad %20 %123
- %125 = OpAccessChain %27 %24 %9 %26
- %126 = OpLoad %20 %125
- %127 = OpFDiv %20 %124 %126
- %129 = OpAccessChain %51 %46 %128
- %130 = OpLoad %20 %129
- %131 = OpAccessChain %27 %24 %9 %108
- %132 = OpLoad %20 %131
- %133 = OpFDiv %20 %130 %132
- %134 = OpCompositeConstruct %66 %127 %133 %112 %112
- OpStore %100 %134
- OpBranch %121
- %135 = OpLabel
- %140 = OpSLessThan %17 %94 %139
- OpSelectionMerge %142 None
- OpBranchConditional %140 %141 %156
- %141 = OpLabel
- %144 = OpAccessChain %51 %46 %143
- %145 = OpLoad %20 %144
- %146 = OpAccessChain %27 %24 %9 %26
- %147 = OpLoad %20 %146
- %148 = OpFDiv %20 %145 %147
- %150 = OpAccessChain %51 %46 %149
- %151 = OpLoad %20 %150
- %152 = OpAccessChain %27 %24 %9 %108
- %153 = OpLoad %20 %152
- %154 = OpFDiv %20 %151 %153
- %155 = OpCompositeConstruct %66 %148 %154 %112 %112
- OpStore %100 %155
- OpBranch %142
- %156 = OpLabel
- %161 = OpSLessThan %17 %94 %160
- OpSelectionMerge %163 None
- OpBranchConditional %161 %162 %177
- %162 = OpLabel
- %165 = OpAccessChain %51 %46 %164
- %166 = OpLoad %20 %165
- %167 = OpAccessChain %27 %24 %9 %26
- %168 = OpLoad %20 %167
- %169 = OpFDiv %20 %166 %168
- %171 = OpAccessChain %51 %46 %170
- %172 = OpLoad %20 %171
- %173 = OpAccessChain %27 %24 %9 %108
- %174 = OpLoad %20 %173
- %175 = OpFDiv %20 %172 %174
- %176 = OpCompositeConstruct %66 %169 %175 %112 %112
- OpStore %100 %176
- OpBranch %163
- %177 = OpLabel
- %182 = OpSLessThan %17 %94 %181
- OpSelectionMerge %184 None
- OpBranchConditional %182 %183 %197
- %183 = OpLabel
- %185 = OpAccessChain %51 %46 %95
- %186 = OpLoad %20 %185
- %187 = OpAccessChain %27 %24 %9 %26
- %188 = OpLoad %20 %187
- %189 = OpFDiv %20 %186 %188
- %191 = OpAccessChain %51 %46 %190
- %192 = OpLoad %20 %191
- %193 = OpAccessChain %27 %24 %9 %108
- %194 = OpLoad %20 %193
- %195 = OpFDiv %20 %192 %194
- %196 = OpCompositeConstruct %66 %189 %195 %112 %112
- OpStore %100 %196
- OpBranch %184
- %197 = OpLabel
- %202 = OpSLessThan %17 %94 %201
- OpSelectionMerge %204 None
- OpBranchConditional %202 %203 %218
- %203 = OpLabel
- %206 = OpAccessChain %51 %46 %205
- %207 = OpLoad %20 %206
- %208 = OpAccessChain %27 %24 %9 %26
- %209 = OpLoad %20 %208
- %210 = OpFDiv %20 %207 %209
- %212 = OpAccessChain %51 %46 %211
- %213 = OpLoad %20 %212
- %214 = OpAccessChain %27 %24 %9 %108
- %215 = OpLoad %20 %214
- %216 = OpFDiv %20 %213 %215
- %217 = OpCompositeConstruct %66 %210 %216 %112 %112
- OpStore %100 %217
- OpBranch %204
- %218 = OpLabel
- %223 = OpSLessThan %17 %94 %222
- OpSelectionMerge %225 None
- OpBranchConditional %223 %224 %239
- %224 = OpLabel
- %227 = OpAccessChain %51 %46 %226
- %228 = OpLoad %20 %227
- %229 = OpAccessChain %27 %24 %9 %26
- %230 = OpLoad %20 %229
- %231 = OpFDiv %20 %228 %230
- %233 = OpAccessChain %51 %46 %232
- %234 = OpLoad %20 %233
- %235 = OpAccessChain %27 %24 %9 %108
- %236 = OpLoad %20 %235
- %237 = OpFDiv %20 %234 %236
- %238 = OpCompositeConstruct %66 %231 %237 %112 %112
- OpStore %100 %238
- OpBranch %225
- %239 = OpLabel
- %244 = OpSLessThan %17 %94 %243
- OpSelectionMerge %246 None
- OpBranchConditional %244 %245 %260
- %245 = OpLabel
- %248 = OpAccessChain %51 %46 %247
- %249 = OpLoad %20 %248
- %250 = OpAccessChain %27 %24 %9 %26
- %251 = OpLoad %20 %250
- %252 = OpFDiv %20 %249 %251
- %254 = OpAccessChain %51 %46 %253
- %255 = OpLoad %20 %254
- %256 = OpAccessChain %27 %24 %9 %108
- %257 = OpLoad %20 %256
- %258 = OpFDiv %20 %255 %257
- %259 = OpCompositeConstruct %66 %252 %258 %112 %112
- OpStore %100 %259
- OpBranch %246
- %260 = OpLabel
- %265 = OpSLessThan %17 %94 %264
- OpSelectionMerge %267 None
- OpBranchConditional %265 %266 %280
- %266 = OpLabel
- %268 = OpAccessChain %51 %46 %118
- %269 = OpLoad %20 %268
- %270 = OpAccessChain %27 %24 %9 %26
- %271 = OpLoad %20 %270
- %272 = OpFDiv %20 %269 %271
- %274 = OpAccessChain %51 %46 %273
- %275 = OpLoad %20 %274
- %276 = OpAccessChain %27 %24 %9 %108
- %277 = OpLoad %20 %276
- %278 = OpFDiv %20 %275 %277
- %279 = OpCompositeConstruct %66 %272 %278 %112 %112
- OpStore %100 %279
- OpBranch %267
- %280 = OpLabel
- OpSelectionMerge %285 None
- OpBranchConditional %265 %285 %300
- %285 = OpLabel
- %288 = OpAccessChain %51 %46 %287
- %289 = OpLoad %20 %288
- %290 = OpAccessChain %27 %24 %9 %26
- %291 = OpLoad %20 %290
- %292 = OpFDiv %20 %289 %291
- %294 = OpAccessChain %51 %46 %293
- %295 = OpLoad %20 %294
- %296 = OpAccessChain %27 %24 %9 %108
- %297 = OpLoad %20 %296
- %298 = OpFDiv %20 %295 %297
- %299 = OpCompositeConstruct %66 %292 %298 %112 %112
- OpStore %100 %299
- OpBranch %267
- %300 = OpLabel
- OpKill
- %267 = OpLabel
- OpBranch %246
- %246 = OpLabel
- OpBranch %225
- %225 = OpLabel
- OpBranch %204
- %204 = OpLabel
- OpBranch %184
- %184 = OpLabel
- OpBranch %163
- %163 = OpLabel
- OpBranch %142
- %142 = OpLabel
- OpBranch %121
- %121 = OpLabel
- OpBranch %98
- %98 = OpLabel
- OpReturn
- OpFunctionEnd
- )";
- // Abstract class exposing an interestingness function as a virtual method.
- class InterestingnessTest {
- public:
- virtual ~InterestingnessTest() = default;
- // Abstract method that subclasses should implement for specific notions of
- // interestingness. Its signature matches Shrinker::InterestingnessFunction.
- // Argument |binary| is the SPIR-V binary to be checked; |counter| is used for
- // debugging purposes.
- virtual bool Interesting(const std::vector<uint32_t>& binary,
- uint32_t counter) = 0;
- // Yields the Interesting instance method wrapped in a function object.
- Shrinker::InterestingnessFunction AsFunction() {
- return std::bind(&InterestingnessTest::Interesting, this,
- std::placeholders::_1, std::placeholders::_2);
- }
- };
- // A test that says all binaries are interesting.
- class AlwaysInteresting : public InterestingnessTest {
- public:
- bool Interesting(const std::vector<uint32_t>&, uint32_t) override {
- return true;
- }
- };
- // A test that says a binary is interesting first time round, and uninteresting
- // thereafter.
- class OnlyInterestingFirstTime : public InterestingnessTest {
- public:
- explicit OnlyInterestingFirstTime() : first_time_(true) {}
- bool Interesting(const std::vector<uint32_t>&, uint32_t) override {
- if (first_time_) {
- first_time_ = false;
- return true;
- }
- return false;
- }
- private:
- bool first_time_;
- };
- // A test that says a binary is interesting first time round, after which
- // interestingness ping pongs between false and true.
- class PingPong : public InterestingnessTest {
- public:
- explicit PingPong() : interesting_(false) {}
- bool Interesting(const std::vector<uint32_t>&, uint32_t) override {
- interesting_ = !interesting_;
- return interesting_;
- }
- private:
- bool interesting_;
- };
- // A test that says a binary is interesting first time round, thereafter
- // decides at random whether it is interesting. This allows the logic of the
- // shrinker to be exercised quite a bit.
- class InterestingThenRandom : public InterestingnessTest {
- public:
- InterestingThenRandom(const PseudoRandomGenerator& random_generator)
- : first_time_(true), random_generator_(random_generator) {}
- bool Interesting(const std::vector<uint32_t>&, uint32_t) override {
- if (first_time_) {
- first_time_ = false;
- return true;
- }
- return random_generator_.RandomBool();
- }
- private:
- bool first_time_;
- PseudoRandomGenerator random_generator_;
- };
- // |binary_in| and |initial_facts| are a SPIR-V binary and sequence of facts to
- // which |transformation_sequence_in| can be applied. Shrinking of
- // |transformation_sequence_in| gets performed with respect to
- // |interestingness_function|. If |expected_binary_out| is non-empty, it must
- // match the binary obtained by applying the final shrunk set of
- // transformations, in which case the number of such transformations should
- // equal |expected_transformations_out_size|.
- //
- // The |step_limit| parameter restricts the number of steps that the shrinker
- // will try; it can be set to something small for a faster (but less thorough)
- // test.
- //
- // The |validator_options| parameter provides validator options that should be
- // used during shrinking.
- void 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) {
- // Run the shrinker.
- auto shrinker_result =
- Shrinker(target_env, kConsoleMessageConsumer, binary_in, initial_facts,
- transformation_sequence_in, interestingness_function, step_limit,
- false, validator_options)
- .Run();
- ASSERT_TRUE(Shrinker::ShrinkerResultStatus::kComplete ==
- shrinker_result.status ||
- Shrinker::ShrinkerResultStatus::kStepLimitReached ==
- shrinker_result.status);
- // If a non-empty expected binary was provided, check that it matches the
- // result of shrinking and that the expected number of transformations remain.
- if (!expected_binary_out.empty()) {
- ASSERT_EQ(expected_binary_out, shrinker_result.transformed_binary);
- ASSERT_EQ(
- expected_transformations_out_size,
- static_cast<uint32_t>(
- shrinker_result.applied_transformations.transformation_size()));
- }
- }
- // Assembles the given |shader| text, and then:
- // - Runs the fuzzer with |seed| to yield a set of transformations
- // - Shrinks the transformation with various interestingness functions,
- // asserting some properties about the result each time
- void RunFuzzerAndShrinker(const std::string& shader,
- const protobufs::FactSequence& initial_facts,
- uint32_t seed) {
- const auto env = SPV_ENV_UNIVERSAL_1_5;
- std::vector<uint32_t> binary_in;
- SpirvTools t(env);
- t.SetMessageConsumer(kConsoleMessageConsumer);
- ASSERT_TRUE(t.Assemble(shader, &binary_in, kFuzzAssembleOption));
- ASSERT_TRUE(t.Validate(binary_in));
- std::vector<fuzzerutil::ModuleSupplier> donor_suppliers;
- for (auto donor : {&kTestShader1, &kTestShader2, &kTestShader3}) {
- donor_suppliers.emplace_back([donor]() {
- return BuildModule(env, kConsoleMessageConsumer, *donor,
- kFuzzAssembleOption);
- });
- }
- // Run the fuzzer and check that it successfully yields a valid binary.
- spvtools::ValidatorOptions validator_options;
- // Depending on the seed, decide whether to enable all passes and which
- // repeated pass manager to use.
- bool enable_all_passes = (seed % 4) == 0;
- Fuzzer::RepeatedPassStrategy repeated_pass_strategy;
- if ((seed % 3) == 0) {
- repeated_pass_strategy = Fuzzer::RepeatedPassStrategy::kSimple;
- } else if ((seed % 3) == 1) {
- repeated_pass_strategy =
- Fuzzer::RepeatedPassStrategy::kLoopedWithRecommendations;
- } else {
- repeated_pass_strategy =
- Fuzzer::RepeatedPassStrategy::kRandomWithRecommendations;
- }
- auto fuzzer_result =
- Fuzzer(env, kConsoleMessageConsumer, binary_in, initial_facts,
- donor_suppliers, MakeUnique<PseudoRandomGenerator>(seed),
- enable_all_passes, repeated_pass_strategy, true, validator_options)
- .Run();
- ASSERT_EQ(Fuzzer::FuzzerResultStatus::kComplete, fuzzer_result.status);
- ASSERT_TRUE(t.Validate(fuzzer_result.transformed_binary));
- const uint32_t kReasonableStepLimit = 50;
- const uint32_t kSmallStepLimit = 20;
- // With the AlwaysInteresting test, we should quickly shrink to the original
- // binary with no transformations remaining.
- RunAndCheckShrinker(env, binary_in, initial_facts,
- fuzzer_result.applied_transformations,
- AlwaysInteresting().AsFunction(), binary_in, 0,
- kReasonableStepLimit, validator_options);
- // With the OnlyInterestingFirstTime test, no shrinking should be achieved.
- RunAndCheckShrinker(
- env, binary_in, initial_facts, fuzzer_result.applied_transformations,
- OnlyInterestingFirstTime().AsFunction(), fuzzer_result.transformed_binary,
- static_cast<uint32_t>(
- fuzzer_result.applied_transformations.transformation_size()),
- kReasonableStepLimit, validator_options);
- // The PingPong test is unpredictable; passing an empty expected binary
- // means that we don't check anything beyond that shrinking completes
- // successfully.
- RunAndCheckShrinker(
- env, binary_in, initial_facts, fuzzer_result.applied_transformations,
- PingPong().AsFunction(), {}, 0, kSmallStepLimit, validator_options);
- // The InterestingThenRandom test is unpredictable; passing an empty
- // expected binary means that we do not check anything about shrinking
- // results.
- RunAndCheckShrinker(
- env, binary_in, initial_facts, fuzzer_result.applied_transformations,
- InterestingThenRandom(PseudoRandomGenerator(seed)).AsFunction(), {}, 0,
- kSmallStepLimit, validator_options);
- }
- TEST(FuzzerShrinkerTest, Miscellaneous1) {
- RunFuzzerAndShrinker(kTestShader1, protobufs::FactSequence(), 2);
- }
- TEST(FuzzerShrinkerTest, Miscellaneous2) {
- RunFuzzerAndShrinker(kTestShader2, protobufs::FactSequence(), 19);
- }
- TEST(FuzzerShrinkerTest, Miscellaneous3) {
- // Add the facts "resolution.x == 250" and "resolution.y == 100".
- protobufs::FactSequence facts;
- {
- protobufs::FactConstantUniform resolution_x_eq_250;
- *resolution_x_eq_250.mutable_uniform_buffer_element_descriptor() =
- MakeUniformBufferElementDescriptor(0, 0, {0, 0});
- *resolution_x_eq_250.mutable_constant_word()->Add() = 250;
- protobufs::Fact temp;
- *temp.mutable_constant_uniform_fact() = resolution_x_eq_250;
- *facts.mutable_fact()->Add() = temp;
- }
- {
- protobufs::FactConstantUniform resolution_y_eq_100;
- *resolution_y_eq_100.mutable_uniform_buffer_element_descriptor() =
- MakeUniformBufferElementDescriptor(0, 0, {0, 1});
- *resolution_y_eq_100.mutable_constant_word()->Add() = 100;
- protobufs::Fact temp;
- *temp.mutable_constant_uniform_fact() = resolution_y_eq_100;
- *facts.mutable_fact()->Add() = temp;
- }
- // Also add an invalid fact, which should be ignored.
- {
- protobufs::FactConstantUniform bad_fact;
- // The descriptor set, binding and indices used here deliberately make no
- // sense.
- *bad_fact.mutable_uniform_buffer_element_descriptor() =
- MakeUniformBufferElementDescriptor(22, 33, {44, 55});
- *bad_fact.mutable_constant_word()->Add() = 100;
- protobufs::Fact temp;
- *temp.mutable_constant_uniform_fact() = bad_fact;
- *facts.mutable_fact()->Add() = temp;
- }
- // Do 2 fuzzer runs, starting from an initial seed of 194 (seed value chosen
- // arbitrarily).
- RunFuzzerAndShrinker(kTestShader3, facts, 194);
- }
- } // namespace
- } // namespace fuzz
- } // namespace spvtools
|