spirv-fuzz: Remove non-deterministic behaviour (#3608)

Fixes #3607.
This commit is contained in:
Vasyl Teliman 2020-07-29 19:47:12 +03:00 committed by GitHub
parent f9b088fe0d
commit 7e75fea9ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 65 additions and 52 deletions

View File

@ -98,7 +98,7 @@ void FuzzerPassReplaceParamsWithStruct::Apply() {
parameter_id.push_back(params[index]->result_id());
}
std::unordered_map<uint32_t, uint32_t> caller_id_to_fresh_id;
std::map<uint32_t, uint32_t> caller_id_to_fresh_id;
for (const auto* inst :
fuzzerutil::GetCallers(GetIRContext(), function.result_id())) {
caller_id_to_fresh_id[inst->result_id()] =

View File

@ -1273,6 +1273,31 @@ bool TypesAreEqualUpToSign(opt::IRContext* ir_context, uint32_t type1_id,
return false;
}
std::map<uint32_t, uint32_t> RepeatedUInt32PairToMap(
const google::protobuf::RepeatedPtrField<protobufs::UInt32Pair>& data) {
std::map<uint32_t, uint32_t> result;
for (const auto& entry : data) {
result[entry.first()] = entry.second();
}
return result;
}
google::protobuf::RepeatedPtrField<protobufs::UInt32Pair>
MapToRepeatedUInt32Pair(const std::map<uint32_t, uint32_t>& data) {
google::protobuf::RepeatedPtrField<protobufs::UInt32Pair> result;
for (const auto& entry : data) {
protobufs::UInt32Pair pair;
pair.set_first(entry.first);
pair.set_second(entry.second);
*result.Add() = std::move(pair);
}
return result;
}
} // namespace fuzzerutil
} // namespace fuzz

View File

@ -15,6 +15,7 @@
#ifndef SOURCE_FUZZ_FUZZER_UTIL_H_
#define SOURCE_FUZZ_FUZZER_UTIL_H_
#include <map>
#include <vector>
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
@ -463,6 +464,16 @@ inline uint32_t FloatToWord(float value) {
bool TypesAreEqualUpToSign(opt::IRContext* ir_context, uint32_t type1_id,
uint32_t type2_id);
// Converts repeated field of UInt32Pair to a map. If two or more equal values
// of |UInt32Pair::first()| are available in |data|, the last value of
// |UInt32Pair::second()| is used.
std::map<uint32_t, uint32_t> RepeatedUInt32PairToMap(
const google::protobuf::RepeatedPtrField<protobufs::UInt32Pair>& data);
// Converts a map into a repeated field of UInt32Pair.
google::protobuf::RepeatedPtrField<protobufs::UInt32Pair>
MapToRepeatedUInt32Pair(const std::map<uint32_t, uint32_t>& data);
} // namespace fuzzerutil
} // namespace fuzz

View File

@ -1389,12 +1389,9 @@ message TransformationReplaceParamsWithStruct {
uint32 fresh_parameter_id = 3;
// Fresh ids for struct objects containing values of replaced parameters.
// This map contains a fresh id for at least every result id of a relevant
// This field contains a fresh id for at least every result id of a relevant
// OpFunctionCall instruction.
//
// While maps are not fully deterministic, the way this map is used does not
// exhibit nondeterminism. Change to repeated Uint32Pair if this changes.
map<uint32, uint32> caller_id_to_fresh_composite_id = 4;
repeated UInt32Pair caller_id_to_fresh_composite_id = 4;
}

View File

@ -21,20 +21,6 @@
namespace spvtools {
namespace fuzz {
namespace {
std::map<uint32_t, uint32_t> PairSequenceToMap(
const google::protobuf::RepeatedPtrField<protobufs::UInt32Pair>&
pair_sequence) {
std::map<uint32_t, uint32_t> result;
for (auto& pair : pair_sequence) {
result[pair.first()] = pair.second();
}
return result;
}
} // namespace
TransformationOutlineFunction::TransformationOutlineFunction(
const spvtools::fuzz::protobufs::TransformationOutlineFunction& message)
: message_(message) {}
@ -55,18 +41,10 @@ TransformationOutlineFunction::TransformationOutlineFunction(
message_.set_new_function_region_entry_block(new_function_region_entry_block);
message_.set_new_caller_result_id(new_caller_result_id);
message_.set_new_callee_result_id(new_callee_result_id);
for (auto& entry : input_id_to_fresh_id) {
protobufs::UInt32Pair pair;
pair.set_first(entry.first);
pair.set_second(entry.second);
*message_.add_input_id_to_fresh_id() = pair;
}
for (auto& entry : output_id_to_fresh_id) {
protobufs::UInt32Pair pair;
pair.set_first(entry.first);
pair.set_second(entry.second);
*message_.add_output_id_to_fresh_id() = pair;
}
*message_.mutable_input_id_to_fresh_id() =
fuzzerutil::MapToRepeatedUInt32Pair(input_id_to_fresh_id);
*message_.mutable_output_id_to_fresh_id() =
fuzzerutil::MapToRepeatedUInt32Pair(output_id_to_fresh_id);
}
bool TransformationOutlineFunction::IsApplicable(
@ -252,8 +230,8 @@ bool TransformationOutlineFunction::IsApplicable(
// For each region input id, i.e. every id defined outside the region but
// used inside the region, ...
std::map<uint32_t, uint32_t> input_id_to_fresh_id_map =
PairSequenceToMap(message_.input_id_to_fresh_id());
auto input_id_to_fresh_id_map =
fuzzerutil::RepeatedUInt32PairToMap(message_.input_id_to_fresh_id());
for (auto id : GetRegionInputIds(ir_context, region_set, exit_block)) {
// There needs to be a corresponding fresh id to be used as a function
// parameter.
@ -280,8 +258,8 @@ bool TransformationOutlineFunction::IsApplicable(
// For each region output id -- i.e. every id defined inside the region but
// used outside the region, ...
std::map<uint32_t, uint32_t> output_id_to_fresh_id_map =
PairSequenceToMap(message_.output_id_to_fresh_id());
auto output_id_to_fresh_id_map =
fuzzerutil::RepeatedUInt32PairToMap(message_.output_id_to_fresh_id());
for (auto id : GetRegionOutputIds(ir_context, region_set, exit_block)) {
if (
// ... there needs to be a corresponding fresh id that can hold the
@ -323,10 +301,10 @@ void TransformationOutlineFunction::Apply(
GetRegionOutputIds(ir_context, region_blocks, original_region_exit_block);
// Maps from input and output ids to fresh ids.
std::map<uint32_t, uint32_t> input_id_to_fresh_id_map =
PairSequenceToMap(message_.input_id_to_fresh_id());
std::map<uint32_t, uint32_t> output_id_to_fresh_id_map =
PairSequenceToMap(message_.output_id_to_fresh_id());
auto input_id_to_fresh_id_map =
fuzzerutil::RepeatedUInt32PairToMap(message_.input_id_to_fresh_id());
auto output_id_to_fresh_id_map =
fuzzerutil::RepeatedUInt32PairToMap(message_.output_id_to_fresh_id());
UpdateModuleIdBoundForFreshIds(ir_context, input_id_to_fresh_id_map,
output_id_to_fresh_id_map);

View File

@ -28,8 +28,7 @@ TransformationReplaceParamsWithStruct::TransformationReplaceParamsWithStruct(
TransformationReplaceParamsWithStruct::TransformationReplaceParamsWithStruct(
const std::vector<uint32_t>& parameter_id, uint32_t fresh_function_type_id,
uint32_t fresh_parameter_id,
const std::unordered_map<uint32_t, uint32_t>&
caller_id_to_fresh_composite_id) {
const std::map<uint32_t, uint32_t>& caller_id_to_fresh_composite_id) {
message_.set_fresh_function_type_id(fresh_function_type_id);
message_.set_fresh_parameter_id(fresh_parameter_id);
@ -37,9 +36,8 @@ TransformationReplaceParamsWithStruct::TransformationReplaceParamsWithStruct(
message_.add_parameter_id(id);
}
message_.mutable_caller_id_to_fresh_composite_id()->insert(
caller_id_to_fresh_composite_id.begin(),
caller_id_to_fresh_composite_id.end());
*message_.mutable_caller_id_to_fresh_composite_id() =
fuzzerutil::MapToRepeatedUInt32Pair(caller_id_to_fresh_composite_id);
}
bool TransformationReplaceParamsWithStruct::IsApplicable(
@ -103,13 +101,15 @@ bool TransformationReplaceParamsWithStruct::IsApplicable(
return false;
}
auto caller_id_to_fresh_composite_id = fuzzerutil::RepeatedUInt32PairToMap(
message_.caller_id_to_fresh_composite_id());
// Check that |callee_id_to_fresh_composite_id| is valid.
for (const auto* inst :
fuzzerutil::GetCallers(ir_context, function->result_id())) {
// Check that the callee is present in the map. It's ok if the map contains
// more ids that there are callees (those ids will not be used).
if (!message_.caller_id_to_fresh_composite_id().contains(
inst->result_id())) {
if (!caller_id_to_fresh_composite_id.count(inst->result_id())) {
return false;
}
}
@ -118,7 +118,7 @@ bool TransformationReplaceParamsWithStruct::IsApplicable(
std::vector<uint32_t> fresh_ids = {message_.fresh_function_type_id(),
message_.fresh_parameter_id()};
for (const auto& entry : message_.caller_id_to_fresh_composite_id()) {
for (const auto& entry : caller_id_to_fresh_composite_id) {
fresh_ids.push_back(entry.second);
}
@ -167,6 +167,9 @@ void TransformationReplaceParamsWithStruct::Apply(
}
}
auto caller_id_to_fresh_composite_id = fuzzerutil::RepeatedUInt32PairToMap(
message_.caller_id_to_fresh_composite_id());
// Update all function calls.
for (auto* inst : fuzzerutil::GetCallers(ir_context, function->result_id())) {
// Create a list of operands for the OpCompositeConstruct instruction.
@ -189,7 +192,7 @@ void TransformationReplaceParamsWithStruct::Apply(
// Insert OpCompositeConstruct before the function call.
auto fresh_composite_id =
message_.caller_id_to_fresh_composite_id().at(inst->result_id());
caller_id_to_fresh_composite_id.at(inst->result_id());
inst->InsertBefore(MakeUnique<opt::Instruction>(
ir_context, SpvOpCompositeConstruct, struct_type_id, fresh_composite_id,
std::move(composite_components)));

View File

@ -15,7 +15,7 @@
#ifndef SOURCE_FUZZ_TRANSFORMATION_REPLACE_PARAMS_WITH_STRUCT_H_
#define SOURCE_FUZZ_TRANSFORMATION_REPLACE_PARAMS_WITH_STRUCT_H_
#include <unordered_map>
#include <map>
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "source/fuzz/transformation.h"
@ -33,8 +33,7 @@ class TransformationReplaceParamsWithStruct : public Transformation {
TransformationReplaceParamsWithStruct(
const std::vector<uint32_t>& parameter_id,
uint32_t fresh_function_type_id, uint32_t fresh_parameter_id,
const std::unordered_map<uint32_t, uint32_t>&
caller_id_to_fresh_composite_id);
const std::map<uint32_t, uint32_t>& caller_id_to_fresh_composite_id);
// - Each element of |parameter_id| is a valid result id of some
// OpFunctionParameter instruction. All parameter ids must correspond to