spirv-fuzz: Add fuzzerutil::FindOrCreate* (#3479)

Part of #3428.
This commit is contained in:
Vasyl Teliman 2020-07-02 12:46:49 +03:00 committed by GitHub
parent fba90d6b0a
commit 4a92579a45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 256 additions and 43 deletions

View File

@ -28,6 +28,7 @@
#include "source/fuzz/transformation_add_type_int.h"
#include "source/fuzz/transformation_add_type_matrix.h"
#include "source/fuzz/transformation_add_type_pointer.h"
#include "source/fuzz/transformation_add_type_struct.h"
#include "source/fuzz/transformation_add_type_vector.h"
namespace spvtools {
@ -162,9 +163,8 @@ uint32_t FuzzerPass::FindOrCreateBoolType() {
}
uint32_t FuzzerPass::FindOrCreateIntegerType(uint32_t width, bool is_signed) {
opt::analysis::Integer int_type(width, is_signed);
auto existing_id = GetIRContext()->get_type_mgr()->GetId(&int_type);
if (existing_id) {
if (auto existing_id =
fuzzerutil::MaybeGetIntegerType(GetIRContext(), width, is_signed)) {
return existing_id;
}
auto result = GetFuzzerContext()->GetFreshId();
@ -173,9 +173,7 @@ uint32_t FuzzerPass::FindOrCreateIntegerType(uint32_t width, bool is_signed) {
}
uint32_t FuzzerPass::FindOrCreateFloatType(uint32_t width) {
opt::analysis::Float float_type(width);
auto existing_id = GetIRContext()->get_type_mgr()->GetId(&float_type);
if (existing_id) {
if (auto existing_id = fuzzerutil::MaybeGetFloatType(GetIRContext(), width)) {
return existing_id;
}
auto result = GetFuzzerContext()->GetFreshId();
@ -205,14 +203,8 @@ uint32_t FuzzerPass::FindOrCreateFunctionType(
uint32_t FuzzerPass::FindOrCreateVectorType(uint32_t component_type_id,
uint32_t component_count) {
assert(component_count >= 2 && component_count <= 4 &&
"Precondition: component count must be in range [2, 4].");
opt::analysis::Type* component_type =
GetIRContext()->get_type_mgr()->GetType(component_type_id);
assert(component_type && "Precondition: the component type must exist.");
opt::analysis::Vector vector_type(component_type, component_count);
auto existing_id = GetIRContext()->get_type_mgr()->GetId(&vector_type);
if (existing_id) {
if (auto existing_id = fuzzerutil::MaybeGetVectorType(
GetIRContext(), component_type_id, component_count)) {
return existing_id;
}
auto result = GetFuzzerContext()->GetFreshId();
@ -242,6 +234,17 @@ uint32_t FuzzerPass::FindOrCreateMatrixType(uint32_t column_count,
return result;
}
uint32_t FuzzerPass::FindOrCreateStructType(
const std::vector<uint32_t>& component_type_ids) {
if (auto existing_id =
fuzzerutil::MaybeGetStructType(GetIRContext(), component_type_ids)) {
return existing_id;
}
auto new_id = GetFuzzerContext()->GetFreshId();
ApplyTransformation(TransformationAddTypeStruct(new_id, component_type_ids));
return new_id;
}
uint32_t FuzzerPass::FindOrCreatePointerType(uint32_t base_type_id,
SpvStorageClass storage_class) {
// We do not use the type manager here, due to problems related to isomorphic

View File

@ -136,6 +136,13 @@ class FuzzerPass {
// type itself do not exist, transformations are applied to add them.
uint32_t FindOrCreateMatrixType(uint32_t column_count, uint32_t row_count);
// Returns the id of an OpTypeStruct instruction with |component_type_ids| as
// type ids for struct's components. If no such a struct type exists,
// transformations are applied to add it. |component_type_ids| may not contain
// a result id of an OpTypeFunction.
uint32_t FindOrCreateStructType(
const std::vector<uint32_t>& component_type_ids);
// Returns the id of a pointer type with base type |base_type_id| (which must
// already exist) and storage class |storage_class|. A transformation is
// applied to add the pointer if it does not already exist.

View File

@ -729,6 +729,146 @@ uint32_t FindOrCreateFunctionType(opt::IRContext* ir_context,
return result_id;
}
uint32_t MaybeGetIntegerType(opt::IRContext* ir_context, uint32_t width,
bool is_signed) {
opt::analysis::Integer type(width, is_signed);
return ir_context->get_type_mgr()->GetId(&type);
}
uint32_t MaybeGetFloatType(opt::IRContext* ir_context, uint32_t width) {
opt::analysis::Float type(width);
return ir_context->get_type_mgr()->GetId(&type);
}
uint32_t MaybeGetVectorType(opt::IRContext* ir_context,
uint32_t component_type_id,
uint32_t element_count) {
const auto* component_type =
ir_context->get_type_mgr()->GetType(component_type_id);
assert(component_type &&
(component_type->AsInteger() || component_type->AsFloat() ||
component_type->AsBool()) &&
"|component_type_id| is invalid");
assert(element_count >= 2 && element_count <= 4 &&
"Precondition: component count must be in range [2, 4].");
opt::analysis::Vector type(component_type, element_count);
return ir_context->get_type_mgr()->GetId(&type);
}
uint32_t MaybeGetStructType(opt::IRContext* ir_context,
const std::vector<uint32_t>& component_type_ids) {
std::vector<const opt::analysis::Type*> component_types;
component_types.reserve(component_type_ids.size());
for (auto type_id : component_type_ids) {
const auto* component_type = ir_context->get_type_mgr()->GetType(type_id);
assert(component_type && !component_type->AsFunction() &&
"Component type is invalid");
component_types.push_back(component_type);
}
opt::analysis::Struct type(component_types);
return ir_context->get_type_mgr()->GetId(&type);
}
void AddIntegerType(opt::IRContext* ir_context, uint32_t result_id,
uint32_t width, bool is_signed) {
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
ir_context, SpvOpTypeInt, 0, result_id,
opt::Instruction::OperandList{
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {width}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {is_signed ? 1u : 0u}}}));
UpdateModuleIdBound(ir_context, result_id);
}
void AddFloatType(opt::IRContext* ir_context, uint32_t result_id,
uint32_t width) {
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
ir_context, SpvOpTypeFloat, 0, result_id,
opt::Instruction::OperandList{
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {width}}}));
UpdateModuleIdBound(ir_context, result_id);
}
void AddVectorType(opt::IRContext* ir_context, uint32_t result_id,
uint32_t component_type_id, uint32_t element_count) {
const auto* component_type =
ir_context->get_type_mgr()->GetType(component_type_id);
(void)component_type; // Make compiler happy in release mode.
assert(component_type &&
(component_type->AsInteger() || component_type->AsFloat() ||
component_type->AsBool()) &&
"|component_type_id| is invalid");
assert(element_count >= 2 && element_count <= 4 &&
"Precondition: component count must be in range [2, 4].");
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
ir_context, SpvOpTypeVector, 0, result_id,
opt::Instruction::OperandList{
{SPV_OPERAND_TYPE_ID, {component_type_id}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {element_count}}}));
UpdateModuleIdBound(ir_context, result_id);
}
void AddStructType(opt::IRContext* ir_context, uint32_t result_id,
const std::vector<uint32_t>& component_type_ids) {
opt::Instruction::OperandList operands;
operands.reserve(component_type_ids.size());
for (auto type_id : component_type_ids) {
const auto* type = ir_context->get_type_mgr()->GetType(type_id);
(void)type; // Make compiler happy in release mode.
assert(type && !type->AsFunction() && "Component's type id is invalid");
operands.push_back({SPV_OPERAND_TYPE_ID, {type_id}});
}
ir_context->AddType(MakeUnique<opt::Instruction>(
ir_context, SpvOpTypeStruct, 0, result_id, std::move(operands)));
UpdateModuleIdBound(ir_context, result_id);
}
uint32_t FindOrCreateIntegerType(opt::IRContext* ir_context, uint32_t result_id,
uint32_t width, bool is_signed) {
if (auto existing_id = MaybeGetIntegerType(ir_context, width, is_signed)) {
return existing_id;
}
AddIntegerType(ir_context, result_id, width, is_signed);
return result_id;
}
uint32_t FindOrCreateFloatType(opt::IRContext* ir_context, uint32_t result_id,
uint32_t width) {
if (auto existing_id = MaybeGetFloatType(ir_context, width)) {
return existing_id;
}
AddFloatType(ir_context, result_id, width);
return result_id;
}
uint32_t FindOrCreateVectorType(opt::IRContext* ir_context, uint32_t result_id,
uint32_t component_type_id,
uint32_t element_count) {
if (auto existing_id =
MaybeGetVectorType(ir_context, component_type_id, element_count)) {
return existing_id;
}
AddVectorType(ir_context, result_id, component_type_id, element_count);
return result_id;
}
uint32_t FindOrCreateStructType(
opt::IRContext* ir_context, uint32_t result_id,
const std::vector<uint32_t>& component_type_ids) {
if (auto existing_id = MaybeGetStructType(ir_context, component_type_ids)) {
return existing_id;
}
AddStructType(ir_context, result_id, component_type_ids);
return result_id;
}
} // namespace fuzzerutil
} // namespace fuzz

View File

@ -284,6 +284,84 @@ uint32_t FindOrCreateFunctionType(opt::IRContext* ir_context,
uint32_t result_id,
const std::vector<uint32_t>& type_ids);
// Returns a result id of an OpTypeInt instruction if present. Returns 0
// otherwise.
uint32_t MaybeGetIntegerType(opt::IRContext* ir_context, uint32_t width,
bool is_signed);
// Returns a result id of an OpTypeFloat instruction if present. Returns 0
// otherwise.
uint32_t MaybeGetFloatType(opt::IRContext* ir_context, uint32_t width);
// Returns a result id of an OpTypeVector instruction if present. Returns 0
// otherwise. |component_type_id| must be a valid result id of an OpTypeInt,
// OpTypeFloat or OpTypeBool instruction in the module. |element_count| must be
// in the range [2, 4].
uint32_t MaybeGetVectorType(opt::IRContext* ir_context,
uint32_t component_type_id, uint32_t element_count);
// Returns a result id of an OpTypeStruct instruction if present. Returns 0
// otherwise. |component_type_ids| may not contain a result id of an
// OpTypeFunction.
uint32_t MaybeGetStructType(opt::IRContext* ir_context,
const std::vector<uint32_t>& component_type_ids);
// Creates a new OpTypeInt instruction in the module. Updates module's id bound
// to accommodate for |result_id|.
void AddIntegerType(opt::IRContext* ir_context, uint32_t result_id,
uint32_t width, bool is_signed);
// Creates a new OpTypeFloat instruction in the module. Updates module's id
// bound to accommodate for |result_id|.
void AddFloatType(opt::IRContext* ir_context, uint32_t result_id,
uint32_t width);
// Creates a new OpTypeVector instruction in the module. |component_type_id|
// must be a valid result id of an OpTypeInt, OpTypeFloat or OpTypeBool
// instruction in the module. |element_count| must be in the range [2, 4].
// Updates module's id bound to accommodate for |result_id|.
void AddVectorType(opt::IRContext* ir_context, uint32_t result_id,
uint32_t component_type_id, uint32_t element_count);
// Creates a new OpTypeStruct instruction in the module. Updates module's id
// bound to accommodate for |result_id|. |component_type_ids| may not contain
// a result id of an OpTypeFunction.
void AddStructType(opt::IRContext* ir_context, uint32_t result_id,
const std::vector<uint32_t>& component_type_ids);
// Returns a result id of an OpTypeInt instruction in the module. Creates a new
// instruction with |result_id|, if no required OpTypeInt is present in the
// module, and returns |result_id|. Updates module's id bound to accommodate for
// |result_id|.
uint32_t FindOrCreateIntegerType(opt::IRContext* ir_context, uint32_t result_id,
uint32_t width, bool is_signed);
// Returns a result id of an OpTypeFloat instruction in the module. Creates a
// new instruction with |result_id|, if no required OpTypeFloat is present in
// the module, and returns |result_id|. Updates module's id bound
// to accommodate for |result_id|.
uint32_t FindOrCreateFloatType(opt::IRContext* ir_context, uint32_t result_id,
uint32_t width);
// Returns a result id of an OpTypeVector instruction in the module. Creates a
// new instruction with |result_id|, if no required OpTypeVector is present in
// the module, and returns |result_id|. |component_type_id| must be a valid
// result id of an OpTypeInt, OpTypeFloat or OpTypeBool instruction in the
// module. |element_count| must be in the range [2, 4]. Updates module's id
// bound to accommodate for |result_id|.
uint32_t FindOrCreateVectorType(opt::IRContext* ir_context, uint32_t result_id,
uint32_t component_type_id,
uint32_t element_count);
// Returns a result id of an OpTypeStruct instruction in the module. Creates a
// new instruction with |result_id|, if no required OpTypeStruct is present in
// the module, and returns |result_id|. Updates module's id bound
// to accommodate for |result_id|. |component_type_ids| may not contain a result
// id of an OpTypeFunction.
uint32_t FindOrCreateStructType(
opt::IRContext* ir_context, uint32_t result_id,
const std::vector<uint32_t>& component_type_ids);
} // namespace fuzzerutil
} // namespace fuzz

View File

@ -73,6 +73,7 @@ void TransformationAddParameter::Apply(
auto parameter_type_id =
fuzzerutil::GetTypeId(ir_context, message_.initializer_id());
assert(parameter_type_id != 0 && "Initializer has invalid type");
// Add new parameters to the function.
function->AddParameter(MakeUnique<opt::Instruction>(

View File

@ -38,17 +38,12 @@ bool TransformationAddTypeFloat::IsApplicable(
// Applicable if there is no float type with this width already declared in
// the module.
opt::analysis::Float float_type(message_.width());
return ir_context->get_type_mgr()->GetId(&float_type) == 0;
return fuzzerutil::MaybeGetFloatType(ir_context, message_.width()) == 0;
}
void TransformationAddTypeFloat::Apply(
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
opt::Instruction::OperandList width = {
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.width()}}};
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
ir_context, SpvOpTypeFloat, 0, message_.fresh_id(), width));
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
fuzzerutil::AddFloatType(ir_context, message_.fresh_id(), message_.width());
// We have added an instruction to the module, so need to be careful about the
// validity of existing analyses.
ir_context->InvalidateAnalysesExceptFor(

View File

@ -40,18 +40,14 @@ bool TransformationAddTypeInt::IsApplicable(
// Applicable if there is no int type with this width and signedness already
// declared in the module.
opt::analysis::Integer int_type(message_.width(), message_.is_signed());
return ir_context->get_type_mgr()->GetId(&int_type) == 0;
return fuzzerutil::MaybeGetIntegerType(ir_context, message_.width(),
message_.is_signed()) == 0;
}
void TransformationAddTypeInt::Apply(opt::IRContext* ir_context,
TransformationContext* /*unused*/) const {
opt::Instruction::OperandList in_operands = {
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.width()}},
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.is_signed() ? 1u : 0u}}};
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
ir_context, SpvOpTypeInt, 0, message_.fresh_id(), in_operands));
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
fuzzerutil::AddIntegerType(ir_context, message_.fresh_id(), message_.width(),
message_.is_signed());
// We have added an instruction to the module, so need to be careful about the
// validity of existing analyses.
ir_context->InvalidateAnalysesExceptFor(

View File

@ -50,13 +50,10 @@ bool TransformationAddTypeStruct::IsApplicable(
void TransformationAddTypeStruct::Apply(
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
opt::Instruction::OperandList in_operands;
for (auto member_type : message_.member_type_id()) {
in_operands.push_back({SPV_OPERAND_TYPE_ID, {member_type}});
}
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
ir_context, SpvOpTypeStruct, 0, message_.fresh_id(), in_operands));
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
fuzzerutil::AddStructType(
ir_context, message_.fresh_id(),
std::vector<uint32_t>(message_.member_type_id().begin(),
message_.member_type_id().end()));
// We have added an instruction to the module, so need to be careful about the
// validity of existing analyses.
ir_context->InvalidateAnalysesExceptFor(

View File

@ -46,13 +46,9 @@ bool TransformationAddTypeVector::IsApplicable(
void TransformationAddTypeVector::Apply(
opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
opt::Instruction::OperandList in_operands;
in_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.component_type_id()}});
in_operands.push_back(
{SPV_OPERAND_TYPE_LITERAL_INTEGER, {message_.component_count()}});
ir_context->module()->AddType(MakeUnique<opt::Instruction>(
ir_context, SpvOpTypeVector, 0, message_.fresh_id(), in_operands));
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
fuzzerutil::AddVectorType(ir_context, message_.fresh_id(),
message_.component_type_id(),
message_.component_count());
// We have added an instruction to the module, so need to be careful about the
// validity of existing analyses.
ir_context->InvalidateAnalysesExceptFor(