spirv-fuzz: Fix width in FuzzerPassAddEquationInstructions (#3685)

Fixes FuzzerPassAddEquationInstructions to check whether certain int/float type widths are supported to avoid creating unsupported types.

Fixes #3669.
This commit is contained in:
Vasyl Teliman 2020-08-12 18:39:23 +03:00 committed by GitHub
parent f0ca96d12c
commit be099cde1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 77 additions and 16 deletions

View File

@ -21,6 +21,26 @@
namespace spvtools {
namespace fuzz {
namespace {
bool IsBitWidthSupported(opt::IRContext* ir_context, uint32_t bit_width) {
switch (bit_width) {
case 32:
return true;
case 64:
return ir_context->get_feature_mgr()->HasCapability(
SpvCapabilityFloat64) &&
ir_context->get_feature_mgr()->HasCapability(SpvCapabilityInt64);
case 16:
return ir_context->get_feature_mgr()->HasCapability(
SpvCapabilityFloat16) &&
ir_context->get_feature_mgr()->HasCapability(SpvCapabilityInt16);
default:
return false;
}
}
} // namespace
FuzzerPassAddEquationInstructions::FuzzerPassAddEquationInstructions(
opt::IRContext* ir_context, TransformationContext* transformation_context,
@ -76,8 +96,22 @@ void FuzzerPassAddEquationInstructions::Apply() {
switch (opcode) {
case SpvOpConvertSToF:
case SpvOpConvertUToF: {
auto candidate_instructions =
GetIntegerInstructions(available_instructions);
std::vector<const opt::Instruction*> candidate_instructions;
for (const auto* inst :
GetIntegerInstructions(available_instructions)) {
const auto* type =
GetIRContext()->get_type_mgr()->GetType(inst->type_id());
assert(type && "|inst| has invalid type");
if (const auto* vector_type = type->AsVector()) {
type = vector_type->element_type();
}
if (IsBitWidthSupported(GetIRContext(),
type->AsInteger()->width())) {
candidate_instructions.push_back(inst);
}
}
if (candidate_instructions.empty()) {
break;
@ -112,20 +146,8 @@ void FuzzerPassAddEquationInstructions::Apply() {
return;
}
case SpvOpBitcast: {
std::vector<const opt::Instruction*> candidate_instructions;
for (const auto* inst : available_instructions) {
const auto* type =
GetIRContext()->get_type_mgr()->GetType(inst->type_id());
assert(type && "Instruction has invalid type");
if ((type->AsVector() &&
(type->AsVector()->element_type()->AsInteger() ||
type->AsVector()->element_type()->AsFloat())) ||
type->AsInteger() || type->AsFloat()) {
// We support OpBitcast for only scalars or vectors of
// numerical type.
candidate_instructions.push_back(inst);
}
}
const auto candidate_instructions =
GetNumericalInstructions(available_instructions);
if (!candidate_instructions.empty()) {
const auto* operand_inst =
@ -356,5 +378,36 @@ FuzzerPassAddEquationInstructions::RestrictToElementBitWidth(
return result;
}
std::vector<opt::Instruction*>
FuzzerPassAddEquationInstructions::GetNumericalInstructions(
const std::vector<opt::Instruction*>& instructions) const {
std::vector<opt::Instruction*> result;
for (auto* inst : instructions) {
const auto* type = GetIRContext()->get_type_mgr()->GetType(inst->type_id());
assert(type && "Instruction has invalid type");
if (const auto* vector_type = type->AsVector()) {
type = vector_type->element_type();
}
if (!type->AsInteger() && !type->AsFloat()) {
// Only numerical scalars or vectors of numerical components are
// supported.
continue;
}
if (!IsBitWidthSupported(GetIRContext(), type->AsInteger()
? type->AsInteger()->width()
: type->AsFloat()->width())) {
continue;
}
result.push_back(inst);
}
return result;
}
} // namespace fuzz
} // namespace spvtools

View File

@ -51,6 +51,14 @@ class FuzzerPassAddEquationInstructions : public FuzzerPass {
std::vector<opt::Instruction*> GetBooleanInstructions(
const std::vector<opt::Instruction*>& instructions) const;
// Yields those instructions in |instructions| that have a scalar numerical or
// a vector of numerical components type. Only 16, 32 and 64-bit numericals
// are supported if both OpTypeInt and OpTypeFloat instructions can be created
// with the specified width (e.g. for 16-bit types both Float16 and Int16
// capabilities must be present).
std::vector<opt::Instruction*> GetNumericalInstructions(
const std::vector<opt::Instruction*>& instructions) const;
// Requires that |instructions| are scalars or vectors of some type. Returns
// only those instructions whose width is |width|. If |width| is 1 this means
// the scalars.