blob: 2444e9f8d780f34f8f6b5966818b84e13f73c0a2 [file] [log] [blame]
// Copyright (c) 2020 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/replayer.h"
#include "source/fuzz/instruction_descriptor.h"
#include "source/fuzz/transformation_split_block.h"
#include "test/fuzz/fuzz_test_util.h"
namespace spvtools {
namespace fuzz {
namespace {
TEST(ReplayerTest, PartialReplay) {
const std::string kTestShader = 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 %8 "g"
OpName %11 "x"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Private %6
%8 = OpVariable %7 Private
%9 = OpConstant %6 10
%10 = OpTypePointer Function %6
%4 = OpFunction %2 None %3
%5 = OpLabel
%11 = OpVariable %10 Function
OpStore %8 %9
%12 = OpLoad %6 %8
OpStore %11 %12
%13 = OpLoad %6 %8
OpStore %11 %13
%14 = OpLoad %6 %8
OpStore %11 %14
%15 = OpLoad %6 %8
OpStore %11 %15
%16 = OpLoad %6 %8
OpStore %11 %16
%17 = OpLoad %6 %8
OpStore %11 %17
%18 = OpLoad %6 %8
OpStore %11 %18
%19 = OpLoad %6 %8
OpStore %11 %19
%20 = OpLoad %6 %8
OpStore %11 %20
%21 = OpLoad %6 %8
OpStore %11 %21
%22 = OpLoad %6 %8
OpStore %11 %22
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
spvtools::ValidatorOptions validator_options;
std::vector<uint32_t> binary_in;
SpirvTools t(env);
t.SetMessageConsumer(kSilentConsumer);
ASSERT_TRUE(t.Assemble(kTestShader, &binary_in, kFuzzAssembleOption));
ASSERT_TRUE(t.Validate(binary_in));
protobufs::TransformationSequence transformations;
for (uint32_t id = 12; id <= 22; id++) {
*transformations.add_transformation() =
TransformationSplitBlock(MakeInstructionDescriptor(id, SpvOpLoad, 0),
id + 100)
.ToMessage();
}
{
// Full replay
protobufs::FactSequence empty_facts;
auto replayer_result =
Replayer(env, kSilentConsumer, binary_in, empty_facts, transformations,
11, 0, true, validator_options)
.Run();
// Replay should succeed.
ASSERT_EQ(Replayer::ReplayerResultStatus::kComplete,
replayer_result.status);
// All transformations should be applied.
ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
transformations, replayer_result.applied_transformations));
const std::string kFullySplitShader = 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 %8 "g"
OpName %11 "x"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Private %6
%8 = OpVariable %7 Private
%9 = OpConstant %6 10
%10 = OpTypePointer Function %6
%4 = OpFunction %2 None %3
%5 = OpLabel
%11 = OpVariable %10 Function
OpStore %8 %9
OpBranch %112
%112 = OpLabel
%12 = OpLoad %6 %8
OpStore %11 %12
OpBranch %113
%113 = OpLabel
%13 = OpLoad %6 %8
OpStore %11 %13
OpBranch %114
%114 = OpLabel
%14 = OpLoad %6 %8
OpStore %11 %14
OpBranch %115
%115 = OpLabel
%15 = OpLoad %6 %8
OpStore %11 %15
OpBranch %116
%116 = OpLabel
%16 = OpLoad %6 %8
OpStore %11 %16
OpBranch %117
%117 = OpLabel
%17 = OpLoad %6 %8
OpStore %11 %17
OpBranch %118
%118 = OpLabel
%18 = OpLoad %6 %8
OpStore %11 %18
OpBranch %119
%119 = OpLabel
%19 = OpLoad %6 %8
OpStore %11 %19
OpBranch %120
%120 = OpLabel
%20 = OpLoad %6 %8
OpStore %11 %20
OpBranch %121
%121 = OpLabel
%21 = OpLoad %6 %8
OpStore %11 %21
OpBranch %122
%122 = OpLabel
%22 = OpLoad %6 %8
OpStore %11 %22
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(
IsEqual(env, kFullySplitShader, replayer_result.transformed_binary));
}
{
// Half replay
protobufs::FactSequence empty_facts;
auto replayer_result =
Replayer(env, kSilentConsumer, binary_in, empty_facts, transformations,
5, 0, true, validator_options)
.Run();
// Replay should succeed.
ASSERT_EQ(Replayer::ReplayerResultStatus::kComplete,
replayer_result.status);
// The first 5 transformations should be applied
ASSERT_EQ(5, replayer_result.applied_transformations.transformation_size());
for (uint32_t i = 0; i < 5; i++) {
ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
transformations.transformation(i),
replayer_result.applied_transformations.transformation(i)));
}
const std::string kHalfSplitShader = 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 %8 "g"
OpName %11 "x"
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Private %6
%8 = OpVariable %7 Private
%9 = OpConstant %6 10
%10 = OpTypePointer Function %6
%4 = OpFunction %2 None %3
%5 = OpLabel
%11 = OpVariable %10 Function
OpStore %8 %9
OpBranch %112
%112 = OpLabel
%12 = OpLoad %6 %8
OpStore %11 %12
OpBranch %113
%113 = OpLabel
%13 = OpLoad %6 %8
OpStore %11 %13
OpBranch %114
%114 = OpLabel
%14 = OpLoad %6 %8
OpStore %11 %14
OpBranch %115
%115 = OpLabel
%15 = OpLoad %6 %8
OpStore %11 %15
OpBranch %116
%116 = OpLabel
%16 = OpLoad %6 %8
OpStore %11 %16
%17 = OpLoad %6 %8
OpStore %11 %17
%18 = OpLoad %6 %8
OpStore %11 %18
%19 = OpLoad %6 %8
OpStore %11 %19
%20 = OpLoad %6 %8
OpStore %11 %20
%21 = OpLoad %6 %8
OpStore %11 %21
%22 = OpLoad %6 %8
OpStore %11 %22
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(
IsEqual(env, kHalfSplitShader, replayer_result.transformed_binary));
}
{
// Empty replay
protobufs::FactSequence empty_facts;
auto replayer_result =
Replayer(env, kSilentConsumer, binary_in, empty_facts, transformations,
0, 0, true, validator_options)
.Run();
// Replay should succeed.
ASSERT_EQ(Replayer::ReplayerResultStatus::kComplete,
replayer_result.status);
// No transformations should be applied
ASSERT_EQ(0, replayer_result.applied_transformations.transformation_size());
ASSERT_TRUE(IsEqual(env, kTestShader, replayer_result.transformed_binary));
}
{
// Invalid replay: too many transformations
protobufs::FactSequence empty_facts;
// The number of transformations requested to be applied exceeds the number
// of transformations
auto replayer_result =
Replayer(env, kSilentConsumer, binary_in, empty_facts, transformations,
12, 0, true, validator_options)
.Run();
// Replay should not succeed.
ASSERT_EQ(Replayer::ReplayerResultStatus::kTooManyTransformationsRequested,
replayer_result.status);
// No transformations should be applied
ASSERT_EQ(0, replayer_result.applied_transformations.transformation_size());
// The output binary should be empty
ASSERT_TRUE(replayer_result.transformed_binary.empty());
}
}
} // namespace
} // namespace fuzz
} // namespace spvtools