blob: 335e3cac0399148bfdd5a0e6fd9affceff8cb65c [file] [log] [blame]
// 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_add_useful_constructs.h"
#include "source/fuzz/transformation_add_constant_boolean.h"
#include "source/fuzz/transformation_add_constant_scalar.h"
#include "source/fuzz/transformation_add_type_boolean.h"
#include "source/fuzz/transformation_add_type_float.h"
#include "source/fuzz/transformation_add_type_int.h"
namespace spvtools {
namespace fuzz {
using opt::IRContext;
FuzzerPassAddUsefulConstructs::FuzzerPassAddUsefulConstructs(
opt::IRContext* ir_context, FactManager* fact_manager,
FuzzerContext* fuzzer_context,
protobufs::TransformationSequence* transformations)
: FuzzerPass(ir_context, fact_manager, fuzzer_context, transformations){};
FuzzerPassAddUsefulConstructs::~FuzzerPassAddUsefulConstructs() = default;
void FuzzerPassAddUsefulConstructs::MaybeAddIntConstant(
uint32_t width, bool is_signed, std::vector<uint32_t> data) const {
opt::analysis::Integer temp_int_type(width, is_signed);
assert(GetIRContext()->get_type_mgr()->GetId(&temp_int_type) &&
"int type should already be registered.");
auto registered_int_type = GetIRContext()
->get_type_mgr()
->GetRegisteredType(&temp_int_type)
->AsInteger();
auto int_type_id = GetIRContext()->get_type_mgr()->GetId(registered_int_type);
assert(int_type_id &&
"The relevant int type should have been added to the module already.");
opt::analysis::IntConstant int_constant(registered_int_type, data);
if (!GetIRContext()->get_constant_mgr()->FindConstant(&int_constant)) {
protobufs::TransformationAddConstantScalar add_constant_int =
transformation::MakeTransformationAddConstantScalar(
GetFuzzerContext()->GetFreshId(), int_type_id, data);
assert(transformation::IsApplicable(add_constant_int, GetIRContext(),
*GetFactManager()) &&
"Should be applicable by construction.");
transformation::Apply(add_constant_int, GetIRContext(), GetFactManager());
*GetTransformations()->add_transformation()->mutable_add_constant_scalar() =
add_constant_int;
}
}
void FuzzerPassAddUsefulConstructs::MaybeAddFloatConstant(
uint32_t width, std::vector<uint32_t> data) const {
opt::analysis::Float temp_float_type(width);
assert(GetIRContext()->get_type_mgr()->GetId(&temp_float_type) &&
"float type should already be registered.");
auto registered_float_type = GetIRContext()
->get_type_mgr()
->GetRegisteredType(&temp_float_type)
->AsFloat();
auto float_type_id =
GetIRContext()->get_type_mgr()->GetId(registered_float_type);
assert(
float_type_id &&
"The relevant float type should have been added to the module already.");
opt::analysis::FloatConstant float_constant(registered_float_type, data);
if (!GetIRContext()->get_constant_mgr()->FindConstant(&float_constant)) {
protobufs::TransformationAddConstantScalar add_constant_float =
transformation::MakeTransformationAddConstantScalar(
GetFuzzerContext()->GetFreshId(), float_type_id, data);
assert(transformation::IsApplicable(add_constant_float, GetIRContext(),
*GetFactManager()) &&
"Should be applicable by construction.");
transformation::Apply(add_constant_float, GetIRContext(), GetFactManager());
*GetTransformations()->add_transformation()->mutable_add_constant_scalar() =
add_constant_float;
}
}
void FuzzerPassAddUsefulConstructs::Apply() {
{
// Add boolean type if not present.
opt::analysis::Bool temp_bool_type;
if (!GetIRContext()->get_type_mgr()->GetId(&temp_bool_type)) {
protobufs::TransformationAddTypeBoolean add_type_boolean =
transformation::MakeTransformationAddTypeBoolean(
GetFuzzerContext()->GetFreshId());
assert(transformation::IsApplicable(add_type_boolean, GetIRContext(),
*GetFactManager()) &&
"Should be applicable by construction.");
transformation::Apply(add_type_boolean, GetIRContext(), GetFactManager());
*GetTransformations()->add_transformation()->mutable_add_type_boolean() =
add_type_boolean;
}
}
{
// Add signed and unsigned 32-bit integer types if not present.
for (auto is_signed : {true, false}) {
opt::analysis::Integer temp_int_type(32, is_signed);
if (!GetIRContext()->get_type_mgr()->GetId(&temp_int_type)) {
protobufs::TransformationAddTypeInt add_type_int =
transformation::MakeTransformationAddTypeInt(
GetFuzzerContext()->GetFreshId(), 32, is_signed);
assert(transformation::IsApplicable(add_type_int, GetIRContext(),
*GetFactManager()) &&
"Should be applicable by construction.");
transformation::Apply(add_type_int, GetIRContext(), GetFactManager());
*GetTransformations()->add_transformation()->mutable_add_type_int() =
add_type_int;
}
}
}
{
// Add 32-bit float type if not present.
opt::analysis::Float temp_float_type(32);
if (!GetIRContext()->get_type_mgr()->GetId(&temp_float_type)) {
protobufs::TransformationAddTypeFloat add_type_float =
transformation::MakeTransformationAddTypeFloat(
GetFuzzerContext()->GetFreshId(), 32);
assert(transformation::IsApplicable(add_type_float, GetIRContext(),
*GetFactManager()) &&
"Should be applicable by construction.");
transformation::Apply(add_type_float, GetIRContext(), GetFactManager());
*GetTransformations()->add_transformation()->mutable_add_type_float() =
add_type_float;
}
}
// Add boolean constants true and false if not present.
opt::analysis::Bool temp_bool_type;
auto bool_type = GetIRContext()
->get_type_mgr()
->GetRegisteredType(&temp_bool_type)
->AsBool();
for (auto boolean_value : {true, false}) {
// Add OpConstantTrue/False if not already there.
opt::analysis::BoolConstant bool_constant(bool_type, boolean_value);
if (!GetIRContext()->get_constant_mgr()->FindConstant(&bool_constant)) {
protobufs::TransformationAddConstantBoolean add_constant_boolean =
transformation::MakeTransformationAddConstantBoolean(
GetFuzzerContext()->GetFreshId(), boolean_value);
assert(transformation::IsApplicable(add_constant_boolean, GetIRContext(),
*GetFactManager()) &&
"Should be applicable by construction.");
transformation::Apply(add_constant_boolean, GetIRContext(),
GetFactManager());
*GetTransformations()
->add_transformation()
->mutable_add_constant_boolean() = add_constant_boolean;
}
}
// Add signed and unsigned 32-bit integer constants 0 and 1 if not present.
for (auto is_signed : {true, false}) {
for (auto value : {0u, 1u}) {
MaybeAddIntConstant(32, is_signed, {value});
}
}
// Add 32-bit float constants 0.0 and 1.0 if not present.
uint32_t uint_data[2];
float float_data[2] = {0.0, 1.0};
memcpy(uint_data, float_data, sizeof(float_data));
for (unsigned int& datum : uint_data) {
MaybeAddFloatConstant(32, {datum});
}
}
} // namespace fuzz
} // namespace spvtools