SPIRV-Tools/test/fuzz/fuzzer_pass_donate_modules_test.cpp
Alastair Donaldson 9c4481419e
spirv-fuzz: Allow inapplicable transformations to be ignored (#4407)
spirv-fuzz features transformations that should be applicable by
construction. Assertions are used to detect when such transformations
turn out to be inapplicable. Failures of such assertions indicate bugs
in the fuzzer. However, when using the fuzzer at scale (e.g. in
ClusterFuzz) reports of these assertion failures create noise, and
cause the fuzzer to exit early. This change adds an option whereby
inapplicable transformations can be ignored. This reduces noise and
allows fuzzing to continue even when a transformation that should be
applicable but is not has been erroneously created.
2021-07-28 22:59:37 +01:00

2271 lines
82 KiB
C++

// 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_pass_donate_modules.h"
#include <algorithm>
#include "gtest/gtest.h"
#include "source/fuzz/pseudo_random_generator.h"
#include "test/fuzz/fuzz_test_util.h"
namespace spvtools {
namespace fuzz {
namespace {
TEST(FuzzerPassDonateModulesTest, BasicDonation) {
std::string recipient_shader = 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 %10 "m"
OpName %16 "v"
OpDecorate %16 RelaxedPrecision
OpDecorate %20 RelaxedPrecision
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeVector %6 3
%8 = OpTypeMatrix %7 2
%9 = OpTypePointer Private %8
%10 = OpVariable %9 Private
%11 = OpTypeInt 32 1
%12 = OpConstant %11 0
%13 = OpTypeInt 32 0
%14 = OpTypeVector %13 4
%15 = OpTypePointer Private %14
%16 = OpVariable %15 Private
%17 = OpConstant %13 2
%18 = OpTypePointer Private %13
%22 = OpConstant %13 0
%23 = OpTypePointer Private %6
%4 = OpFunction %2 None %3
%5 = OpLabel
%19 = OpAccessChain %18 %16 %17
%20 = OpLoad %13 %19
%21 = OpConvertUToF %6 %20
%24 = OpAccessChain %23 %10 %12 %22
OpStore %24 %21
OpReturn
OpFunctionEnd
)";
std::string donor_shader = 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 %12 "bar(mf24;"
OpName %11 "m"
OpName %20 "foo(vu4;"
OpName %19 "v"
OpName %23 "x"
OpName %26 "param"
OpName %29 "result"
OpName %31 "i"
OpName %81 "param"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeVector %6 4
%8 = OpTypeMatrix %7 2
%9 = OpTypePointer Function %8
%10 = OpTypeFunction %6 %9
%14 = OpTypeInt 32 0
%15 = OpTypeVector %14 4
%16 = OpTypePointer Function %15
%17 = OpTypeInt 32 1
%18 = OpTypeFunction %17 %16
%22 = OpTypePointer Function %17
%24 = OpConstant %14 2
%25 = OpConstantComposite %15 %24 %24 %24 %24
%28 = OpTypePointer Function %6
%30 = OpConstant %6 0
%32 = OpConstant %17 0
%39 = OpConstant %17 10
%40 = OpTypeBool
%43 = OpConstant %17 3
%50 = OpConstant %17 1
%55 = OpConstant %14 0
%56 = OpTypePointer Function %14
%59 = OpConstant %14 1
%65 = OpConstant %17 2
%68 = OpConstant %6 1
%69 = OpConstant %6 2
%70 = OpConstant %6 3
%71 = OpConstant %6 4
%72 = OpConstant %14 3
%76 = OpConstant %6 6
%77 = OpConstant %6 7
%4 = OpFunction %2 None %3
%5 = OpLabel
%23 = OpVariable %22 Function
%26 = OpVariable %16 Function
OpStore %26 %25
%27 = OpFunctionCall %17 %20 %26
OpStore %23 %27
OpReturn
OpFunctionEnd
%12 = OpFunction %6 None %10
%11 = OpFunctionParameter %9
%13 = OpLabel
%29 = OpVariable %28 Function
%31 = OpVariable %22 Function
OpStore %29 %30
OpStore %31 %32
OpBranch %33
%33 = OpLabel
OpLoopMerge %35 %36 None
OpBranch %37
%37 = OpLabel
%38 = OpLoad %17 %31
%41 = OpSLessThan %40 %38 %39
OpBranchConditional %41 %34 %35
%34 = OpLabel
%42 = OpLoad %17 %31
%44 = OpExtInst %17 %1 SClamp %42 %32 %43
%45 = OpAccessChain %28 %11 %32 %44
%46 = OpLoad %6 %45
%47 = OpLoad %6 %29
%48 = OpFAdd %6 %47 %46
OpStore %29 %48
OpBranch %36
%36 = OpLabel
%49 = OpLoad %17 %31
%51 = OpIAdd %17 %49 %50
OpStore %31 %51
OpBranch %33
%35 = OpLabel
%52 = OpLoad %6 %29
OpReturnValue %52
OpFunctionEnd
%20 = OpFunction %17 None %18
%19 = OpFunctionParameter %16
%21 = OpLabel
%81 = OpVariable %9 Function
%57 = OpAccessChain %56 %19 %55
%58 = OpLoad %14 %57
%60 = OpAccessChain %56 %19 %59
%61 = OpLoad %14 %60
%62 = OpUGreaterThan %40 %58 %61
OpSelectionMerge %64 None
OpBranchConditional %62 %63 %67
%63 = OpLabel
OpReturnValue %65
%67 = OpLabel
%73 = OpAccessChain %56 %19 %72
%74 = OpLoad %14 %73
%75 = OpConvertUToF %6 %74
%78 = OpCompositeConstruct %7 %30 %68 %69 %70
%79 = OpCompositeConstruct %7 %71 %75 %76 %77
%80 = OpCompositeConstruct %8 %78 %79
OpStore %81 %80
%82 = OpFunctionCall %6 %12 %81
%83 = OpConvertFToS %17 %82
OpReturnValue %83
%64 = OpLabel
%85 = OpUndef %17
OpReturnValue %85
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context =
BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context =
BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), false);
// We just check that the result is valid. Checking to what it should be
// exactly equal to would be very fragile.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
}
TEST(FuzzerPassDonateModulesTest, DonationWithUniforms) {
// This test checks that when donating a shader that contains uniforms,
// uniform variables and associated pointer types are demoted from having
// Uniform storage class to Private storage class.
std::string recipient_and_donor_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpMemberDecorate %9 0 Offset 0
OpDecorate %9 Block
OpDecorate %11 DescriptorSet 0
OpDecorate %11 Binding 0
OpMemberDecorate %19 0 Offset 0
OpDecorate %19 Block
OpDecorate %21 DescriptorSet 0
OpDecorate %21 Binding 1
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypePointer Function %6
%9 = OpTypeStruct %6
%10 = OpTypePointer Uniform %9
%11 = OpVariable %10 Uniform
%12 = OpTypeInt 32 1
%13 = OpConstant %12 0
%14 = OpTypePointer Uniform %6
%17 = OpTypePointer Function %12
%19 = OpTypeStruct %12
%20 = OpTypePointer Uniform %19
%21 = OpVariable %20 Uniform
%22 = OpTypePointer Uniform %12
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
%18 = OpVariable %17 Function
%15 = OpAccessChain %14 %11 %13
%16 = OpLoad %6 %15
OpStore %8 %16
%23 = OpAccessChain %22 %21 %13
%24 = OpLoad %12 %23
OpStore %18 %24
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context = BuildModule(
env, consumer, recipient_and_donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context = BuildModule(
env, consumer, recipient_and_donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), false);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
std::string after_transformation = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpMemberDecorate %9 0 Offset 0
OpDecorate %9 Block
OpDecorate %11 DescriptorSet 0
OpDecorate %11 Binding 0
OpMemberDecorate %19 0 Offset 0
OpDecorate %19 Block
OpDecorate %21 DescriptorSet 0
OpDecorate %21 Binding 1
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypePointer Function %6
%9 = OpTypeStruct %6
%10 = OpTypePointer Uniform %9
%11 = OpVariable %10 Uniform
%12 = OpTypeInt 32 1
%13 = OpConstant %12 0
%14 = OpTypePointer Uniform %6
%17 = OpTypePointer Function %12
%19 = OpTypeStruct %12
%20 = OpTypePointer Uniform %19
%21 = OpVariable %20 Uniform
%22 = OpTypePointer Uniform %12
%100 = OpTypePointer Function %6
%101 = OpTypeStruct %6
%102 = OpTypePointer Private %101
%104 = OpConstant %6 0
%105 = OpConstantComposite %101 %104
%103 = OpVariable %102 Private %105
%106 = OpConstant %12 0
%107 = OpTypePointer Private %6
%108 = OpTypePointer Function %12
%109 = OpTypeStruct %12
%110 = OpTypePointer Private %109
%112 = OpConstantComposite %109 %13
%111 = OpVariable %110 Private %112
%113 = OpTypePointer Private %12
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
%18 = OpVariable %17 Function
%15 = OpAccessChain %14 %11 %13
%16 = OpLoad %6 %15
OpStore %8 %16
%23 = OpAccessChain %22 %21 %13
%24 = OpLoad %12 %23
OpStore %18 %24
OpReturn
OpFunctionEnd
%114 = OpFunction %2 None %3
%115 = OpLabel
%116 = OpVariable %100 Function %104
%117 = OpVariable %108 Function %13
%118 = OpAccessChain %107 %103 %106
%119 = OpLoad %6 %118
OpStore %116 %119
%120 = OpAccessChain %113 %111 %106
%121 = OpLoad %12 %120
OpStore %117 %121
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, after_transformation, recipient_context.get()));
}
TEST(FuzzerPassDonateModulesTest, DonationWithInputAndOutputVariables) {
// This test checks that when donating a shader that contains input and output
// variables, such variables and associated pointer types are demoted to have
// the Private storage class.
std::string recipient_and_donor_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main" %9 %11
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpDecorate %9 Location 0
OpDecorate %11 Location 1
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeVector %6 4
%8 = OpTypePointer Output %7
%9 = OpVariable %8 Output
%10 = OpTypePointer Input %7
%11 = OpVariable %10 Input
%4 = OpFunction %2 None %3
%5 = OpLabel
%12 = OpLoad %7 %11
OpStore %9 %12
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context = BuildModule(
env, consumer, recipient_and_donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context = BuildModule(
env, consumer, recipient_and_donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), false);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
std::string after_transformation = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main" %9 %11
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpDecorate %9 Location 0
OpDecorate %11 Location 1
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeVector %6 4
%8 = OpTypePointer Output %7
%9 = OpVariable %8 Output
%10 = OpTypePointer Input %7
%11 = OpVariable %10 Input
%100 = OpTypePointer Private %7
%102 = OpConstant %6 0
%103 = OpConstantComposite %7 %102 %102 %102 %102
%101 = OpVariable %100 Private %103
%104 = OpTypePointer Private %7
%105 = OpVariable %104 Private %103
%4 = OpFunction %2 None %3
%5 = OpLabel
%12 = OpLoad %7 %11
OpStore %9 %12
OpReturn
OpFunctionEnd
%106 = OpFunction %2 None %3
%107 = OpLabel
%108 = OpLoad %7 %105
OpStore %101 %108
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, after_transformation, recipient_context.get()));
}
TEST(FuzzerPassDonateModulesTest, DonateFunctionTypeWithDifferentPointers) {
std::string recipient_and_donor_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 0
%7 = OpTypePointer Function %6
%8 = OpTypeFunction %2 %7
%4 = OpFunction %2 None %3
%5 = OpLabel
%9 = OpVariable %7 Function
%10 = OpFunctionCall %2 %11 %9
OpReturn
OpFunctionEnd
%11 = OpFunction %2 None %8
%12 = OpFunctionParameter %7
%13 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_5;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context = BuildModule(
env, consumer, recipient_and_donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context = BuildModule(
env, consumer, recipient_and_donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), false);
// We just check that the result is valid. Checking to what it should be
// exactly equal to would be very fragile.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
}
TEST(FuzzerPassDonateModulesTest, DonateOpConstantNull) {
std::string recipient_shader = R"(
OpCapability Shader
OpCapability ImageQuery
OpCapability VariablePointers
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
OpSourceExtension "GL_EXT_samplerless_texture_functions"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
std::string donor_shader = R"(
OpCapability Shader
OpCapability ImageQuery
OpCapability VariablePointers
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypePointer Private %6
%8 = OpConstantNull %7
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context =
BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context =
BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), false);
// We just check that the result is valid. Checking to what it should be
// exactly equal to would be very fragile.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
}
TEST(FuzzerPassDonateModulesTest, DonateCodeThatUsesImages) {
std::string recipient_shader = R"(
OpCapability Shader
OpCapability ImageQuery
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
OpSourceExtension "GL_EXT_samplerless_texture_functions"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
std::string donor_shader = R"(
OpCapability Shader
OpCapability ImageQuery
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
OpSourceExtension "GL_EXT_samplerless_texture_functions"
OpName %4 "main"
OpName %10 "mySampler"
OpName %21 "myTexture"
OpName %33 "v"
OpDecorate %10 RelaxedPrecision
OpDecorate %10 DescriptorSet 0
OpDecorate %10 Binding 0
OpDecorate %11 RelaxedPrecision
OpDecorate %21 RelaxedPrecision
OpDecorate %21 DescriptorSet 0
OpDecorate %21 Binding 1
OpDecorate %22 RelaxedPrecision
OpDecorate %34 RelaxedPrecision
OpDecorate %40 RelaxedPrecision
OpDecorate %42 RelaxedPrecision
OpDecorate %43 RelaxedPrecision
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeImage %6 2D 0 0 0 1 Unknown
%8 = OpTypeSampledImage %7
%9 = OpTypePointer UniformConstant %8
%10 = OpVariable %9 UniformConstant
%12 = OpTypeInt 32 1
%13 = OpConstant %12 2
%15 = OpTypeVector %12 2
%17 = OpTypeInt 32 0
%18 = OpConstant %17 0
%20 = OpTypePointer UniformConstant %7
%21 = OpVariable %20 UniformConstant
%23 = OpConstant %12 1
%25 = OpConstant %17 1
%27 = OpTypeBool
%31 = OpTypeVector %6 4
%32 = OpTypePointer Function %31
%35 = OpConstantComposite %15 %23 %23
%36 = OpConstant %12 3
%37 = OpConstant %12 4
%38 = OpConstantComposite %15 %36 %37
%4 = OpFunction %2 None %3
%5 = OpLabel
%33 = OpVariable %32 Function
%11 = OpLoad %8 %10
%14 = OpImage %7 %11
%16 = OpImageQuerySizeLod %15 %14 %13
%19 = OpCompositeExtract %12 %16 0
%22 = OpLoad %7 %21
%24 = OpImageQuerySizeLod %15 %22 %23
%26 = OpCompositeExtract %12 %24 1
%28 = OpSGreaterThan %27 %19 %26
OpSelectionMerge %30 None
OpBranchConditional %28 %29 %41
%29 = OpLabel
%34 = OpLoad %8 %10
%39 = OpImage %7 %34
%40 = OpImageFetch %31 %39 %35 Lod|ConstOffset %13 %38
OpStore %33 %40
OpBranch %30
%41 = OpLabel
%42 = OpLoad %7 %21
%43 = OpImageFetch %31 %42 %35 Lod|ConstOffset %13 %38
OpStore %33 %43
OpBranch %30
%30 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context =
BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context =
BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), false);
// We just check that the result is valid. Checking to what it should be
// exactly equal to would be very fragile.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
}
TEST(FuzzerPassDonateModulesTest, DonateCodeThatUsesSampler) {
std::string recipient_shader = R"(
OpCapability Shader
OpCapability ImageQuery
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
OpSourceExtension "GL_EXT_samplerless_texture_functions"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
std::string donor_shader = R"(
OpCapability Shader
OpCapability ImageQuery
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
OpDecorate %16 DescriptorSet 0
OpDecorate %16 Binding 0
OpDecorate %12 DescriptorSet 0
OpDecorate %12 Binding 64
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%23 = OpTypeFloat 32
%6 = OpTypeImage %23 2D 2 0 0 1 Unknown
%47 = OpTypePointer UniformConstant %6
%12 = OpVariable %47 UniformConstant
%15 = OpTypeSampler
%55 = OpTypePointer UniformConstant %15
%17 = OpTypeSampledImage %6
%16 = OpVariable %55 UniformConstant
%37 = OpTypeVector %23 4
%109 = OpConstant %23 0
%66 = OpConstantComposite %37 %109 %109 %109 %109
%56 = OpTypeBool
%54 = OpConstantTrue %56
%4 = OpFunction %2 None %3
%5 = OpLabel
OpBranch %50
%50 = OpLabel
%51 = OpPhi %37 %66 %5 %111 %53
OpLoopMerge %52 %53 None
OpBranchConditional %54 %53 %52
%53 = OpLabel
%106 = OpLoad %6 %12
%107 = OpLoad %15 %16
%110 = OpSampledImage %17 %106 %107
%111 = OpImageSampleImplicitLod %37 %110 %66 Bias %109
OpBranch %50
%52 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context =
BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context =
BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), false);
// We just check that the result is valid. Checking to what it should be
// exactly equal to would be very fragile.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
}
TEST(FuzzerPassDonateModulesTest, DonateCodeThatUsesImageStructField) {
std::string recipient_shader = R"(
OpCapability Shader
OpCapability ImageQuery
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
OpSourceExtension "GL_EXT_samplerless_texture_functions"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
std::string donor_shader = R"(
OpCapability Shader
OpCapability ImageQuery
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
OpSourceExtension "GL_EXT_samplerless_texture_functions"
OpName %4 "main"
OpName %10 "mySampler"
OpName %21 "myTexture"
OpName %33 "v"
OpDecorate %10 RelaxedPrecision
OpDecorate %10 DescriptorSet 0
OpDecorate %10 Binding 0
OpDecorate %11 RelaxedPrecision
OpDecorate %21 RelaxedPrecision
OpDecorate %21 DescriptorSet 0
OpDecorate %21 Binding 1
OpDecorate %22 RelaxedPrecision
OpDecorate %34 RelaxedPrecision
OpDecorate %40 RelaxedPrecision
OpDecorate %42 RelaxedPrecision
OpDecorate %43 RelaxedPrecision
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeImage %6 2D 0 0 0 1 Unknown
%8 = OpTypeSampledImage %7
%9 = OpTypePointer UniformConstant %8
%10 = OpVariable %9 UniformConstant
%12 = OpTypeInt 32 1
%13 = OpConstant %12 2
%15 = OpTypeVector %12 2
%17 = OpTypeInt 32 0
%18 = OpConstant %17 0
%20 = OpTypePointer UniformConstant %7
%21 = OpVariable %20 UniformConstant
%23 = OpConstant %12 1
%25 = OpConstant %17 1
%27 = OpTypeBool
%31 = OpTypeVector %6 4
%32 = OpTypePointer Function %31
%35 = OpConstantComposite %15 %23 %23
%36 = OpConstant %12 3
%37 = OpConstant %12 4
%38 = OpConstantComposite %15 %36 %37
%201 = OpTypeStruct %7 %7
%4 = OpFunction %2 None %3
%5 = OpLabel
%33 = OpVariable %32 Function
%11 = OpLoad %8 %10
%14 = OpImage %7 %11
%22 = OpLoad %7 %21
%200 = OpCompositeConstruct %201 %14 %22
%202 = OpCompositeExtract %7 %200 0
%203 = OpCompositeExtract %7 %200 1
%24 = OpImageQuerySizeLod %15 %203 %23
%16 = OpImageQuerySizeLod %15 %202 %13
%26 = OpCompositeExtract %12 %24 1
%19 = OpCompositeExtract %12 %16 0
%28 = OpSGreaterThan %27 %19 %26
OpSelectionMerge %30 None
OpBranchConditional %28 %29 %41
%29 = OpLabel
%34 = OpLoad %8 %10
%39 = OpImage %7 %34
%40 = OpImageFetch %31 %39 %35 Lod|ConstOffset %13 %38
OpStore %33 %40
OpBranch %30
%41 = OpLabel
%42 = OpLoad %7 %21
%43 = OpImageFetch %31 %42 %35 Lod|ConstOffset %13 %38
OpStore %33 %43
OpBranch %30
%30 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context =
BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context =
BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), false);
// We just check that the result is valid. Checking to what it should be
// exactly equal to would be very fragile.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
}
TEST(FuzzerPassDonateModulesTest, DonateCodeThatUsesImageFunctionParameter) {
std::string recipient_shader = R"(
OpCapability Shader
OpCapability ImageQuery
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
OpSourceExtension "GL_EXT_samplerless_texture_functions"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
std::string donor_shader = R"(
OpCapability Shader
OpCapability ImageQuery
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
OpSourceExtension "GL_EXT_samplerless_texture_functions"
OpName %4 "main"
OpName %10 "mySampler"
OpName %21 "myTexture"
OpName %33 "v"
OpDecorate %10 RelaxedPrecision
OpDecorate %10 DescriptorSet 0
OpDecorate %10 Binding 0
OpDecorate %11 RelaxedPrecision
OpDecorate %21 RelaxedPrecision
OpDecorate %21 DescriptorSet 0
OpDecorate %21 Binding 1
OpDecorate %22 RelaxedPrecision
OpDecorate %34 RelaxedPrecision
OpDecorate %40 RelaxedPrecision
OpDecorate %42 RelaxedPrecision
OpDecorate %43 RelaxedPrecision
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeImage %6 2D 0 0 0 1 Unknown
%8 = OpTypeSampledImage %7
%9 = OpTypePointer UniformConstant %8
%10 = OpVariable %9 UniformConstant
%12 = OpTypeInt 32 1
%13 = OpConstant %12 2
%15 = OpTypeVector %12 2
%17 = OpTypeInt 32 0
%18 = OpConstant %17 0
%20 = OpTypePointer UniformConstant %7
%21 = OpVariable %20 UniformConstant
%23 = OpConstant %12 1
%25 = OpConstant %17 1
%27 = OpTypeBool
%31 = OpTypeVector %6 4
%32 = OpTypePointer Function %31
%35 = OpConstantComposite %15 %23 %23
%36 = OpConstant %12 3
%37 = OpConstant %12 4
%38 = OpConstantComposite %15 %36 %37
%201 = OpTypeFunction %15 %7 %12
%4 = OpFunction %2 None %3
%5 = OpLabel
%33 = OpVariable %32 Function
%11 = OpLoad %8 %10
%14 = OpImage %7 %11
%16 = OpFunctionCall %15 %200 %14 %13
%19 = OpCompositeExtract %12 %16 0
%22 = OpLoad %7 %21
%24 = OpImageQuerySizeLod %15 %22 %23
%26 = OpCompositeExtract %12 %24 1
%28 = OpSGreaterThan %27 %19 %26
OpSelectionMerge %30 None
OpBranchConditional %28 %29 %41
%29 = OpLabel
%34 = OpLoad %8 %10
%39 = OpImage %7 %34
%40 = OpImageFetch %31 %39 %35 Lod|ConstOffset %13 %38
OpStore %33 %40
OpBranch %30
%41 = OpLabel
%42 = OpLoad %7 %21
%43 = OpImageFetch %31 %42 %35 Lod|ConstOffset %13 %38
OpStore %33 %43
OpBranch %30
%30 = OpLabel
OpReturn
OpFunctionEnd
%200 = OpFunction %15 None %201
%202 = OpFunctionParameter %7
%203 = OpFunctionParameter %12
%204 = OpLabel
%205 = OpImageQuerySizeLod %15 %202 %203
OpReturnValue %205
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context =
BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context =
BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), false);
// We just check that the result is valid. Checking to what it should be
// exactly equal to would be very fragile.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
}
TEST(FuzzerPassDonateModulesTest, DonateShaderWithImageStorageClass) {
std::string recipient_shader = R"(
OpCapability Shader
OpCapability ImageQuery
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 320
OpSourceExtension "GL_EXT_samplerless_texture_functions"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
std::string donor_shader = R"(
OpCapability Shader
OpCapability SampledBuffer
OpCapability ImageBuffer
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %2 "MainPSPacked"
OpExecutionMode %2 OriginUpperLeft
OpDecorate %18 DescriptorSet 0
OpDecorate %18 Binding 128
%49 = OpTypeInt 32 0
%50 = OpTypeFloat 32
%58 = OpConstant %50 1
%66 = OpConstant %49 0
%87 = OpTypeVector %50 2
%88 = OpConstantComposite %87 %58 %58
%17 = OpTypeImage %49 2D 2 0 0 2 R32ui
%118 = OpTypePointer UniformConstant %17
%123 = OpTypeVector %49 2
%132 = OpTypeVoid
%133 = OpTypeFunction %132
%142 = OpTypePointer Image %49
%18 = OpVariable %118 UniformConstant
%2 = OpFunction %132 None %133
%153 = OpLabel
%495 = OpConvertFToU %123 %88
%501 = OpImageTexelPointer %142 %18 %495 %66
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context =
BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context =
BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), true);
// We just check that the result is valid. Checking to what it should be
// exactly equal to would be very fragile.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
}
TEST(FuzzerPassDonateModulesTest, DonateComputeShaderWithRuntimeArray) {
std::string recipient_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %4 "main"
OpExecutionMode %4 LocalSize 1 1 1
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
std::string donor_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %4 "main"
OpExecutionMode %4 LocalSize 1 1 1
OpSource ESSL 310
OpDecorate %9 ArrayStride 4
OpMemberDecorate %10 0 Offset 0
OpDecorate %10 BufferBlock
OpDecorate %12 DescriptorSet 0
OpDecorate %12 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%9 = OpTypeRuntimeArray %6
%10 = OpTypeStruct %9
%11 = OpTypePointer Uniform %10
%12 = OpVariable %11 Uniform
%13 = OpTypeInt 32 0
%16 = OpConstant %6 0
%18 = OpConstant %6 1
%20 = OpTypePointer Uniform %6
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
%14 = OpArrayLength %13 %12 0
%15 = OpBitcast %6 %14
OpStore %8 %15
%17 = OpLoad %6 %8
%19 = OpISub %6 %17 %18
%21 = OpAccessChain %20 %12 %16 %19
OpStore %21 %16
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context =
BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context =
BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), false);
// We just check that the result is valid. Checking to what it should be
// exactly equal to would be very fragile.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
}
TEST(FuzzerPassDonateModulesTest, DonateComputeShaderWithRuntimeArrayLivesafe) {
std::string recipient_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %4 "main"
OpExecutionMode %4 LocalSize 1 1 1
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
std::string donor_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %4 "main"
OpExecutionMode %4 LocalSize 1 1 1
OpSource ESSL 310
OpDecorate %16 ArrayStride 4
OpMemberDecorate %17 0 Offset 0
OpDecorate %17 BufferBlock
OpDecorate %19 DescriptorSet 0
OpDecorate %19 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%9 = OpConstant %6 0
%16 = OpTypeRuntimeArray %6
%17 = OpTypeStruct %16
%18 = OpTypePointer Uniform %17
%19 = OpVariable %18 Uniform
%20 = OpTypeInt 32 0
%23 = OpTypeBool
%26 = OpConstant %6 32
%27 = OpTypePointer Uniform %6
%30 = OpConstant %6 1
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
OpStore %8 %9
OpBranch %10
%10 = OpLabel
OpLoopMerge %12 %13 None
OpBranch %14
%14 = OpLabel
%15 = OpLoad %6 %8
%21 = OpArrayLength %20 %19 0
%22 = OpBitcast %6 %21
%24 = OpSLessThan %23 %15 %22
OpBranchConditional %24 %11 %12
%11 = OpLabel
%25 = OpLoad %6 %8
%28 = OpAccessChain %27 %19 %9 %25
OpStore %28 %26
OpBranch %13
%13 = OpLabel
%29 = OpLoad %6 %8
%31 = OpIAdd %6 %29 %30
OpStore %8 %31
OpBranch %10
%12 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context =
BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context =
BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), true);
// We just check that the result is valid. Checking to what it should be
// exactly equal to would be very fragile.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
}
TEST(FuzzerPassDonateModulesTest, DonateComputeShaderWithWorkgroupVariables) {
std::string recipient_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %4 "main"
OpExecutionMode %4 LocalSize 1 1 1
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
std::string donor_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %4 "main"
OpExecutionMode %4 LocalSize 1 1 1
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Workgroup %6
%8 = OpVariable %7 Workgroup
%9 = OpConstant %6 2
%10 = OpVariable %7 Workgroup
%4 = OpFunction %2 None %3
%5 = OpLabel
OpStore %8 %9
%11 = OpLoad %6 %8
OpStore %10 %11
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context =
BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context =
BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), true);
// We just check that the result is valid. Checking to what it should be
// exactly equal to would be very fragile.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
}
TEST(FuzzerPassDonateModulesTest, DonateComputeShaderWithAtomics) {
std::string recipient_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %4 "main"
OpExecutionMode %4 LocalSize 1 1 1
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
std::string donor_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %4 "main"
OpExecutionMode %4 LocalSize 1 1 1
OpSource ESSL 310
OpMemberDecorate %9 0 Offset 0
OpDecorate %9 BufferBlock
OpDecorate %11 DescriptorSet 0
OpDecorate %11 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 0
%7 = OpTypePointer Function %6
%9 = OpTypeStruct %6
%10 = OpTypePointer Uniform %9
%11 = OpVariable %10 Uniform
%12 = OpTypeInt 32 1
%13 = OpConstant %12 0
%14 = OpTypePointer Uniform %6
%16 = OpConstant %6 1
%17 = OpConstant %6 0
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
%15 = OpAccessChain %14 %11 %13
%18 = OpAtomicIAdd %6 %15 %16 %17 %16
OpStore %8 %18
%19 = OpAccessChain %14 %11 %13
%20 = OpLoad %6 %8
%21 = OpAtomicUMin %6 %19 %16 %17 %20
OpStore %8 %21
%22 = OpAccessChain %14 %11 %13
%23 = OpLoad %6 %8
%24 = OpAtomicUMax %6 %22 %16 %17 %23
OpStore %8 %24
%25 = OpAccessChain %14 %11 %13
%26 = OpLoad %6 %8
%27 = OpAtomicAnd %6 %25 %16 %17 %26
OpStore %8 %27
%28 = OpAccessChain %14 %11 %13
%29 = OpLoad %6 %8
%30 = OpAtomicOr %6 %28 %16 %17 %29
OpStore %8 %30
%31 = OpAccessChain %14 %11 %13
%32 = OpLoad %6 %8
%33 = OpAtomicXor %6 %31 %16 %17 %32
OpStore %8 %33
%34 = OpAccessChain %14 %11 %13
%35 = OpLoad %6 %8
%36 = OpAtomicExchange %6 %34 %16 %17 %35
OpStore %8 %36
%37 = OpAccessChain %14 %11 %13
%38 = OpLoad %6 %8
%39 = OpAtomicCompareExchange %6 %37 %16 %17 %17 %16 %38
OpStore %8 %39
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context =
BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context =
BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), true);
// We just check that the result is valid. Checking to what it should be
// exactly equal to would be very fragile.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
}
TEST(FuzzerPassDonateModulesTest, Miscellaneous1) {
std::string recipient_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
std::string donor_shader = 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
)";
const auto env = SPV_ENV_UNIVERSAL_1_5;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context =
BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context =
BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), false);
// We just check that the result is valid. Checking to what it should be
// exactly equal to would be very fragile.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
}
TEST(FuzzerPassDonateModulesTest, OpSpecConstantInstructions) {
std::string donor_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeBool
%7 = OpTypeInt 32 1
%8 = OpTypeStruct %6 %6 %7
%9 = OpSpecConstantTrue %6
%10 = OpSpecConstantFalse %6
%11 = OpSpecConstant %7 2
%12 = OpSpecConstantComposite %8 %9 %10 %11
%13 = OpSpecConstantOp %6 LogicalEqual %9 %10
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
std::string recipient_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context =
BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context =
BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), false);
// Check that the module is valid first.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
std::string expected_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%100 = OpTypeBool
%101 = OpTypeInt 32 1
%102 = OpTypeStruct %100 %100 %101
%103 = OpConstantTrue %100
%104 = OpConstantFalse %100
%105 = OpConstant %101 2
%106 = OpConstantComposite %102 %103 %104 %105
%107 = OpSpecConstantOp %100 LogicalEqual %103 %104
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
%108 = OpFunction %2 None %3
%109 = OpLabel
OpReturn
OpFunctionEnd
)";
// Now check that the transformation has produced the expected result.
ASSERT_TRUE(IsEqual(env, expected_shader, recipient_context.get()));
}
TEST(FuzzerPassDonateModulesTest, DonationSupportsOpTypeRuntimeArray) {
std::string donor_shader = R"(
OpCapability Shader
OpExtension "SPV_KHR_storage_buffer_storage_class"
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %29 "kernel_1"
OpEntryPoint GLCompute %37 "kernel_2"
OpSource OpenCL_C 120
OpDecorate %2 ArrayStride 4
OpMemberDecorate %3 0 Offset 0
OpDecorate %3 Block
OpMemberDecorate %5 0 Offset 0
OpMemberDecorate %6 0 Offset 0
OpDecorate %6 Block
OpDecorate %21 BuiltIn WorkgroupSize
OpDecorate %23 DescriptorSet 0
OpDecorate %23 Binding 0
OpDecorate %25 SpecId 3
OpDecorate %18 SpecId 0
OpDecorate %19 SpecId 1
OpDecorate %20 SpecId 2
%1 = OpTypeInt 32 0
%2 = OpTypeRuntimeArray %1
%3 = OpTypeStruct %2
%4 = OpTypePointer StorageBuffer %3
%5 = OpTypeStruct %1
%6 = OpTypeStruct %5
%7 = OpTypePointer PushConstant %6
%8 = OpTypeFloat 32
%9 = OpTypeVoid
%10 = OpTypeFunction %9
%11 = OpTypePointer Workgroup %1
%12 = OpTypePointer PushConstant %5
%13 = OpTypePointer StorageBuffer %1
%14 = OpTypeFunction %1 %1
%15 = OpTypeVector %1 3
%16 = OpTypePointer Private %15
%17 = OpConstant %1 0
%18 = OpSpecConstant %1 1
%19 = OpSpecConstant %1 1
%20 = OpSpecConstant %1 1
%21 = OpSpecConstantComposite %15 %18 %19 %20
%25 = OpSpecConstant %1 1
%26 = OpTypeArray %1 %25
%27 = OpTypePointer Workgroup %26
%22 = OpVariable %16 Private %21
%23 = OpVariable %4 StorageBuffer
%24 = OpVariable %7 PushConstant
%28 = OpVariable %27 Workgroup
%29 = OpFunction %9 None %10
%30 = OpLabel
%31 = OpAccessChain %11 %28 %17
%32 = OpAccessChain %12 %24 %17
%33 = OpLoad %5 %32
%34 = OpCompositeExtract %1 %33 0
%35 = OpFunctionCall %1 %45 %34
%36 = OpAccessChain %13 %23 %17 %34
OpStore %36 %35
OpReturn
OpFunctionEnd
%37 = OpFunction %9 None %10
%38 = OpLabel
%39 = OpAccessChain %11 %28 %17
%40 = OpAccessChain %12 %24 %17
%41 = OpLoad %5 %40
%42 = OpCompositeExtract %1 %41 0
%43 = OpFunctionCall %1 %45 %42
%44 = OpAccessChain %13 %23 %17 %42
OpStore %44 %43
OpReturn
OpFunctionEnd
%45 = OpFunction %1 Pure %14
%46 = OpFunctionParameter %1
%47 = OpLabel
%48 = OpAccessChain %11 %28 %46
%49 = OpLoad %1 %48
OpReturnValue %49
OpFunctionEnd
)";
std::string recipient_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_0;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context =
BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context =
BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), false);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
}
TEST(FuzzerPassDonateModulesTest, HandlesCapabilities) {
std::string donor_shader = R"(
OpCapability VariablePointersStorageBuffer
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%11 = OpConstant %6 23
%7 = OpTypePointer Function %6
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
OpBranch %9
%9 = OpLabel
%10 = OpPhi %7 %8 %5
OpStore %10 %11
OpReturn
OpFunctionEnd
)";
std::string recipient_shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context =
BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context =
BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
ASSERT_TRUE(donor_context->get_feature_mgr()->HasCapability(
SpvCapabilityVariablePointersStorageBuffer));
ASSERT_FALSE(recipient_context->get_feature_mgr()->HasCapability(
SpvCapabilityVariablePointersStorageBuffer));
fuzzer_pass.DonateSingleModule(donor_context.get(), false);
// Check that recipient module hasn't changed.
ASSERT_TRUE(IsEqual(env, recipient_shader, recipient_context.get()));
// Add the missing capability.
//
// We are adding VariablePointers to test the case when donor and recipient
// have different OpCapability instructions but the same capabilities. In our
// example, VariablePointers implicitly declares
// VariablePointersStorageBuffer. Thus, two modules must be compatible.
recipient_context->AddCapability(SpvCapabilityVariablePointers);
ASSERT_TRUE(donor_context->get_feature_mgr()->HasCapability(
SpvCapabilityVariablePointersStorageBuffer));
ASSERT_TRUE(recipient_context->get_feature_mgr()->HasCapability(
SpvCapabilityVariablePointersStorageBuffer));
fuzzer_pass.DonateSingleModule(donor_context.get(), false);
// Check that donation was successful.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
std::string after_transformation = R"(
OpCapability Shader
OpCapability VariablePointers
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%100 = OpTypeFloat 32
%101 = OpConstant %100 23
%102 = OpTypePointer Function %100
%105 = OpConstant %100 0
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
%103 = OpFunction %2 None %3
%104 = OpLabel
%106 = OpVariable %102 Function %105
OpBranch %107
%107 = OpLabel
%108 = OpPhi %102 %106 %104
OpStore %108 %101
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, after_transformation, recipient_context.get()));
}
TEST(FuzzerPassDonateModulesTest, HandlesOpPhisInMergeBlock) {
std::string donor_shader = R"(
; OpPhis don't support pointers without this capability
; and we need pointers to test some of the functionality
OpCapability VariablePointers
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%14 = OpTypeBool
%15 = OpConstantTrue %14
%42 = OpTypePointer Function %14
; back-edge block is unreachable in the CFG
%4 = OpFunction %2 None %3
%5 = OpLabel
OpBranch %6
%6 = OpLabel
OpLoopMerge %8 %7 None
OpBranch %8
%7 = OpLabel
OpBranch %6
%8 = OpLabel
OpReturn
OpFunctionEnd
; back-edge block already has an edge to the merge block
%9 = OpFunction %2 None %3
%10 = OpLabel
OpBranch %11
%11 = OpLabel
OpLoopMerge %13 %12 None
OpBranch %12
%12 = OpLabel
OpBranchConditional %15 %11 %13
%13 = OpLabel
OpReturn
OpFunctionEnd
; merge block has no OpPhis
%16 = OpFunction %2 None %3
%17 = OpLabel
OpBranch %18
%18 = OpLabel
OpLoopMerge %20 %19 None
OpBranchConditional %15 %19 %20
%19 = OpLabel
OpBranch %18
%20 = OpLabel
OpReturn
OpFunctionEnd
; merge block has OpPhis and some of their operands are available at
; the back-edge block
%21 = OpFunction %2 None %3
%22 = OpLabel
OpBranch %23
%23 = OpLabel
%24 = OpCopyObject %14 %15
OpLoopMerge %28 %27 None
OpBranchConditional %15 %25 %28
%25 = OpLabel
%26 = OpCopyObject %14 %15
OpBranchConditional %15 %28 %27
%27 = OpLabel
OpBranch %23
%28 = OpLabel
%29 = OpPhi %14 %24 %23 %26 %25
OpReturn
OpFunctionEnd
; none of the OpPhis' operands dominate the back-edge block but some of
; them have basic type
%30 = OpFunction %2 None %3
%31 = OpLabel
OpBranch %32
%32 = OpLabel
OpLoopMerge %40 %39 None
OpBranch %33
%33 = OpLabel
OpSelectionMerge %38 None
OpBranchConditional %15 %34 %36
%34 = OpLabel
%35 = OpCopyObject %14 %15
OpBranchConditional %35 %38 %40
%36 = OpLabel
%37 = OpCopyObject %14 %15
OpBranchConditional %37 %38 %40
%38 = OpLabel
OpBranch %39
%39 = OpLabel
OpBranch %32
%40 = OpLabel
%41 = OpPhi %14 %35 %34 %37 %36
OpReturn
OpFunctionEnd
; none of the OpPhis' operands dominate the back-edge block and none of
; them have basic type
%43 = OpFunction %2 None %3
%44 = OpLabel
%45 = OpVariable %42 Function
OpBranch %46
%46 = OpLabel
OpLoopMerge %54 %53 None
OpBranch %47
%47 = OpLabel
OpSelectionMerge %52 None
OpBranchConditional %15 %48 %50
%48 = OpLabel
%49 = OpCopyObject %42 %45
OpBranchConditional %15 %52 %54
%50 = OpLabel
%51 = OpCopyObject %42 %45
OpBranchConditional %15 %52 %54
%52 = OpLabel
OpBranch %53
%53 = OpLabel
OpBranch %46
%54 = OpLabel
%55 = OpPhi %42 %49 %48 %51 %50
OpReturn
OpFunctionEnd
)";
std::string recipient_shader = R"(
; OpPhis don't support pointers without this capability
; and we need pointers to test some of the functionality
OpCapability VariablePointers
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
spvtools::ValidatorOptions validator_options;
const auto recipient_context =
BuildModule(env, consumer, recipient_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
const auto donor_context =
BuildModule(env, consumer, donor_shader, kFuzzAssembleOption);
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
donor_context.get(), validator_options, kConsoleMessageConsumer));
TransformationContext transformation_context(
MakeUnique<FactManager>(recipient_context.get()), validator_options);
FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
false);
protobufs::TransformationSequence transformation_sequence;
FuzzerPassDonateModules fuzzer_pass(recipient_context.get(),
&transformation_context, &fuzzer_context,
&transformation_sequence, false, {});
fuzzer_pass.DonateSingleModule(donor_context.get(), true);
// We just check that the result is valid. Checking to what it should be
// exactly equal to would be very fragile.
ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
recipient_context.get(), validator_options, kConsoleMessageConsumer));
}
} // namespace
} // namespace fuzz
} // namespace spvtools