mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-18 11:10:05 +00:00
parent
a0d8dc2b44
commit
bc2f78b7d9
@ -53,11 +53,12 @@ void FuzzerPassAddSynonyms::Apply() {
|
||||
// Select all instructions that can be used to create a synonym to.
|
||||
auto available_instructions = FindAvailableInstructions(
|
||||
function, block, inst_it,
|
||||
[synonym_type](opt::IRContext* ir_context, opt::Instruction* inst) {
|
||||
[synonym_type, this](opt::IRContext* ir_context,
|
||||
opt::Instruction* inst) {
|
||||
// Check that we can create a synonym to |inst| as described by
|
||||
// the |synonym_type| and insert it before |inst_it|.
|
||||
return TransformationAddSynonym::IsInstructionValid(
|
||||
ir_context, inst, synonym_type);
|
||||
ir_context, *GetTransformationContext(), inst, synonym_type);
|
||||
});
|
||||
|
||||
if (available_instructions.empty()) {
|
||||
|
@ -60,10 +60,10 @@ void FuzzerPassAddVectorShuffleInstructions::Apply() {
|
||||
std::vector<opt::Instruction*> vector_instructions =
|
||||
FindAvailableInstructions(
|
||||
function, block, instruction_iterator,
|
||||
[instruction_descriptor](
|
||||
[this, instruction_descriptor](
|
||||
opt::IRContext* ir_context,
|
||||
opt::Instruction* instruction) -> bool {
|
||||
if (!instruction->type_id()) {
|
||||
if (!instruction->result_id() || !instruction->type_id()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -73,6 +73,18 @@ void FuzzerPassAddVectorShuffleInstructions::Apply() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GetTransformationContext()
|
||||
->GetFactManager()
|
||||
->IdIsIrrelevant(instruction->result_id()) &&
|
||||
!fuzzerutil::CanMakeSynonymOf(ir_context,
|
||||
*GetTransformationContext(),
|
||||
instruction)) {
|
||||
// If the id is irrelevant, we can use it since it will not
|
||||
// participate in DataSynonym fact. Otherwise, we should be
|
||||
// able to produce a synonym out of the id.
|
||||
return false;
|
||||
}
|
||||
|
||||
return fuzzerutil::IdIsAvailableBeforeInstruction(
|
||||
ir_context,
|
||||
FindInstruction(instruction_descriptor, ir_context),
|
||||
|
@ -142,6 +142,9 @@ void FuzzerPassApplyIdSynonyms::Apply() {
|
||||
: parent_block->terminator();
|
||||
}
|
||||
|
||||
assert(!GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
|
||||
synonym_to_try->object()) &&
|
||||
"Irrelevant ids can't participate in DataSynonym facts");
|
||||
ApplyTransformation(TransformationCompositeExtract(
|
||||
MakeInstructionDescriptor(GetIRContext(),
|
||||
instruction_to_insert_before),
|
||||
|
@ -14,12 +14,10 @@
|
||||
|
||||
#include "source/fuzz/fuzzer_pass_construct_composites.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/transformation_composite_construct.h"
|
||||
#include "source/util/make_unique.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
@ -67,8 +65,23 @@ void FuzzerPassConstructComposites::Apply() {
|
||||
// program point) and suitable for making a synonym of, associate it
|
||||
// with the id of its result type.
|
||||
TypeIdToInstructions type_id_to_available_instructions;
|
||||
for (auto instruction : FindAvailableInstructions(
|
||||
function, block, inst_it, fuzzerutil::CanMakeSynonymOf)) {
|
||||
auto available_instructions = FindAvailableInstructions(
|
||||
function, block, inst_it,
|
||||
[this](opt::IRContext* ir_context, opt::Instruction* inst) {
|
||||
if (!inst->result_id() || !inst->type_id()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the id is irrelevant, we can use it since it will not
|
||||
// participate in DataSynonym fact. Otherwise, we should be able
|
||||
// to produce a synonym out of the id.
|
||||
return GetTransformationContext()
|
||||
->GetFactManager()
|
||||
->IdIsIrrelevant(inst->result_id()) ||
|
||||
fuzzerutil::CanMakeSynonymOf(
|
||||
ir_context, *GetTransformationContext(), inst);
|
||||
});
|
||||
for (auto instruction : available_instructions) {
|
||||
RecordAvailableInstruction(instruction,
|
||||
&type_id_to_available_instructions);
|
||||
}
|
||||
|
@ -55,8 +55,12 @@ void FuzzerPassCopyObjects::Apply() {
|
||||
}
|
||||
|
||||
std::vector<opt::Instruction*> relevant_instructions =
|
||||
FindAvailableInstructions(function, block, inst_it,
|
||||
fuzzerutil::CanMakeSynonymOf);
|
||||
FindAvailableInstructions(
|
||||
function, block, inst_it,
|
||||
[this](opt::IRContext* ir_context, opt::Instruction* inst) {
|
||||
return fuzzerutil::CanMakeSynonymOf(
|
||||
ir_context, *GetTransformationContext(), inst);
|
||||
});
|
||||
|
||||
// At this point, |relevant_instructions| contains all the instructions
|
||||
// we might think of copying.
|
||||
|
@ -14,6 +14,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include "source/fuzz/fuzzer_pass_interchange_zero_like_constants.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/id_use_descriptor.h"
|
||||
#include "source/fuzz/transformation_record_synonymous_constants.h"
|
||||
@ -83,13 +84,21 @@ void FuzzerPassInterchangeZeroLikeConstants::Apply() {
|
||||
|
||||
for (auto constant : GetIRContext()->GetConstants()) {
|
||||
uint32_t constant_id = constant->result_id();
|
||||
uint32_t toggled_id = FindOrCreateToggledConstant(constant);
|
||||
if (GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
|
||||
constant_id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t toggled_id = FindOrCreateToggledConstant(constant);
|
||||
if (!toggled_id) {
|
||||
// Not a zero-like constant
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(!GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
|
||||
toggled_id) &&
|
||||
"FindOrCreateToggledConstant can't produce an irrelevant id");
|
||||
|
||||
// Record synonymous constants
|
||||
ApplyTransformation(
|
||||
TransformationRecordSynonymousConstants(constant_id, toggled_id));
|
||||
|
@ -80,7 +80,7 @@ void FuzzerPassPushIdsThroughVariables::Apply() {
|
||||
std::vector<opt::Instruction*> value_instructions =
|
||||
FindAvailableInstructions(
|
||||
function, block, instruction_iterator,
|
||||
[basic_type_id, instruction_descriptor](
|
||||
[this, basic_type_id, instruction_descriptor](
|
||||
opt::IRContext* ir_context,
|
||||
opt::Instruction* instruction) -> bool {
|
||||
if (!instruction->result_id() || !instruction->type_id()) {
|
||||
@ -91,6 +91,12 @@ void FuzzerPassPushIdsThroughVariables::Apply() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fuzzerutil::CanMakeSynonymOf(ir_context,
|
||||
*GetTransformationContext(),
|
||||
instruction)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return fuzzerutil::IdIsAvailableBeforeInstruction(
|
||||
ir_context,
|
||||
FindInstruction(instruction_descriptor, ir_context),
|
||||
|
@ -248,7 +248,9 @@ bool CanInsertOpcodeBeforeInstruction(
|
||||
return opcode == SpvOpPhi || instruction_in_block->opcode() != SpvOpPhi;
|
||||
}
|
||||
|
||||
bool CanMakeSynonymOf(opt::IRContext* ir_context, opt::Instruction* inst) {
|
||||
bool CanMakeSynonymOf(opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context,
|
||||
opt::Instruction* inst) {
|
||||
if (inst->opcode() == SpvOpSampledImage) {
|
||||
// The SPIR-V data rules say that only very specific instructions may
|
||||
// may consume the result id of an OpSampledImage, and this excludes the
|
||||
@ -259,6 +261,11 @@ bool CanMakeSynonymOf(opt::IRContext* ir_context, opt::Instruction* inst) {
|
||||
// We can only make a synonym of an instruction that generates an id.
|
||||
return false;
|
||||
}
|
||||
if (transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
inst->result_id())) {
|
||||
// An irrelevant id can't be a synonym of anything.
|
||||
return false;
|
||||
}
|
||||
if (!inst->type_id()) {
|
||||
// We can only make a synonym of an instruction that has a type.
|
||||
return false;
|
||||
|
@ -93,7 +93,11 @@ bool CanInsertOpcodeBeforeInstruction(
|
||||
SpvOp opcode, const opt::BasicBlock::iterator& instruction_in_block);
|
||||
|
||||
// Determines whether it is OK to make a synonym of |inst|.
|
||||
bool CanMakeSynonymOf(opt::IRContext* ir_context, opt::Instruction* inst);
|
||||
// |transformation_context| is used to verify that the result id of |inst|
|
||||
// does not participate in IdIsIrrelevant fact.
|
||||
bool CanMakeSynonymOf(opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context,
|
||||
opt::Instruction* inst);
|
||||
|
||||
// Determines whether the given type is a composite; that is: an array, matrix,
|
||||
// struct or vector.
|
||||
|
@ -56,7 +56,8 @@ bool TransformationAddSynonym::IsApplicable(
|
||||
}
|
||||
|
||||
// Check that we can apply |synonym_type| to |result_id|.
|
||||
if (!IsInstructionValid(ir_context, synonym, message_.synonym_type())) {
|
||||
if (!IsInstructionValid(ir_context, transformation_context, synonym,
|
||||
message_.synonym_type())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -124,7 +125,8 @@ protobufs::Transformation TransformationAddSynonym::ToMessage() const {
|
||||
}
|
||||
|
||||
bool TransformationAddSynonym::IsInstructionValid(
|
||||
opt::IRContext* ir_context, opt::Instruction* inst,
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context, opt::Instruction* inst,
|
||||
protobufs::TransformationAddSynonym::SynonymType synonym_type) {
|
||||
// Instruction must have a result id, type id. We skip OpUndef and
|
||||
// OpConstantNull.
|
||||
@ -133,8 +135,10 @@ bool TransformationAddSynonym::IsInstructionValid(
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3177):
|
||||
// We can't create a synonym of an irrelevant id.
|
||||
if (!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context, inst)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (synonym_type) {
|
||||
case protobufs::TransformationAddSynonym::ADD_ZERO:
|
||||
case protobufs::TransformationAddSynonym::SUB_ZERO:
|
||||
@ -151,7 +155,9 @@ bool TransformationAddSynonym::IsInstructionValid(
|
||||
return type->AsInteger() || type->AsFloat();
|
||||
}
|
||||
case protobufs::TransformationAddSynonym::COPY_OBJECT:
|
||||
return fuzzerutil::CanMakeSynonymOf(ir_context, inst);
|
||||
// All checks for OpCopyObject are handled by
|
||||
// fuzzerutil::CanMakeSynonymOf.
|
||||
return true;
|
||||
case protobufs::TransformationAddSynonym::LOGICAL_AND:
|
||||
case protobufs::TransformationAddSynonym::LOGICAL_OR: {
|
||||
// The instruction must be either a scalar or a vector of booleans.
|
||||
|
@ -35,6 +35,7 @@ class TransformationAddSynonym : public Transformation {
|
||||
const protobufs::InstructionDescriptor& insert_before);
|
||||
|
||||
// - |result_id| must be a valid result id of some instruction in the module.
|
||||
// - |result_id| may not be an irrelevant id.
|
||||
// - |synonym_type| is a type of the synonymous instruction that will be
|
||||
// created.
|
||||
// - |synonym_fresh_id| is a fresh id.
|
||||
@ -57,7 +58,9 @@ class TransformationAddSynonym : public Transformation {
|
||||
// Returns true if we can create a synonym of |inst| according to the
|
||||
// |synonym_type|.
|
||||
static bool IsInstructionValid(
|
||||
opt::IRContext* ir_context, opt::Instruction* inst,
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context,
|
||||
opt::Instruction* inst,
|
||||
protobufs::TransformationAddSynonym::SynonymType synonym_type);
|
||||
|
||||
// Returns true if |synonym_type| requires an additional constant instruction
|
||||
|
@ -40,7 +40,8 @@ TransformationCompositeConstruct::TransformationCompositeConstruct(
|
||||
}
|
||||
|
||||
bool TransformationCompositeConstruct::IsApplicable(
|
||||
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context) const {
|
||||
if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
|
||||
// We require the id for the composite constructor to be unused.
|
||||
return false;
|
||||
@ -87,7 +88,20 @@ bool TransformationCompositeConstruct::IsApplicable(
|
||||
|
||||
// Now check whether every component being used to initialize the composite is
|
||||
// available at the desired program point.
|
||||
for (auto& component : message_.component()) {
|
||||
for (auto component : message_.component()) {
|
||||
auto* inst = ir_context->get_def_use_mgr()->GetDef(component);
|
||||
if (!inst) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We should be able to create a synonym of |component| if it's not
|
||||
// irrelevant.
|
||||
if (!transformation_context.GetFactManager()->IdIsIrrelevant(component) &&
|
||||
!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context,
|
||||
inst)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, insert_before,
|
||||
component)) {
|
||||
return false;
|
||||
@ -130,6 +144,11 @@ void TransformationCompositeConstruct::Apply(
|
||||
ir_context->get_type_mgr()->GetType(message_.composite_type_id());
|
||||
uint32_t index = 0;
|
||||
for (auto component : message_.component()) {
|
||||
if (transformation_context->GetFactManager()->IdIsIrrelevant(component)) {
|
||||
// Irrelevant ids do not participate in DataSynonym facts.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto component_type = ir_context->get_type_mgr()->GetType(
|
||||
ir_context->get_def_use_mgr()->GetDef(component)->type_id());
|
||||
if (composite_type->AsVector() && component_type->AsVector()) {
|
||||
|
@ -40,7 +40,8 @@ TransformationCompositeExtract::TransformationCompositeExtract(
|
||||
}
|
||||
|
||||
bool TransformationCompositeExtract::IsApplicable(
|
||||
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context) const {
|
||||
if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
|
||||
return false;
|
||||
}
|
||||
@ -54,6 +55,14 @@ bool TransformationCompositeExtract::IsApplicable(
|
||||
if (!composite_instruction) {
|
||||
return false;
|
||||
}
|
||||
if (!transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
message_.composite_id()) &&
|
||||
!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context,
|
||||
composite_instruction)) {
|
||||
// |composite_id| will participate in DataSynonym facts. Thus, it can't be
|
||||
// an irrelevant id.
|
||||
return false;
|
||||
}
|
||||
if (auto block = ir_context->get_instr_block(composite_instruction)) {
|
||||
if (composite_instruction == instruction_to_insert_before ||
|
||||
!ir_context->GetDominatorAnalysis(block->GetParent())
|
||||
@ -105,17 +114,20 @@ void TransformationCompositeExtract::Apply(
|
||||
|
||||
// Add the fact that the id storing the extracted element is synonymous with
|
||||
// the index into the structure.
|
||||
std::vector<uint32_t> indices;
|
||||
for (auto an_index : message_.index()) {
|
||||
indices.push_back(an_index);
|
||||
if (!transformation_context->GetFactManager()->IdIsIrrelevant(
|
||||
message_.composite_id())) {
|
||||
std::vector<uint32_t> indices;
|
||||
for (auto an_index : message_.index()) {
|
||||
indices.push_back(an_index);
|
||||
}
|
||||
protobufs::DataDescriptor data_descriptor_for_extracted_element =
|
||||
MakeDataDescriptor(message_.composite_id(), std::move(indices));
|
||||
protobufs::DataDescriptor data_descriptor_for_result_id =
|
||||
MakeDataDescriptor(message_.fresh_id(), {});
|
||||
transformation_context->GetFactManager()->AddFactDataSynonym(
|
||||
data_descriptor_for_extracted_element, data_descriptor_for_result_id,
|
||||
ir_context);
|
||||
}
|
||||
protobufs::DataDescriptor data_descriptor_for_extracted_element =
|
||||
MakeDataDescriptor(message_.composite_id(), std::move(indices));
|
||||
protobufs::DataDescriptor data_descriptor_for_result_id =
|
||||
MakeDataDescriptor(message_.fresh_id(), {});
|
||||
transformation_context->GetFactManager()->AddFactDataSynonym(
|
||||
data_descriptor_for_extracted_element, data_descriptor_for_result_id,
|
||||
ir_context);
|
||||
}
|
||||
|
||||
protobufs::Transformation TransformationCompositeExtract::ToMessage() const {
|
||||
|
@ -48,7 +48,8 @@ class TransformationCompositeExtract : public Transformation {
|
||||
// Adds an OpCompositeConstruct instruction before the instruction identified
|
||||
// by |message_.instruction_to_insert_before|, that extracts from
|
||||
// |message_.composite_id| via indices |message_.index| into
|
||||
// |message_.fresh_id|. Generates a data synonym fact relating
|
||||
// |message_.fresh_id|. If |composite_id| is not an irrelevant id,
|
||||
// generates a data synonym fact relating
|
||||
// |message_.fresh_id| to the extracted element.
|
||||
void Apply(opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const override;
|
||||
|
@ -37,7 +37,8 @@ TransformationEquationInstruction::TransformationEquationInstruction(
|
||||
}
|
||||
|
||||
bool TransformationEquationInstruction::IsApplicable(
|
||||
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context) const {
|
||||
// The result id must be fresh.
|
||||
if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
|
||||
return false;
|
||||
@ -59,6 +60,9 @@ bool TransformationEquationInstruction::IsApplicable(
|
||||
if (inst->opcode() == SpvOpUndef) {
|
||||
return false;
|
||||
}
|
||||
if (transformation_context.GetFactManager()->IdIsIrrelevant(id)) {
|
||||
return false;
|
||||
}
|
||||
if (!fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, insert_before,
|
||||
id)) {
|
||||
return false;
|
||||
|
@ -38,7 +38,8 @@ TransformationPushIdThroughVariable::TransformationPushIdThroughVariable(
|
||||
}
|
||||
|
||||
bool TransformationPushIdThroughVariable::IsApplicable(
|
||||
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context) const {
|
||||
// |message_.value_synonym_id| and |message_.variable_id| must be fresh.
|
||||
if (!fuzzerutil::IsFreshId(ir_context, message_.value_synonym_id()) ||
|
||||
!fuzzerutil::IsFreshId(ir_context, message_.variable_id())) {
|
||||
@ -73,6 +74,12 @@ bool TransformationPushIdThroughVariable::IsApplicable(
|
||||
return false;
|
||||
}
|
||||
|
||||
// |value_id| may not be an irrelevant id.
|
||||
if (transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
message_.value_id())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// A pointer type instruction pointing to the value type must be defined.
|
||||
auto pointer_type_id = fuzzerutil::MaybeGetPointerType(
|
||||
ir_context, value_instruction->type_id(),
|
||||
|
@ -36,6 +36,7 @@ class TransformationPushIdThroughVariable : public Transformation {
|
||||
|
||||
// - |message_.value_id| must be an instruction result id that has the same
|
||||
// type as the pointee type of |message_.pointer_id|
|
||||
// - |value_id| may not be an irrelevant id.
|
||||
// - |message_.value_synonym_id| must be fresh
|
||||
// - |message_.variable_id| must be fresh
|
||||
// - |message_.variable_storage_class| must be either StorageClassPrivate or
|
||||
|
@ -32,12 +32,19 @@ TransformationRecordSynonymousConstants::
|
||||
|
||||
bool TransformationRecordSynonymousConstants::IsApplicable(
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& /* unused */) const {
|
||||
const TransformationContext& transformation_context) const {
|
||||
// The ids must be different
|
||||
if (message_.constant1_id() == message_.constant2_id()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
message_.constant1_id()) ||
|
||||
transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
message_.constant2_id())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return AreEquivalentConstants(ir_context, message_.constant1_id(),
|
||||
message_.constant2_id());
|
||||
}
|
||||
@ -45,17 +52,10 @@ bool TransformationRecordSynonymousConstants::IsApplicable(
|
||||
void TransformationRecordSynonymousConstants::Apply(
|
||||
opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const {
|
||||
protobufs::FactDataSynonym fact_data_synonym;
|
||||
// Define the two equivalent data descriptors (just containing the ids)
|
||||
*fact_data_synonym.mutable_data1() =
|
||||
MakeDataDescriptor(message_.constant1_id(), {});
|
||||
*fact_data_synonym.mutable_data2() =
|
||||
MakeDataDescriptor(message_.constant2_id(), {});
|
||||
protobufs::Fact fact;
|
||||
*fact.mutable_data_synonym_fact() = fact_data_synonym;
|
||||
|
||||
// Add the fact to the fact manager
|
||||
transformation_context->GetFactManager()->AddFact(fact, ir_context);
|
||||
transformation_context->GetFactManager()->AddFactDataSynonym(
|
||||
MakeDataDescriptor(message_.constant1_id(), {}),
|
||||
MakeDataDescriptor(message_.constant2_id(), {}), ir_context);
|
||||
}
|
||||
|
||||
protobufs::Transformation TransformationRecordSynonymousConstants::ToMessage()
|
||||
@ -67,11 +67,14 @@ protobufs::Transformation TransformationRecordSynonymousConstants::ToMessage()
|
||||
|
||||
bool TransformationRecordSynonymousConstants::AreEquivalentConstants(
|
||||
opt::IRContext* ir_context, uint32_t constant_id1, uint32_t constant_id2) {
|
||||
opt::Instruction* def_1 = ir_context->get_def_use_mgr()->GetDef(constant_id1);
|
||||
opt::Instruction* def_2 = ir_context->get_def_use_mgr()->GetDef(constant_id2);
|
||||
const auto* def_1 = ir_context->get_def_use_mgr()->GetDef(constant_id1);
|
||||
const auto* def_2 = ir_context->get_def_use_mgr()->GetDef(constant_id2);
|
||||
|
||||
// Check that the definitions exist
|
||||
assert(def_1 && def_2 && "The constant ids must exist in the module.");
|
||||
if (!def_1 || !def_2) {
|
||||
// We don't use an assertion since otherwise the shrinker fails.
|
||||
return false;
|
||||
}
|
||||
|
||||
// The type ids must be the same
|
||||
// TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/3536): Somehow
|
||||
|
@ -41,6 +41,7 @@ class TransformationRecordSynonymousConstants : public Transformation {
|
||||
// - if both of them represent zero-like values of the same type
|
||||
// - if they are composite constants with the same type and their
|
||||
// components are pairwise equivalent.
|
||||
// - |constant1_id| and |constant2_id| may not be irrelevant.
|
||||
bool IsApplicable(
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context) const override;
|
||||
|
@ -39,7 +39,8 @@ TransformationVectorShuffle::TransformationVectorShuffle(
|
||||
}
|
||||
|
||||
bool TransformationVectorShuffle::IsApplicable(
|
||||
opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
|
||||
opt::IRContext* ir_context,
|
||||
const TransformationContext& transformation_context) const {
|
||||
// The fresh id must not already be in use.
|
||||
if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
|
||||
return false;
|
||||
@ -56,12 +57,26 @@ bool TransformationVectorShuffle::IsApplicable(
|
||||
if (!vector1_instruction || !vector1_instruction->type_id()) {
|
||||
return false;
|
||||
}
|
||||
// We should be able to create a synonym of |vector1| if it's not irrelevant.
|
||||
if (!transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
message_.vector1()) &&
|
||||
!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context,
|
||||
vector1_instruction)) {
|
||||
return false;
|
||||
}
|
||||
// The second vector must be an instruction with a type id
|
||||
auto vector2_instruction =
|
||||
ir_context->get_def_use_mgr()->GetDef(message_.vector2());
|
||||
if (!vector2_instruction || !vector2_instruction->type_id()) {
|
||||
return false;
|
||||
}
|
||||
// We should be able to create a synonym of |vector2| if it's not irrelevant.
|
||||
if (!transformation_context.GetFactManager()->IdIsIrrelevant(
|
||||
message_.vector2()) &&
|
||||
!fuzzerutil::CanMakeSynonymOf(ir_context, transformation_context,
|
||||
vector2_instruction)) {
|
||||
return false;
|
||||
}
|
||||
auto vector1_type =
|
||||
ir_context->get_type_mgr()->GetType(vector1_instruction->type_id());
|
||||
// The first vector instruction's type must actually be a vector type.
|
||||
@ -161,9 +176,21 @@ void TransformationVectorShuffle::Apply(
|
||||
// |component| refers.
|
||||
if (component <
|
||||
GetVectorType(ir_context, message_.vector1())->element_count()) {
|
||||
// Irrelevant id cannot participate in DataSynonym facts.
|
||||
if (transformation_context->GetFactManager()->IdIsIrrelevant(
|
||||
message_.vector1())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
descriptor_for_source_component =
|
||||
MakeDataDescriptor(message_.vector1(), {component});
|
||||
} else {
|
||||
// Irrelevant id cannot participate in DataSynonym facts.
|
||||
if (transformation_context->GetFactManager()->IdIsIrrelevant(
|
||||
message_.vector2())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto index_into_vector_2 =
|
||||
component -
|
||||
GetVectorType(ir_context, message_.vector1())->element_count();
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "source/fuzz/transformation.h"
|
||||
#include "source/fuzz/transformation_context.h"
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
#include "source/opt/types.h"
|
||||
|
||||
namespace spvtools {
|
||||
@ -59,7 +58,9 @@ class TransformationVectorShuffle : public Transformation {
|
||||
// from which it came (with undefined components being ignored). If the
|
||||
// result vector is a contiguous sub-range of one of the input vectors, a
|
||||
// fact is added to record that |message_.fresh_id| is synonymous with this
|
||||
// sub-range.
|
||||
// sub-range. DataSynonym facts are added only for non-irrelevant vectors
|
||||
// (e.g. if |vector1| is irrelevant but |vector2| is not, synonyms will be
|
||||
// created for |vector1| but not |vector2|).
|
||||
void Apply(opt::IRContext* ir_context,
|
||||
TransformationContext* transformation_context) const override;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user