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.
diff --git a/source/fuzz/fuzzer_pass_add_equation_instructions.cpp b/source/fuzz/fuzzer_pass_add_equation_instructions.cpp
index 9170ada..62fcfea 100644
--- a/source/fuzz/fuzzer_pass_add_equation_instructions.cpp
+++ b/source/fuzz/fuzzer_pass_add_equation_instructions.cpp
@@ -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 @@
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 @@
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 @@
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
diff --git a/source/fuzz/fuzzer_pass_add_equation_instructions.h b/source/fuzz/fuzzer_pass_add_equation_instructions.h
index 8328b6b..9ce581e 100644
--- a/source/fuzz/fuzzer_pass_add_equation_instructions.h
+++ b/source/fuzz/fuzzer_pass_add_equation_instructions.h
@@ -51,6 +51,14 @@
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.