// 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 "gtest/gtest.h"
#include "source/fuzz/fuzzer.h"
#include "source/fuzz/fuzzer_util.h"
#include "source/fuzz/pseudo_random_generator.h"
#include "source/fuzz/replayer.h"
#include "source/fuzz/uniform_buffer_element_descriptor.h"
#include "test/fuzz/fuzz_test_util.h"

namespace spvtools {
namespace fuzz {
namespace {

const uint32_t kNumFuzzerRuns = 20;

// The 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 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 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
  )";

// The SPIR-V comes from the 'matrices_smart_loops' GLSL shader that ships
// with GraphicsFuzz.

const std::string kTestShader4 = R"(
               OpCapability Shader
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Fragment %4 "main" %327 %363 %65 %70 %80 %90 %99 %108 %117 %126 %135 %144 %333
               OpExecutionMode %4 OriginUpperLeft
               OpSource ESSL 310
               OpName %4 "main"
               OpName %8 "matrix_number"
               OpName %12 "cols"
               OpName %23 "rows"
               OpName %31 "c"
               OpName %41 "r"
               OpName %65 "m22"
               OpName %68 "buf0"
               OpMemberName %68 0 "one"
               OpName %70 ""
               OpName %80 "m23"
               OpName %90 "m24"
               OpName %99 "m32"
               OpName %108 "m33"
               OpName %117 "m34"
               OpName %126 "m42"
               OpName %135 "m43"
               OpName %144 "m44"
               OpName %164 "sum_index"
               OpName %165 "cols"
               OpName %173 "rows"
               OpName %184 "sums"
               OpName %189 "c"
               OpName %198 "r"
               OpName %325 "region_x"
               OpName %327 "gl_FragCoord"
               OpName %331 "buf1"
               OpMemberName %331 0 "resolution"
               OpName %333 ""
               OpName %340 "region_y"
               OpName %348 "overall_region"
               OpName %363 "_GLF_color"
               OpDecorate %8 RelaxedPrecision
               OpDecorate %12 RelaxedPrecision
               OpDecorate %19 RelaxedPrecision
               OpDecorate %23 RelaxedPrecision
               OpDecorate %29 RelaxedPrecision
               OpDecorate %31 RelaxedPrecision
               OpDecorate %38 RelaxedPrecision
               OpDecorate %39 RelaxedPrecision
               OpDecorate %41 RelaxedPrecision
               OpDecorate %47 RelaxedPrecision
               OpDecorate %48 RelaxedPrecision
               OpDecorate %50 RelaxedPrecision
               OpDecorate %66 RelaxedPrecision
               OpDecorate %67 RelaxedPrecision
               OpMemberDecorate %68 0 Offset 0
               OpDecorate %68 Block
               OpDecorate %70 DescriptorSet 0
               OpDecorate %70 Binding 0
               OpDecorate %81 RelaxedPrecision
               OpDecorate %82 RelaxedPrecision
               OpDecorate %91 RelaxedPrecision
               OpDecorate %92 RelaxedPrecision
               OpDecorate %100 RelaxedPrecision
               OpDecorate %101 RelaxedPrecision
               OpDecorate %109 RelaxedPrecision
               OpDecorate %110 RelaxedPrecision
               OpDecorate %118 RelaxedPrecision
               OpDecorate %119 RelaxedPrecision
               OpDecorate %127 RelaxedPrecision
               OpDecorate %128 RelaxedPrecision
               OpDecorate %136 RelaxedPrecision
               OpDecorate %137 RelaxedPrecision
               OpDecorate %145 RelaxedPrecision
               OpDecorate %146 RelaxedPrecision
               OpDecorate %152 RelaxedPrecision
               OpDecorate %154 RelaxedPrecision
               OpDecorate %155 RelaxedPrecision
               OpDecorate %156 RelaxedPrecision
               OpDecorate %157 RelaxedPrecision
               OpDecorate %159 RelaxedPrecision
               OpDecorate %160 RelaxedPrecision
               OpDecorate %161 RelaxedPrecision
               OpDecorate %162 RelaxedPrecision
               OpDecorate %163 RelaxedPrecision
               OpDecorate %164 RelaxedPrecision
               OpDecorate %165 RelaxedPrecision
               OpDecorate %171 RelaxedPrecision
               OpDecorate %173 RelaxedPrecision
               OpDecorate %179 RelaxedPrecision
               OpDecorate %185 RelaxedPrecision
               OpDecorate %189 RelaxedPrecision
               OpDecorate %195 RelaxedPrecision
               OpDecorate %196 RelaxedPrecision
               OpDecorate %198 RelaxedPrecision
               OpDecorate %204 RelaxedPrecision
               OpDecorate %205 RelaxedPrecision
               OpDecorate %207 RelaxedPrecision
               OpDecorate %218 RelaxedPrecision
               OpDecorate %219 RelaxedPrecision
               OpDecorate %220 RelaxedPrecision
               OpDecorate %228 RelaxedPrecision
               OpDecorate %229 RelaxedPrecision
               OpDecorate %230 RelaxedPrecision
               OpDecorate %238 RelaxedPrecision
               OpDecorate %239 RelaxedPrecision
               OpDecorate %240 RelaxedPrecision
               OpDecorate %248 RelaxedPrecision
               OpDecorate %249 RelaxedPrecision
               OpDecorate %250 RelaxedPrecision
               OpDecorate %258 RelaxedPrecision
               OpDecorate %259 RelaxedPrecision
               OpDecorate %260 RelaxedPrecision
               OpDecorate %268 RelaxedPrecision
               OpDecorate %269 RelaxedPrecision
               OpDecorate %270 RelaxedPrecision
               OpDecorate %278 RelaxedPrecision
               OpDecorate %279 RelaxedPrecision
               OpDecorate %280 RelaxedPrecision
               OpDecorate %288 RelaxedPrecision
               OpDecorate %289 RelaxedPrecision
               OpDecorate %290 RelaxedPrecision
               OpDecorate %298 RelaxedPrecision
               OpDecorate %299 RelaxedPrecision
               OpDecorate %300 RelaxedPrecision
               OpDecorate %309 RelaxedPrecision
               OpDecorate %310 RelaxedPrecision
               OpDecorate %311 RelaxedPrecision
               OpDecorate %312 RelaxedPrecision
               OpDecorate %313 RelaxedPrecision
               OpDecorate %319 RelaxedPrecision
               OpDecorate %320 RelaxedPrecision
               OpDecorate %321 RelaxedPrecision
               OpDecorate %322 RelaxedPrecision
               OpDecorate %323 RelaxedPrecision
               OpDecorate %324 RelaxedPrecision
               OpDecorate %325 RelaxedPrecision
               OpDecorate %327 BuiltIn FragCoord
               OpMemberDecorate %331 0 Offset 0
               OpDecorate %331 Block
               OpDecorate %333 DescriptorSet 0
               OpDecorate %333 Binding 1
               OpDecorate %339 RelaxedPrecision
               OpDecorate %340 RelaxedPrecision
               OpDecorate %347 RelaxedPrecision
               OpDecorate %348 RelaxedPrecision
               OpDecorate %349 RelaxedPrecision
               OpDecorate %351 RelaxedPrecision
               OpDecorate %352 RelaxedPrecision
               OpDecorate %353 RelaxedPrecision
               OpDecorate %354 RelaxedPrecision
               OpDecorate %356 RelaxedPrecision
               OpDecorate %363 Location 0
               OpDecorate %364 RelaxedPrecision
          %2 = OpTypeVoid
          %3 = OpTypeFunction %2
          %6 = OpTypeInt 32 0
          %7 = OpTypePointer Function %6
          %9 = OpConstant %6 0
         %10 = OpTypeInt 32 1
         %11 = OpTypePointer Function %10
         %13 = OpConstant %10 2
         %20 = OpConstant %10 4
         %21 = OpTypeBool
         %32 = OpConstant %10 0
         %61 = OpTypeFloat 32
         %62 = OpTypeVector %61 2
         %63 = OpTypeMatrix %62 2
         %64 = OpTypePointer Private %63
         %65 = OpVariable %64 Private
         %68 = OpTypeStruct %61
         %69 = OpTypePointer Uniform %68
         %70 = OpVariable %69 Uniform
         %71 = OpTypePointer Uniform %61
         %74 = OpTypePointer Private %61
         %77 = OpTypeVector %61 3
         %78 = OpTypeMatrix %77 2
         %79 = OpTypePointer Private %78
         %80 = OpVariable %79 Private
         %87 = OpTypeVector %61 4
         %88 = OpTypeMatrix %87 2
         %89 = OpTypePointer Private %88
         %90 = OpVariable %89 Private
         %97 = OpTypeMatrix %62 3
         %98 = OpTypePointer Private %97
         %99 = OpVariable %98 Private
        %106 = OpTypeMatrix %77 3
        %107 = OpTypePointer Private %106
        %108 = OpVariable %107 Private
        %115 = OpTypeMatrix %87 3
        %116 = OpTypePointer Private %115
        %117 = OpVariable %116 Private
        %124 = OpTypeMatrix %62 4
        %125 = OpTypePointer Private %124
        %126 = OpVariable %125 Private
        %133 = OpTypeMatrix %77 4
        %134 = OpTypePointer Private %133
        %135 = OpVariable %134 Private
        %142 = OpTypeMatrix %87 4
        %143 = OpTypePointer Private %142
        %144 = OpVariable %143 Private
        %153 = OpConstant %10 1
        %158 = OpConstant %6 1
        %181 = OpConstant %6 9
        %182 = OpTypeArray %61 %181
        %183 = OpTypePointer Function %182
        %186 = OpConstant %61 0
        %187 = OpTypePointer Function %61
        %314 = OpConstant %61 16
        %326 = OpTypePointer Input %87
        %327 = OpVariable %326 Input
        %328 = OpTypePointer Input %61
        %331 = OpTypeStruct %62
        %332 = OpTypePointer Uniform %331
        %333 = OpVariable %332 Uniform
        %336 = OpConstant %61 3
        %350 = OpConstant %10 3
        %357 = OpConstant %10 9
        %362 = OpTypePointer Output %87
        %363 = OpVariable %362 Output
        %368 = OpConstant %61 1
        %374 = OpConstantComposite %87 %186 %186 %186 %368
          %4 = OpFunction %2 None %3
          %5 = OpLabel
          %8 = OpVariable %7 Function
         %12 = OpVariable %11 Function
         %23 = OpVariable %11 Function
         %31 = OpVariable %11 Function
         %41 = OpVariable %11 Function
        %164 = OpVariable %11 Function
        %165 = OpVariable %11 Function
        %173 = OpVariable %11 Function
        %184 = OpVariable %183 Function
        %189 = OpVariable %11 Function
        %198 = OpVariable %11 Function
        %325 = OpVariable %11 Function
        %340 = OpVariable %11 Function
        %348 = OpVariable %11 Function
               OpStore %8 %9
               OpStore %12 %13
               OpBranch %14
         %14 = OpLabel
               OpLoopMerge %16 %17 None
               OpBranch %18
         %18 = OpLabel
         %19 = OpLoad %10 %12
         %22 = OpSLessThanEqual %21 %19 %20
               OpBranchConditional %22 %15 %16
         %15 = OpLabel
               OpStore %23 %13
               OpBranch %24
         %24 = OpLabel
               OpLoopMerge %26 %27 None
               OpBranch %28
         %28 = OpLabel
         %29 = OpLoad %10 %23
         %30 = OpSLessThanEqual %21 %29 %20
               OpBranchConditional %30 %25 %26
         %25 = OpLabel
               OpStore %31 %32
               OpBranch %33
         %33 = OpLabel
               OpLoopMerge %35 %36 None
               OpBranch %37
         %37 = OpLabel
         %38 = OpLoad %10 %31
         %39 = OpLoad %10 %12
         %40 = OpSLessThan %21 %38 %39
               OpBranchConditional %40 %34 %35
         %34 = OpLabel
               OpStore %41 %32
               OpBranch %42
         %42 = OpLabel
               OpLoopMerge %44 %45 None
               OpBranch %46
         %46 = OpLabel
         %47 = OpLoad %10 %41
         %48 = OpLoad %10 %23
         %49 = OpSLessThan %21 %47 %48
               OpBranchConditional %49 %43 %44
         %43 = OpLabel
         %50 = OpLoad %6 %8
               OpSelectionMerge %60 None
               OpSwitch %50 %60 0 %51 1 %52 2 %53 3 %54 4 %55 5 %56 6 %57 7 %58 8 %59
         %51 = OpLabel
         %66 = OpLoad %10 %31
         %67 = OpLoad %10 %41
         %72 = OpAccessChain %71 %70 %32
         %73 = OpLoad %61 %72
         %75 = OpAccessChain %74 %65 %66 %67
               OpStore %75 %73
               OpBranch %60
         %52 = OpLabel
         %81 = OpLoad %10 %31
         %82 = OpLoad %10 %41
         %83 = OpAccessChain %71 %70 %32
         %84 = OpLoad %61 %83
         %85 = OpAccessChain %74 %80 %81 %82
               OpStore %85 %84
               OpBranch %60
         %53 = OpLabel
         %91 = OpLoad %10 %31
         %92 = OpLoad %10 %41
         %93 = OpAccessChain %71 %70 %32
         %94 = OpLoad %61 %93
         %95 = OpAccessChain %74 %90 %91 %92
               OpStore %95 %94
               OpBranch %60
         %54 = OpLabel
        %100 = OpLoad %10 %31
        %101 = OpLoad %10 %41
        %102 = OpAccessChain %71 %70 %32
        %103 = OpLoad %61 %102
        %104 = OpAccessChain %74 %99 %100 %101
               OpStore %104 %103
               OpBranch %60
         %55 = OpLabel
        %109 = OpLoad %10 %31
        %110 = OpLoad %10 %41
        %111 = OpAccessChain %71 %70 %32
        %112 = OpLoad %61 %111
        %113 = OpAccessChain %74 %108 %109 %110
               OpStore %113 %112
               OpBranch %60
         %56 = OpLabel
        %118 = OpLoad %10 %31
        %119 = OpLoad %10 %41
        %120 = OpAccessChain %71 %70 %32
        %121 = OpLoad %61 %120
        %122 = OpAccessChain %74 %117 %118 %119
               OpStore %122 %121
               OpBranch %60
         %57 = OpLabel
        %127 = OpLoad %10 %31
        %128 = OpLoad %10 %41
        %129 = OpAccessChain %71 %70 %32
        %130 = OpLoad %61 %129
        %131 = OpAccessChain %74 %126 %127 %128
               OpStore %131 %130
               OpBranch %60
         %58 = OpLabel
        %136 = OpLoad %10 %31
        %137 = OpLoad %10 %41
        %138 = OpAccessChain %71 %70 %32
        %139 = OpLoad %61 %138
        %140 = OpAccessChain %74 %135 %136 %137
               OpStore %140 %139
               OpBranch %60
         %59 = OpLabel
        %145 = OpLoad %10 %31
        %146 = OpLoad %10 %41
        %147 = OpAccessChain %71 %70 %32
        %148 = OpLoad %61 %147
        %149 = OpAccessChain %74 %144 %145 %146
               OpStore %149 %148
               OpBranch %60
         %60 = OpLabel
               OpBranch %45
         %45 = OpLabel
        %152 = OpLoad %10 %41
        %154 = OpIAdd %10 %152 %153
               OpStore %41 %154
               OpBranch %42
         %44 = OpLabel
               OpBranch %36
         %36 = OpLabel
        %155 = OpLoad %10 %31
        %156 = OpIAdd %10 %155 %153
               OpStore %31 %156
               OpBranch %33
         %35 = OpLabel
        %157 = OpLoad %6 %8
        %159 = OpIAdd %6 %157 %158
               OpStore %8 %159
               OpBranch %27
         %27 = OpLabel
        %160 = OpLoad %10 %23
        %161 = OpIAdd %10 %160 %153
               OpStore %23 %161
               OpBranch %24
         %26 = OpLabel
               OpBranch %17
         %17 = OpLabel
        %162 = OpLoad %10 %12
        %163 = OpIAdd %10 %162 %153
               OpStore %12 %163
               OpBranch %14
         %16 = OpLabel
               OpStore %164 %32
               OpStore %165 %13
               OpBranch %166
        %166 = OpLabel
               OpLoopMerge %168 %169 None
               OpBranch %170
        %170 = OpLabel
        %171 = OpLoad %10 %165
        %172 = OpSLessThanEqual %21 %171 %20
               OpBranchConditional %172 %167 %168
        %167 = OpLabel
               OpStore %173 %13
               OpBranch %174
        %174 = OpLabel
               OpLoopMerge %176 %177 None
               OpBranch %178
        %178 = OpLabel
        %179 = OpLoad %10 %173
        %180 = OpSLessThanEqual %21 %179 %20
               OpBranchConditional %180 %175 %176
        %175 = OpLabel
        %185 = OpLoad %10 %164
        %188 = OpAccessChain %187 %184 %185
               OpStore %188 %186
               OpStore %189 %32
               OpBranch %190
        %190 = OpLabel
               OpLoopMerge %192 %193 None
               OpBranch %194
        %194 = OpLabel
        %195 = OpLoad %10 %189
        %196 = OpLoad %10 %165
        %197 = OpSLessThan %21 %195 %196
               OpBranchConditional %197 %191 %192
        %191 = OpLabel
               OpStore %198 %32
               OpBranch %199
        %199 = OpLabel
               OpLoopMerge %201 %202 None
               OpBranch %203
        %203 = OpLabel
        %204 = OpLoad %10 %198
        %205 = OpLoad %10 %173
        %206 = OpSLessThan %21 %204 %205
               OpBranchConditional %206 %200 %201
        %200 = OpLabel
        %207 = OpLoad %10 %164
               OpSelectionMerge %217 None
               OpSwitch %207 %217 0 %208 1 %209 2 %210 3 %211 4 %212 5 %213 6 %214 7 %215 8 %216
        %208 = OpLabel
        %218 = OpLoad %10 %164
        %219 = OpLoad %10 %189
        %220 = OpLoad %10 %198
        %221 = OpAccessChain %74 %65 %219 %220
        %222 = OpLoad %61 %221
        %223 = OpAccessChain %187 %184 %218
        %224 = OpLoad %61 %223
        %225 = OpFAdd %61 %224 %222
        %226 = OpAccessChain %187 %184 %218
               OpStore %226 %225
               OpBranch %217
        %209 = OpLabel
        %228 = OpLoad %10 %164
        %229 = OpLoad %10 %189
        %230 = OpLoad %10 %198
        %231 = OpAccessChain %74 %80 %229 %230
        %232 = OpLoad %61 %231
        %233 = OpAccessChain %187 %184 %228
        %234 = OpLoad %61 %233
        %235 = OpFAdd %61 %234 %232
        %236 = OpAccessChain %187 %184 %228
               OpStore %236 %235
               OpBranch %217
        %210 = OpLabel
        %238 = OpLoad %10 %164
        %239 = OpLoad %10 %189
        %240 = OpLoad %10 %198
        %241 = OpAccessChain %74 %90 %239 %240
        %242 = OpLoad %61 %241
        %243 = OpAccessChain %187 %184 %238
        %244 = OpLoad %61 %243
        %245 = OpFAdd %61 %244 %242
        %246 = OpAccessChain %187 %184 %238
               OpStore %246 %245
               OpBranch %217
        %211 = OpLabel
        %248 = OpLoad %10 %164
        %249 = OpLoad %10 %189
        %250 = OpLoad %10 %198
        %251 = OpAccessChain %74 %99 %249 %250
        %252 = OpLoad %61 %251
        %253 = OpAccessChain %187 %184 %248
        %254 = OpLoad %61 %253
        %255 = OpFAdd %61 %254 %252
        %256 = OpAccessChain %187 %184 %248
               OpStore %256 %255
               OpBranch %217
        %212 = OpLabel
        %258 = OpLoad %10 %164
        %259 = OpLoad %10 %189
        %260 = OpLoad %10 %198
        %261 = OpAccessChain %74 %108 %259 %260
        %262 = OpLoad %61 %261
        %263 = OpAccessChain %187 %184 %258
        %264 = OpLoad %61 %263
        %265 = OpFAdd %61 %264 %262
        %266 = OpAccessChain %187 %184 %258
               OpStore %266 %265
               OpBranch %217
        %213 = OpLabel
        %268 = OpLoad %10 %164
        %269 = OpLoad %10 %189
        %270 = OpLoad %10 %198
        %271 = OpAccessChain %74 %117 %269 %270
        %272 = OpLoad %61 %271
        %273 = OpAccessChain %187 %184 %268
        %274 = OpLoad %61 %273
        %275 = OpFAdd %61 %274 %272
        %276 = OpAccessChain %187 %184 %268
               OpStore %276 %275
               OpBranch %217
        %214 = OpLabel
        %278 = OpLoad %10 %164
        %279 = OpLoad %10 %189
        %280 = OpLoad %10 %198
        %281 = OpAccessChain %74 %126 %279 %280
        %282 = OpLoad %61 %281
        %283 = OpAccessChain %187 %184 %278
        %284 = OpLoad %61 %283
        %285 = OpFAdd %61 %284 %282
        %286 = OpAccessChain %187 %184 %278
               OpStore %286 %285
               OpBranch %217
        %215 = OpLabel
        %288 = OpLoad %10 %164
        %289 = OpLoad %10 %189
        %290 = OpLoad %10 %198
        %291 = OpAccessChain %74 %135 %289 %290
        %292 = OpLoad %61 %291
        %293 = OpAccessChain %187 %184 %288
        %294 = OpLoad %61 %293
        %295 = OpFAdd %61 %294 %292
        %296 = OpAccessChain %187 %184 %288
               OpStore %296 %295
               OpBranch %217
        %216 = OpLabel
        %298 = OpLoad %10 %164
        %299 = OpLoad %10 %189
        %300 = OpLoad %10 %198
        %301 = OpAccessChain %74 %144 %299 %300
        %302 = OpLoad %61 %301
        %303 = OpAccessChain %187 %184 %298
        %304 = OpLoad %61 %303
        %305 = OpFAdd %61 %304 %302
        %306 = OpAccessChain %187 %184 %298
               OpStore %306 %305
               OpBranch %217
        %217 = OpLabel
               OpBranch %202
        %202 = OpLabel
        %309 = OpLoad %10 %198
        %310 = OpIAdd %10 %309 %153
               OpStore %198 %310
               OpBranch %199
        %201 = OpLabel
               OpBranch %193
        %193 = OpLabel
        %311 = OpLoad %10 %189
        %312 = OpIAdd %10 %311 %153
               OpStore %189 %312
               OpBranch %190
        %192 = OpLabel
        %313 = OpLoad %10 %164
        %315 = OpAccessChain %187 %184 %313
        %316 = OpLoad %61 %315
        %317 = OpFDiv %61 %316 %314
        %318 = OpAccessChain %187 %184 %313
               OpStore %318 %317
        %319 = OpLoad %10 %164
        %320 = OpIAdd %10 %319 %153
               OpStore %164 %320
               OpBranch %177
        %177 = OpLabel
        %321 = OpLoad %10 %173
        %322 = OpIAdd %10 %321 %153
               OpStore %173 %322
               OpBranch %174
        %176 = OpLabel
               OpBranch %169
        %169 = OpLabel
        %323 = OpLoad %10 %165
        %324 = OpIAdd %10 %323 %153
               OpStore %165 %324
               OpBranch %166
        %168 = OpLabel
        %329 = OpAccessChain %328 %327 %9
        %330 = OpLoad %61 %329
        %334 = OpAccessChain %71 %333 %32 %9
        %335 = OpLoad %61 %334
        %337 = OpFDiv %61 %335 %336
        %338 = OpFDiv %61 %330 %337
        %339 = OpConvertFToS %10 %338
               OpStore %325 %339
        %341 = OpAccessChain %328 %327 %158
        %342 = OpLoad %61 %341
        %343 = OpAccessChain %71 %333 %32 %9
        %344 = OpLoad %61 %343
        %345 = OpFDiv %61 %344 %336
        %346 = OpFDiv %61 %342 %345
        %347 = OpConvertFToS %10 %346
               OpStore %340 %347
        %349 = OpLoad %10 %340
        %351 = OpIMul %10 %349 %350
        %352 = OpLoad %10 %325
        %353 = OpIAdd %10 %351 %352
               OpStore %348 %353
        %354 = OpLoad %10 %348
        %355 = OpSGreaterThan %21 %354 %32
        %356 = OpLoad %10 %348
        %358 = OpSLessThan %21 %356 %357
        %359 = OpLogicalAnd %21 %355 %358
               OpSelectionMerge %361 None
               OpBranchConditional %359 %360 %373
        %360 = OpLabel
        %364 = OpLoad %10 %348
        %365 = OpAccessChain %187 %184 %364
        %366 = OpLoad %61 %365
        %367 = OpCompositeConstruct %77 %366 %366 %366
        %369 = OpCompositeExtract %61 %367 0
        %370 = OpCompositeExtract %61 %367 1
        %371 = OpCompositeExtract %61 %367 2
        %372 = OpCompositeConstruct %87 %369 %370 %371 %368
               OpStore %363 %372
               OpBranch %361
        %373 = OpLabel
               OpStore %363 %374
               OpBranch %361
        %361 = OpLabel
               OpReturn
               OpFunctionEnd
  )";

// The SPIR-V comes from the following GLSL:
//
// #version 310 es
// precision highp float;
//
// layout(location = 0) out vec4 color;
//
// void main()
// {
//   color = vec4(1.0, 0.0, 0.0, 1.0);
// }

const std::string kTestShader5 = R"(
               OpCapability Shader
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Fragment %4 "main" %9
               OpExecutionMode %4 OriginUpperLeft
               OpSource ESSL 310
               OpName %4 "main"
               OpName %9 "color"
               OpDecorate %9 Location 0
          %2 = OpTypeVoid
          %3 = OpTypeFunction %2
          %6 = OpTypeFloat 32
          %7 = OpTypeVector %6 4
          %8 = OpTypePointer Output %7
          %9 = OpVariable %8 Output
         %10 = OpConstant %6 1
         %11 = OpConstant %6 0
         %12 = OpConstantComposite %7 %10 %11 %11 %10
          %4 = OpFunction %2 None %3
          %5 = OpLabel
               OpStore %9 %12
               OpReturn
               OpFunctionEnd
  )";

// Some miscellaneous SPIR-V.

const std::string kTestShader6 = R"(
               OpCapability Shader
               OpCapability SampledBuffer
               OpCapability ImageBuffer
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Fragment %2 "main" %40 %41
               OpExecutionMode %2 OriginUpperLeft
               OpSource GLSL 450
               OpDecorate %40 DescriptorSet 0
               OpDecorate %40 Binding 69
               OpDecorate %41 DescriptorSet 0
               OpDecorate %41 Binding 1
         %54 = OpTypeFloat 32
         %76 = OpTypeVector %54 4
         %55 = OpConstant %54 0
         %56 = OpTypeVector %54 3
         %94 = OpTypeVector %54 2
        %112 = OpConstantComposite %94 %55 %55
         %57 = OpConstantComposite %56 %55 %55 %55
         %15 = OpTypeImage %54 2D 2 0 0 1 Unknown
        %114 = OpTypePointer UniformConstant %15
         %38 = OpTypeSampler
        %125 = OpTypePointer UniformConstant %38
        %132 = OpTypeVoid
        %133 = OpTypeFunction %132
         %45 = OpTypeSampledImage %15
         %40 = OpVariable %114 UniformConstant
         %41 = OpVariable %125 UniformConstant
          %2 = OpFunction %132 None %133
        %164 = OpLabel
        %184 = OpLoad %15 %40
        %213 = OpLoad %38 %41
        %216 = OpSampledImage %45 %184 %213
        %217 = OpImageSampleImplicitLod %76 %216 %112 Bias %55
               OpReturn
               OpFunctionEnd
  )";

// A virtually empty piece of SPIR-V.

const std::string kTestShader7 = R"(
               OpCapability Shader
          %1 = OpExtInstImport "GLSL.std.450"
               OpMemoryModel Logical GLSL450
               OpEntryPoint Fragment %4 "main"
               OpExecutionMode %4 OriginUpperLeft
               OpSource ESSL 320
          %2 = OpTypeVoid
          %3 = OpTypeFunction %2
          %4 = OpFunction %2 None %3
          %5 = OpLabel
               OpReturn
               OpFunctionEnd
  )";

void AddConstantUniformFact(protobufs::FactSequence* facts,
                            uint32_t descriptor_set, uint32_t binding,
                            std::vector<uint32_t>&& indices, uint32_t value) {
  protobufs::FactConstantUniform fact;
  *fact.mutable_uniform_buffer_element_descriptor() =
      MakeUniformBufferElementDescriptor(descriptor_set, binding,
                                         std::move(indices));
  *fact.mutable_constant_word()->Add() = value;
  protobufs::Fact temp;
  *temp.mutable_constant_uniform_fact() = fact;
  *facts->mutable_fact()->Add() = temp;
}

// Reinterpret the bits of |value| as a 32-bit unsigned int
uint32_t FloatBitsAsUint(float value) {
  uint32_t result;
  memcpy(&result, &value, sizeof(float));
  return result;
}

// Assembles the given |shader| text, and then runs the fuzzer |num_runs|
// times, using successive seeds starting from |initial_seed|.  Checks that
// the binary produced after each fuzzer run is valid, and that replaying
// the transformations that were applied during fuzzing leads to an
// identical binary.
void RunFuzzerAndReplayer(const std::string& shader,
                          const protobufs::FactSequence& initial_facts,
                          uint32_t initial_seed, uint32_t num_runs) {
  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, &kTestShader4,
                     &kTestShader5, &kTestShader6}) {
    donor_suppliers.emplace_back([donor]() {
      return BuildModule(env, kConsoleMessageConsumer, *donor,
                         kFuzzAssembleOption);
    });
  }

  std::vector<RepeatedPassStrategy> strategies{
      RepeatedPassStrategy::kSimple,
      RepeatedPassStrategy::kLoopedWithRecommendations,
      RepeatedPassStrategy::kRandomWithRecommendations};
  uint32_t strategy_index = 0;
  for (uint32_t seed = initial_seed; seed < initial_seed + num_runs; seed++) {
    spvtools::ValidatorOptions validator_options;

    std::unique_ptr<opt::IRContext> ir_context;
    ASSERT_TRUE(fuzzerutil::BuildIRContext(env, kConsoleMessageConsumer,
                                           binary_in, validator_options,
                                           &ir_context));

    auto fuzzer_context = MakeUnique<FuzzerContext>(
        MakeUnique<PseudoRandomGenerator>(seed),
        FuzzerContext::GetMinFreshId(ir_context.get()), false);

    auto transformation_context = MakeUnique<TransformationContext>(
        MakeUnique<FactManager>(ir_context.get()), validator_options);
    transformation_context->GetFactManager()->AddInitialFacts(
        kConsoleMessageConsumer, initial_facts);

    // Every 4th time we run the fuzzer, enable all fuzzer passes.
    bool enable_all_passes = (seed % 4) == 0;
    Fuzzer fuzzer(std::move(ir_context), std::move(transformation_context),
                  std::move(fuzzer_context), kConsoleMessageConsumer,
                  donor_suppliers, enable_all_passes,
                  strategies[strategy_index], true, validator_options, false);
    auto fuzzer_result = fuzzer.Run(0);

    // Cycle the repeated pass strategy so that we try a different one next time
    // we run the fuzzer.
    strategy_index =
        (strategy_index + 1) % static_cast<uint32_t>(strategies.size());

    ASSERT_NE(Fuzzer::Status::kFuzzerPassLedToInvalidModule,
              fuzzer_result.status);
    std::vector<uint32_t> transformed_binary;
    fuzzer.GetIRContext()->module()->ToBinary(&transformed_binary, true);
    ASSERT_TRUE(t.Validate(transformed_binary));

    auto replayer_result =
        Replayer(env, kConsoleMessageConsumer, binary_in, initial_facts,
                 fuzzer.GetTransformationSequence(),
                 static_cast<uint32_t>(
                     fuzzer.GetTransformationSequence().transformation_size()),
                 false, validator_options)
            .Run();
    ASSERT_EQ(Replayer::ReplayerResultStatus::kComplete,
              replayer_result.status);

    // After replaying the transformations applied by the fuzzer, exactly those
    // transformations should have been applied, and the binary resulting from
    // replay should be identical to that which resulted from fuzzing.
    std::string fuzzer_transformations_string;
    std::string replayer_transformations_string;
    fuzzer.GetTransformationSequence().SerializeToString(
        &fuzzer_transformations_string);
    replayer_result.applied_transformations.SerializeToString(
        &replayer_transformations_string);
    ASSERT_EQ(fuzzer_transformations_string, replayer_transformations_string);
    ASSERT_TRUE(IsEqual(env, transformed_binary,
                        replayer_result.transformed_module.get()));
  }
}

TEST(FuzzerReplayerTest, Miscellaneous1) {
  // Do some fuzzer runs, starting from an initial seed of 0 (seed value chosen
  // arbitrarily).
  RunFuzzerAndReplayer(kTestShader1, protobufs::FactSequence(), 0,
                       kNumFuzzerRuns);
}

TEST(FuzzerReplayerTest, Miscellaneous2) {
  // Do some fuzzer runs, starting from an initial seed of 10 (seed value chosen
  // arbitrarily).
  RunFuzzerAndReplayer(kTestShader2, protobufs::FactSequence(), 10,
                       kNumFuzzerRuns);
}

TEST(FuzzerReplayerTest, Miscellaneous3) {
  // Add the facts "resolution.x == 250" and "resolution.y == 100".
  protobufs::FactSequence facts;
  AddConstantUniformFact(&facts, 0, 0, {0, 0}, 250);
  AddConstantUniformFact(&facts, 0, 0, {0, 1}, 100);

  // Do some fuzzer runs, starting from an initial seed of 94 (seed value chosen
  // arbitrarily).
  RunFuzzerAndReplayer(kTestShader3, facts, 94, kNumFuzzerRuns);
}

TEST(FuzzerReplayerTest, Miscellaneous4) {
  // Add the facts:
  //  - "one == 1.0"
  //  - "resolution.y == 256.0",
  protobufs::FactSequence facts;
  AddConstantUniformFact(&facts, 0, 0, {0}, FloatBitsAsUint(1.0));
  AddConstantUniformFact(&facts, 0, 1, {0, 0}, FloatBitsAsUint(256.0));
  AddConstantUniformFact(&facts, 0, 1, {0, 1}, FloatBitsAsUint(256.0));

  // Do some fuzzer runs, starting from an initial seed of 14 (seed value chosen
  // arbitrarily).
  RunFuzzerAndReplayer(kTestShader4, facts, 14, kNumFuzzerRuns);
}

TEST(FuzzerReplayerTest, Miscellaneous5) {
  // Do some fuzzer runs, starting from an initial seed of 29 (seed value chosen
  // arbitrarily).
  RunFuzzerAndReplayer(kTestShader5, protobufs::FactSequence(), 29,
                       kNumFuzzerRuns);
}

TEST(FuzzerReplayerTest, Miscellaneous6) {
  // Do some fuzzer runs, starting from an initial seed of 57 (seed value chosen
  // arbitrarily).
  RunFuzzerAndReplayer(kTestShader6, protobufs::FactSequence(), 57,
                       kNumFuzzerRuns);
}

TEST(FuzzerReplayerTest, Miscellaneous7) {
  // Do some fuzzer runs, starting from an initial seed of 1 (seed value chosen
  // arbitrarily).
  RunFuzzerAndReplayer(kTestShader7, protobufs::FactSequence(), 1,
                       kNumFuzzerRuns);
}

}  // namespace
}  // namespace fuzz
}  // namespace spvtools
