blob: 991f29038466b8eda371e5e2807205f4f87b050e [file] [log] [blame]
// Copyright (c) 2020 Vasyl Teliman
//
// 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/transformation_add_synonym.h"
#include "source/fuzz/instruction_descriptor.h"
#include "test/fuzz/fuzz_test_util.h"
namespace spvtools {
namespace fuzz {
namespace {
TEST(TransformationAddSynonymTest, NotApplicable) {
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpDecorate %8 RelaxedPrecision
OpDecorate %22 RelaxedPrecision
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%9 = OpConstant %6 3
%10 = OpTypeFloat 32
%11 = OpTypePointer Function %10
%13 = OpConstant %10 4.5
%14 = OpTypeVector %10 2
%15 = OpTypePointer Function %14
%17 = OpConstant %10 3
%18 = OpConstant %10 4
%19 = OpConstantComposite %14 %17 %18
%20 = OpTypeVector %6 2
%21 = OpTypePointer Function %20
%23 = OpConstant %6 4
%24 = OpConstantComposite %20 %9 %23
%26 = OpConstantNull %6
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
%12 = OpVariable %11 Function
%16 = OpVariable %15 Function
%22 = OpVariable %21 Function
OpStore %8 %9
OpStore %12 %13
OpStore %16 %19
OpStore %22 %24
%25 = OpUndef %6
%27 = OpLoad %6 %8
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
ASSERT_TRUE(IsValid(env, context.get()));
FactManager fact_manager;
spvtools::ValidatorOptions validator_options;
TransformationContext transformation_context(&fact_manager,
validator_options);
auto insert_before = MakeInstructionDescriptor(22, SpvOpReturn, 0);
#ifndef NDEBUG
ASSERT_DEATH(
TransformationAddSynonym(
9, static_cast<protobufs::TransformationAddSynonym::SynonymType>(-1),
40, insert_before)
.IsApplicable(context.get(), transformation_context),
"Synonym type is invalid");
#endif
// |synonym_fresh_id| is not fresh.
ASSERT_FALSE(
TransformationAddSynonym(9, protobufs::TransformationAddSynonym::ADD_ZERO,
9, insert_before)
.IsApplicable(context.get(), transformation_context));
// |result_id| is invalid.
ASSERT_FALSE(
TransformationAddSynonym(
40, protobufs::TransformationAddSynonym::ADD_ZERO, 40, insert_before)
.IsApplicable(context.get(), transformation_context));
// Instruction with |result_id| has no type id.
ASSERT_FALSE(
TransformationAddSynonym(5, protobufs::TransformationAddSynonym::ADD_ZERO,
40, insert_before)
.IsApplicable(context.get(), transformation_context));
// Instruction with |result_id| is an OpUndef.
ASSERT_FALSE(
TransformationAddSynonym(
25, protobufs::TransformationAddSynonym::ADD_ZERO, 40, insert_before)
.IsApplicable(context.get(), transformation_context));
// Instruction with |result_id| is an OpConstantNull.
ASSERT_FALSE(
TransformationAddSynonym(
26, protobufs::TransformationAddSynonym::ADD_ZERO, 40, insert_before)
.IsApplicable(context.get(), transformation_context));
// |insert_before| is invalid.
ASSERT_FALSE(
TransformationAddSynonym(9, protobufs::TransformationAddSynonym::ADD_ZERO,
40, MakeInstructionDescriptor(25, SpvOpStore, 0))
.IsApplicable(context.get(), transformation_context));
// Can't insert before |insert_before|.
ASSERT_FALSE(
TransformationAddSynonym(9, protobufs::TransformationAddSynonym::ADD_ZERO,
40, MakeInstructionDescriptor(5, SpvOpLabel, 0))
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationAddSynonym(
9, protobufs::TransformationAddSynonym::ADD_ZERO, 40,
MakeInstructionDescriptor(22, SpvOpVariable, 0))
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationAddSynonym(
9, protobufs::TransformationAddSynonym::ADD_ZERO, 40,
MakeInstructionDescriptor(25, SpvOpFunctionEnd, 0))
.IsApplicable(context.get(), transformation_context));
// Domination rules are not satisfied.
ASSERT_FALSE(TransformationAddSynonym(
27, protobufs::TransformationAddSynonym::ADD_ZERO, 40,
MakeInstructionDescriptor(27, SpvOpLoad, 0))
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationAddSynonym(
27, protobufs::TransformationAddSynonym::ADD_ZERO, 40,
MakeInstructionDescriptor(22, SpvOpStore, 1))
.IsApplicable(context.get(), transformation_context));
}
TEST(TransformationAddSynonymTest, AddZeroSubZeroMulOne) {
std::string 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 1
%7 = OpConstant %6 0
%8 = OpConstant %6 1
%9 = OpConstant %6 34
%10 = OpTypeInt 32 0
%13 = OpConstant %10 34
%14 = OpTypeFloat 32
%15 = OpConstant %14 0
%16 = OpConstant %14 1
%17 = OpConstant %14 34
%18 = OpTypeVector %14 2
%19 = OpConstantComposite %18 %15 %15
%20 = OpConstantComposite %18 %16 %16
%21 = OpConstant %14 3
%22 = OpConstant %14 4
%23 = OpConstantComposite %18 %21 %22
%24 = OpTypeVector %6 2
%25 = OpConstantComposite %24 %7 %7
%26 = OpConstantComposite %24 %8 %8
%27 = OpConstant %6 3
%28 = OpConstant %6 4
%29 = OpConstantComposite %24 %27 %28
%30 = OpTypeVector %10 2
%33 = OpConstant %10 3
%34 = OpConstant %10 4
%35 = OpConstantComposite %30 %33 %34
%36 = OpTypeBool
%37 = OpTypeVector %36 2
%38 = OpConstantTrue %36
%39 = OpConstantComposite %37 %38 %38
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
ASSERT_TRUE(IsValid(env, context.get()));
FactManager fact_manager;
spvtools::ValidatorOptions validator_options;
TransformationContext transformation_context(&fact_manager,
validator_options);
auto insert_before = MakeInstructionDescriptor(5, SpvOpReturn, 0);
uint32_t fresh_id = 50;
for (auto synonym_type : {protobufs::TransformationAddSynonym::ADD_ZERO,
protobufs::TransformationAddSynonym::SUB_ZERO,
protobufs::TransformationAddSynonym::MUL_ONE}) {
ASSERT_TRUE(
TransformationAddSynonym::IsAdditionalConstantRequired(synonym_type));
// Can't create a synonym of a scalar or a vector of a wrong (in this case -
// boolean) type.
ASSERT_FALSE(
TransformationAddSynonym(38, synonym_type, fresh_id, insert_before)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(
TransformationAddSynonym(39, synonym_type, fresh_id, insert_before)
.IsApplicable(context.get(), transformation_context));
// Required constant is not present in the module.
ASSERT_FALSE(
TransformationAddSynonym(13, synonym_type, fresh_id, insert_before)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(
TransformationAddSynonym(35, synonym_type, fresh_id, insert_before)
.IsApplicable(context.get(), transformation_context));
for (auto result_id : {9, 17, 23, 29}) {
TransformationAddSynonym transformation(result_id, synonym_type, fresh_id,
insert_before);
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
transformation.Apply(context.get(), &transformation_context);
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(result_id, {}),
MakeDataDescriptor(fresh_id, {})));
++fresh_id;
}
}
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
%6 = OpTypeInt 32 1
%7 = OpConstant %6 0
%8 = OpConstant %6 1
%9 = OpConstant %6 34
%10 = OpTypeInt 32 0
%13 = OpConstant %10 34
%14 = OpTypeFloat 32
%15 = OpConstant %14 0
%16 = OpConstant %14 1
%17 = OpConstant %14 34
%18 = OpTypeVector %14 2
%19 = OpConstantComposite %18 %15 %15
%20 = OpConstantComposite %18 %16 %16
%21 = OpConstant %14 3
%22 = OpConstant %14 4
%23 = OpConstantComposite %18 %21 %22
%24 = OpTypeVector %6 2
%25 = OpConstantComposite %24 %7 %7
%26 = OpConstantComposite %24 %8 %8
%27 = OpConstant %6 3
%28 = OpConstant %6 4
%29 = OpConstantComposite %24 %27 %28
%30 = OpTypeVector %10 2
%33 = OpConstant %10 3
%34 = OpConstant %10 4
%35 = OpConstantComposite %30 %33 %34
%36 = OpTypeBool
%37 = OpTypeVector %36 2
%38 = OpConstantTrue %36
%39 = OpConstantComposite %37 %38 %38
%4 = OpFunction %2 None %3
%5 = OpLabel
%50 = OpIAdd %6 %9 %7
%51 = OpFAdd %14 %17 %15
%52 = OpFAdd %18 %23 %19
%53 = OpIAdd %24 %29 %25
%54 = OpISub %6 %9 %7
%55 = OpFSub %14 %17 %15
%56 = OpFSub %18 %23 %19
%57 = OpISub %24 %29 %25
%58 = OpIMul %6 %9 %8
%59 = OpFMul %14 %17 %16
%60 = OpFMul %18 %23 %20
%61 = OpIMul %24 %29 %26
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
}
TEST(TransformationAddSynonymTest, LogicalAndLogicalOr) {
std::string 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 = OpConstantFalse %6
%9 = OpConstantTrue %6
%10 = OpTypeVector %6 2
%11 = OpConstantComposite %10 %7 %9
%12 = OpConstantComposite %10 %7 %7
%13 = OpConstantComposite %10 %9 %9
%14 = OpTypeFloat 32
%17 = OpConstant %14 35
%18 = OpTypeVector %14 2
%21 = OpConstant %14 3
%22 = OpConstant %14 4
%23 = OpConstantComposite %18 %21 %22
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
ASSERT_TRUE(IsValid(env, context.get()));
FactManager fact_manager;
spvtools::ValidatorOptions validator_options;
TransformationContext transformation_context(&fact_manager,
validator_options);
auto insert_before = MakeInstructionDescriptor(5, SpvOpReturn, 0);
uint32_t fresh_id = 50;
for (auto synonym_type : {protobufs::TransformationAddSynonym::LOGICAL_AND,
protobufs::TransformationAddSynonym::LOGICAL_OR}) {
ASSERT_TRUE(
TransformationAddSynonym::IsAdditionalConstantRequired(synonym_type));
// Can't create a synonym of a scalar or a vector of a wrong (in this case -
// float) type.
ASSERT_FALSE(
TransformationAddSynonym(17, synonym_type, fresh_id, insert_before)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(
TransformationAddSynonym(23, synonym_type, fresh_id, insert_before)
.IsApplicable(context.get(), transformation_context));
for (auto result_id : {9, 11}) {
TransformationAddSynonym transformation(result_id, synonym_type, fresh_id,
insert_before);
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
transformation.Apply(context.get(), &transformation_context);
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(result_id, {}),
MakeDataDescriptor(fresh_id, {})));
++fresh_id;
}
}
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
%6 = OpTypeBool
%7 = OpConstantFalse %6
%9 = OpConstantTrue %6
%10 = OpTypeVector %6 2
%11 = OpConstantComposite %10 %7 %9
%12 = OpConstantComposite %10 %7 %7
%13 = OpConstantComposite %10 %9 %9
%14 = OpTypeFloat 32
%17 = OpConstant %14 35
%18 = OpTypeVector %14 2
%21 = OpConstant %14 3
%22 = OpConstant %14 4
%23 = OpConstantComposite %18 %21 %22
%4 = OpFunction %2 None %3
%5 = OpLabel
%50 = OpLogicalAnd %6 %9 %9
%51 = OpLogicalAnd %10 %11 %13
%52 = OpLogicalOr %6 %9 %7
%53 = OpLogicalOr %10 %11 %12
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
}
TEST(TransformationAddSynonymTest, LogicalAndConstantIsNotPresent) {
std::string 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 = OpConstantFalse %6
%10 = OpTypeVector %6 2
%12 = OpConstantComposite %10 %7 %7
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
ASSERT_TRUE(IsValid(env, context.get()));
FactManager fact_manager;
spvtools::ValidatorOptions validator_options;
TransformationContext transformation_context(&fact_manager,
validator_options);
auto insert_before = MakeInstructionDescriptor(5, SpvOpReturn, 0);
const auto synonym_type = protobufs::TransformationAddSynonym::LOGICAL_AND;
// Required constant is not present in the module.
ASSERT_FALSE(TransformationAddSynonym(7, synonym_type, 50, insert_before)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationAddSynonym(12, synonym_type, 50, insert_before)
.IsApplicable(context.get(), transformation_context));
}
TEST(TransformationAddSynonymTest, LogicalOrConstantIsNotPresent) {
std::string 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 = OpConstantTrue %6
%10 = OpTypeVector %6 2
%12 = OpConstantComposite %10 %7 %7
%4 = OpFunction %2 None %3
%5 = OpLabel
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
ASSERT_TRUE(IsValid(env, context.get()));
FactManager fact_manager;
spvtools::ValidatorOptions validator_options;
TransformationContext transformation_context(&fact_manager,
validator_options);
auto insert_before = MakeInstructionDescriptor(5, SpvOpReturn, 0);
const auto synonym_type = protobufs::TransformationAddSynonym::LOGICAL_OR;
// Required constant is not present in the module.
ASSERT_FALSE(TransformationAddSynonym(7, synonym_type, 50, insert_before)
.IsApplicable(context.get(), transformation_context));
ASSERT_FALSE(TransformationAddSynonym(12, synonym_type, 50, insert_before)
.IsApplicable(context.get(), transformation_context));
}
TEST(TransformationAddSynonymTest, CopyObject) {
std::string shader = R"(
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %4 "main"
OpExecutionMode %4 OriginUpperLeft
OpSource ESSL 310
OpDecorate %8 RelaxedPrecision
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%9 = OpConstant %6 4
%10 = OpTypeFloat 32
%11 = OpTypePointer Function %10
%13 = OpConstant %10 4
%14 = OpTypeVector %10 2
%15 = OpTypePointer Function %14
%17 = OpConstant %10 3.4000001
%18 = OpConstantComposite %14 %17 %17
%19 = OpTypeBool
%20 = OpTypeStruct %19
%21 = OpTypePointer Function %20
%23 = OpConstantTrue %19
%24 = OpConstantComposite %20 %23
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
%12 = OpVariable %11 Function
%16 = OpVariable %15 Function
%22 = OpVariable %21 Function
OpStore %8 %9
OpStore %12 %13
OpStore %16 %18
OpStore %22 %24
OpReturn
OpFunctionEnd
)";
const auto env = SPV_ENV_UNIVERSAL_1_3;
const auto consumer = nullptr;
const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
ASSERT_TRUE(IsValid(env, context.get()));
FactManager fact_manager;
spvtools::ValidatorOptions validator_options;
TransformationContext transformation_context(&fact_manager,
validator_options);
auto insert_before = MakeInstructionDescriptor(5, SpvOpReturn, 0);
const auto synonym_type = protobufs::TransformationAddSynonym::COPY_OBJECT;
ASSERT_FALSE(
TransformationAddSynonym::IsAdditionalConstantRequired(synonym_type));
uint32_t fresh_id = 50;
for (auto result_id : {9, 13, 17, 18, 23, 24, 22}) {
TransformationAddSynonym transformation(result_id, synonym_type, fresh_id,
insert_before);
ASSERT_TRUE(
transformation.IsApplicable(context.get(), transformation_context));
transformation.Apply(context.get(), &transformation_context);
ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(result_id, {}),
MakeDataDescriptor(fresh_id, {})));
++fresh_id;
}
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
OpDecorate %8 RelaxedPrecision
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeInt 32 1
%7 = OpTypePointer Function %6
%9 = OpConstant %6 4
%10 = OpTypeFloat 32
%11 = OpTypePointer Function %10
%13 = OpConstant %10 4
%14 = OpTypeVector %10 2
%15 = OpTypePointer Function %14
%17 = OpConstant %10 3.4000001
%18 = OpConstantComposite %14 %17 %17
%19 = OpTypeBool
%20 = OpTypeStruct %19
%21 = OpTypePointer Function %20
%23 = OpConstantTrue %19
%24 = OpConstantComposite %20 %23
%4 = OpFunction %2 None %3
%5 = OpLabel
%8 = OpVariable %7 Function
%12 = OpVariable %11 Function
%16 = OpVariable %15 Function
%22 = OpVariable %21 Function
OpStore %8 %9
OpStore %12 %13
OpStore %16 %18
OpStore %22 %24
%50 = OpCopyObject %6 %9
%51 = OpCopyObject %10 %13
%52 = OpCopyObject %10 %17
%53 = OpCopyObject %14 %18
%54 = OpCopyObject %19 %23
%55 = OpCopyObject %20 %24
%56 = OpCopyObject %21 %22
OpReturn
OpFunctionEnd
)";
ASSERT_TRUE(IsEqual(env, expected_shader, context.get()));
}
} // namespace
} // namespace fuzz
} // namespace spvtools