SPIRV-Tools/source/fuzz/transformation_replace_id_with_synonym.cpp
Alastair Donaldson 9e65f054d1
spirv-fuzz: Account for differing signedness in WrapVectorSynonym (#4414)
Makes the fuzzer pass and transformation that wraps vector synonyms
aware of the fact that integer operations can have arguments that
differ in signedness, and that the result type of such an operation
can have different sign from the argument types.

Fixes #4413.
2021-09-14 21:09:39 +00:00

120 lines
4.3 KiB
C++

// 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/transformation_replace_id_with_synonym.h"
#include <algorithm>
#include "source/fuzz/data_descriptor.h"
#include "source/fuzz/fuzzer_util.h"
#include "source/fuzz/id_use_descriptor.h"
#include "source/opt/types.h"
#include "source/util/make_unique.h"
namespace spvtools {
namespace fuzz {
TransformationReplaceIdWithSynonym::TransformationReplaceIdWithSynonym(
protobufs::TransformationReplaceIdWithSynonym message)
: message_(std::move(message)) {}
TransformationReplaceIdWithSynonym::TransformationReplaceIdWithSynonym(
protobufs::IdUseDescriptor id_use_descriptor, uint32_t synonymous_id) {
*message_.mutable_id_use_descriptor() = std::move(id_use_descriptor);
message_.set_synonymous_id(synonymous_id);
}
bool TransformationReplaceIdWithSynonym::IsApplicable(
opt::IRContext* ir_context,
const TransformationContext& transformation_context) const {
auto id_of_interest = message_.id_use_descriptor().id_of_interest();
// Does the fact manager know about the synonym?
auto data_descriptor_for_synonymous_id =
MakeDataDescriptor(message_.synonymous_id(), {});
if (!transformation_context.GetFactManager()->IsSynonymous(
MakeDataDescriptor(id_of_interest, {}),
data_descriptor_for_synonymous_id)) {
return false;
}
// Does the id use descriptor in the transformation identify an instruction?
auto use_instruction =
FindInstructionContainingUse(message_.id_use_descriptor(), ir_context);
if (!use_instruction) {
return false;
}
uint32_t type_id_of_interest =
ir_context->get_def_use_mgr()->GetDef(id_of_interest)->type_id();
uint32_t type_id_synonym = ir_context->get_def_use_mgr()
->GetDef(message_.synonymous_id())
->type_id();
// If the id of interest and the synonym are scalar or vector integer
// constants with different signedness, their use can only be swapped if the
// instruction is agnostic to the signedness of the operand.
if (!fuzzerutil::TypesAreCompatible(
ir_context, use_instruction->opcode(),
message_.id_use_descriptor().in_operand_index(), type_id_of_interest,
type_id_synonym)) {
return false;
}
// Is the use suitable for being replaced in principle?
if (!fuzzerutil::IdUseCanBeReplaced(
ir_context, transformation_context, use_instruction,
message_.id_use_descriptor().in_operand_index())) {
return false;
}
// The transformation is applicable if the synonymous id is available at the
// use point.
return fuzzerutil::IdIsAvailableAtUse(
ir_context, use_instruction,
message_.id_use_descriptor().in_operand_index(),
message_.synonymous_id());
}
void TransformationReplaceIdWithSynonym::Apply(
spvtools::opt::IRContext* ir_context,
TransformationContext* /*unused*/) const {
auto instruction_to_change =
FindInstructionContainingUse(message_.id_use_descriptor(), ir_context);
instruction_to_change->SetInOperand(
message_.id_use_descriptor().in_operand_index(),
{message_.synonymous_id()});
ir_context->get_def_use_mgr()->EraseUseRecordsOfOperandIds(
instruction_to_change);
ir_context->get_def_use_mgr()->AnalyzeInstUse(instruction_to_change);
// No analyses need to be invalidated, since the transformation is local to a
// block, and the def-use analysis has been updated.
}
protobufs::Transformation TransformationReplaceIdWithSynonym::ToMessage()
const {
protobufs::Transformation result;
*result.mutable_replace_id_with_synonym() = message_;
return result;
}
std::unordered_set<uint32_t> TransformationReplaceIdWithSynonym::GetFreshIds()
const {
return std::unordered_set<uint32_t>();
}
} // namespace fuzz
} // namespace spvtools