mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-10-18 11:10:05 +00:00
spirv-fuzz: Refactor 'copy object' and 'construct composite' transformations (#2966)
Rework these transformations to identify instructions via (base, opcode, skip-count) triples, rather than (base, offset) pairs.
This commit is contained in:
parent
964dc52df5
commit
00170cc5e6
@ -14,6 +14,8 @@
|
||||
|
||||
#include "source/fuzz/fuzzer_pass.h"
|
||||
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
|
||||
@ -69,9 +71,10 @@ std::vector<opt::Instruction*> FuzzerPass::FindAvailableInstructions(
|
||||
}
|
||||
|
||||
void FuzzerPass::MaybeAddTransformationBeforeEachInstruction(
|
||||
std::function<uint32_t(
|
||||
const opt::Function& function, opt::BasicBlock* block,
|
||||
opt::BasicBlock::iterator inst_it, uint32_t base, uint32_t offset)>
|
||||
std::function<
|
||||
void(const opt::Function& function, opt::BasicBlock* block,
|
||||
opt::BasicBlock::iterator inst_it,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor)>
|
||||
maybe_apply_transformation) {
|
||||
// Consider every block in every function.
|
||||
for (auto& function : *GetIRContext()->module()) {
|
||||
@ -80,46 +83,45 @@ void FuzzerPass::MaybeAddTransformationBeforeEachInstruction(
|
||||
// whether to apply a transformation before it.
|
||||
|
||||
// In order for transformations to insert new instructions, they need to
|
||||
// be able to identify the instruction to insert before. We enable this
|
||||
// by tracking a base instruction, which must generate a result id, and
|
||||
// an offset (to allow us to identify instructions that do not generate
|
||||
// result ids).
|
||||
// be able to identify the instruction to insert before. We describe an
|
||||
// instruction via its opcode, 'opc', a base instruction 'base' that has a
|
||||
// result id, and the number of instructions with opcode 'opc' that we
|
||||
// should skip when searching from 'base' for the desired instruction.
|
||||
// (An instruction that has a result id is represented by its own opcode,
|
||||
// itself as 'base', and a skip-count of 0.)
|
||||
std::vector<std::tuple<uint32_t, SpvOp, uint32_t>>
|
||||
base_opcode_skip_triples;
|
||||
|
||||
// The initial base instruction is the block label.
|
||||
uint32_t base = block.id();
|
||||
uint32_t offset = 0;
|
||||
// Consider every instruction in the block.
|
||||
|
||||
// Counts the number of times we have seen each opcode since we reset the
|
||||
// base instruction.
|
||||
std::map<SpvOp, uint32_t> skip_count;
|
||||
|
||||
// Consider every instruction in the block. The label is excluded: it is
|
||||
// only necessary to consider it as a base in case the first instruction
|
||||
// in the block does not have a result id.
|
||||
for (auto inst_it = block.begin(); inst_it != block.end(); ++inst_it) {
|
||||
if (inst_it->HasResultId()) {
|
||||
// In the case that the instruction has a result id, we use the
|
||||
// instruction as its own base, with zero offset.
|
||||
// instruction as its own base, and clear the skip counts we have
|
||||
// collected.
|
||||
base = inst_it->result_id();
|
||||
offset = 0;
|
||||
} else {
|
||||
// The instruction does not have a result id, so we need to identify
|
||||
// it via the latest instruction that did have a result id (base), and
|
||||
// an incremented offset.
|
||||
offset++;
|
||||
skip_count.clear();
|
||||
}
|
||||
const SpvOp opcode = inst_it->opcode();
|
||||
|
||||
// Invoke the provided function, which might apply a transformation.
|
||||
// Its return value informs us of how many instructions it inserted.
|
||||
// (This will be 0 if no transformation was applied.)
|
||||
uint32_t num_instructions_inserted =
|
||||
maybe_apply_transformation(function, &block, inst_it, base, offset);
|
||||
maybe_apply_transformation(
|
||||
function, &block, inst_it,
|
||||
MakeInstructionDescriptor(
|
||||
base, opcode,
|
||||
skip_count.count(opcode) ? skip_count.at(opcode) : 0));
|
||||
|
||||
if (!inst_it->HasResultId()) {
|
||||
// We are tracking the current id-less instruction via an offset,
|
||||
// |offset|, from a previous instruction, |base|, that has an id. We
|
||||
// increment |offset| to reflect any newly-inserted instructions.
|
||||
//
|
||||
// An alternative would be to reset |base| to be an id generated by
|
||||
// a newly-inserted instruction, but that would be more complex, and
|
||||
// sticking to a |base| that already existed before this
|
||||
// transformation was applied makes the applicability of future
|
||||
// transformations less tightly coupled with the presence of the just-
|
||||
// applied transformation.
|
||||
offset += num_instructions_inserted;
|
||||
skip_count[opcode] =
|
||||
skip_count.count(opcode) ? skip_count.at(opcode) + 1 : 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,27 +67,26 @@ class FuzzerPass {
|
||||
instruction_is_relevant);
|
||||
|
||||
// A helper method that iterates through each instruction in each block, at
|
||||
// all times tracking a base instruction and offset that allows that latest
|
||||
// all times tracking an instruction descriptor that allows the latest
|
||||
// instruction to be located even if it has no result id.
|
||||
//
|
||||
// The code to manipulate the base and offset is a bit fiddly, and the point
|
||||
// of this method is to avoiding having to duplicate it in multiple
|
||||
// The code to manipulate the instruction descriptor is a bit fiddly, and the
|
||||
// point of this method is to avoiding having to duplicate it in multiple
|
||||
// transformation passes.
|
||||
//
|
||||
// The function |maybe_apply_transformation| is invoked for each instruction
|
||||
// |inst_it| in block |block| of function |function| that is encountered. The
|
||||
// |base| and |offset| parameters to the function object allow |inst_it| to be
|
||||
// identified.
|
||||
// |instruction_descriptor| parameter to the function object allows |inst_it|
|
||||
// to be identified.
|
||||
//
|
||||
// The job of |maybe_apply_transformation| is to randomly decide whether to
|
||||
// try to apply some transformation, and then - if selected - to attempt to
|
||||
// apply it. The function returns the number of instructions that were
|
||||
// inserted before |inst_it|, so that |offset| can be updated.
|
||||
//
|
||||
// apply it.
|
||||
void MaybeAddTransformationBeforeEachInstruction(
|
||||
std::function<uint32_t(
|
||||
const opt::Function& function, opt::BasicBlock* block,
|
||||
opt::BasicBlock::iterator inst_it, uint32_t base, uint32_t offset)>
|
||||
std::function<
|
||||
void(const opt::Function& function, opt::BasicBlock* block,
|
||||
opt::BasicBlock::iterator inst_it,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor)>
|
||||
maybe_apply_transformation);
|
||||
|
||||
private:
|
||||
|
@ -43,21 +43,22 @@ void FuzzerPassConstructComposites::Apply() {
|
||||
}
|
||||
|
||||
MaybeAddTransformationBeforeEachInstruction(
|
||||
[this, &composite_type_ids](const opt::Function& function,
|
||||
opt::BasicBlock* block,
|
||||
opt::BasicBlock::iterator inst_it,
|
||||
uint32_t base, uint32_t offset) -> uint32_t {
|
||||
[this, &composite_type_ids](
|
||||
const opt::Function& function, opt::BasicBlock* block,
|
||||
opt::BasicBlock::iterator inst_it,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor)
|
||||
-> void {
|
||||
// Check whether it is legitimate to insert a composite construction
|
||||
// before the instruction.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
|
||||
SpvOpCompositeConstruct, inst_it)) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Randomly decide whether to try inserting an object copy here.
|
||||
if (!GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfConstructingComposite())) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// For each instruction that is available at this program point (i.e. an
|
||||
@ -134,21 +135,20 @@ void FuzzerPassConstructComposites::Apply() {
|
||||
// We did not manage to make a composite; return 0 to indicate that no
|
||||
// instructions were added.
|
||||
assert(constructor_arguments == nullptr);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
assert(constructor_arguments != nullptr);
|
||||
|
||||
// Make and apply a transformation.
|
||||
TransformationConstructComposite transformation(
|
||||
chosen_composite_type, *constructor_arguments, base, offset,
|
||||
GetFuzzerContext()->GetFreshId());
|
||||
chosen_composite_type, *constructor_arguments,
|
||||
instruction_descriptor, GetFuzzerContext()->GetFreshId());
|
||||
assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) &&
|
||||
"This transformation should be applicable by construction.");
|
||||
transformation.Apply(GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation() =
|
||||
transformation.ToMessage();
|
||||
// Indicate that one instruction was added.
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -31,19 +31,25 @@ FuzzerPassCopyObjects::~FuzzerPassCopyObjects() = default;
|
||||
void FuzzerPassCopyObjects::Apply() {
|
||||
MaybeAddTransformationBeforeEachInstruction(
|
||||
[this](const opt::Function& function, opt::BasicBlock* block,
|
||||
opt::BasicBlock::iterator inst_it, uint32_t base,
|
||||
uint32_t offset) -> uint32_t {
|
||||
opt::BasicBlock::iterator inst_it,
|
||||
const protobufs::InstructionDescriptor& instruction_descriptor)
|
||||
-> void {
|
||||
assert(inst_it->opcode() ==
|
||||
instruction_descriptor.target_instruction_opcode() &&
|
||||
"The opcode of the instruction we might insert before must be "
|
||||
"the same as the opcode in the descriptor for the instruction");
|
||||
|
||||
// Check whether it is legitimate to insert a copy before this
|
||||
// instruction.
|
||||
if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyObject,
|
||||
inst_it)) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Randomly decide whether to try inserting an object copy here.
|
||||
if (!GetFuzzerContext()->ChoosePercentage(
|
||||
GetFuzzerContext()->GetChanceOfCopyingObject())) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<opt::Instruction*> relevant_instructions =
|
||||
@ -53,21 +59,20 @@ void FuzzerPassCopyObjects::Apply() {
|
||||
// At this point, |relevant_instructions| contains all the instructions
|
||||
// we might think of copying.
|
||||
if (relevant_instructions.empty()) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Choose a copyable instruction at random, and create and apply an
|
||||
// object copying transformation based on it.
|
||||
uint32_t index = GetFuzzerContext()->RandomIndex(relevant_instructions);
|
||||
TransformationCopyObject transformation(
|
||||
relevant_instructions[index]->result_id(), base, offset,
|
||||
relevant_instructions[index]->result_id(), instruction_descriptor,
|
||||
GetFuzzerContext()->GetFreshId());
|
||||
assert(transformation.IsApplicable(GetIRContext(), *GetFactManager()) &&
|
||||
"This transformation should be applicable by construction.");
|
||||
transformation.Apply(GetIRContext(), GetFactManager());
|
||||
*GetTransformations()->add_transformation() =
|
||||
transformation.ToMessage();
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -180,41 +180,6 @@ opt::BasicBlock::iterator GetIteratorForInstruction(
|
||||
return block->end();
|
||||
}
|
||||
|
||||
opt::BasicBlock::iterator GetIteratorForBaseInstructionAndOffset(
|
||||
opt::BasicBlock* block, const opt::Instruction* base_inst,
|
||||
uint32_t offset) {
|
||||
// The cases where |base_inst| is the block's label, vs. inside the block,
|
||||
// are dealt with separately.
|
||||
if (base_inst == block->GetLabelInst()) {
|
||||
// |base_inst| is the block's label.
|
||||
if (offset == 0) {
|
||||
// We cannot return an iterator to the block's label.
|
||||
return block->end();
|
||||
}
|
||||
// Conceptually, the first instruction in the block is [label + 1].
|
||||
// We thus start from 1 when applying the offset.
|
||||
auto inst_it = block->begin();
|
||||
for (uint32_t i = 1; i < offset && inst_it != block->end(); i++) {
|
||||
++inst_it;
|
||||
}
|
||||
// This is either the desired instruction, or the end of the block.
|
||||
return inst_it;
|
||||
}
|
||||
// |base_inst| is inside the block.
|
||||
for (auto inst_it = block->begin(); inst_it != block->end(); ++inst_it) {
|
||||
if (base_inst == &*inst_it) {
|
||||
// We have found the base instruction; we now apply the offset.
|
||||
for (uint32_t i = 0; i < offset && inst_it != block->end(); i++) {
|
||||
++inst_it;
|
||||
}
|
||||
// This is either the desired instruction, or the end of the block.
|
||||
return inst_it;
|
||||
}
|
||||
}
|
||||
assert(false && "The base instruction was not found.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool NewEdgeRespectsUseDefDominance(opt::IRContext* context,
|
||||
opt::BasicBlock* bb_from,
|
||||
opt::BasicBlock* bb_to) {
|
||||
|
@ -69,16 +69,6 @@ bool BlockIsInLoopContinueConstruct(opt::IRContext* context, uint32_t block_id,
|
||||
opt::BasicBlock::iterator GetIteratorForInstruction(
|
||||
opt::BasicBlock* block, const opt::Instruction* inst);
|
||||
|
||||
// Requires that |base_inst| is either the label instruction of |block| or an
|
||||
// instruction inside |block|.
|
||||
//
|
||||
// If the block contains a (non-label, non-terminator) instruction |offset|
|
||||
// instructions after |base_inst|, an iterator to this instruction is returned.
|
||||
//
|
||||
// Otherwise |block|->end() is returned.
|
||||
opt::BasicBlock::iterator GetIteratorForBaseInstructionAndOffset(
|
||||
opt::BasicBlock* block, const opt::Instruction* base_inst, uint32_t offset);
|
||||
|
||||
// The function determines whether adding an edge from |bb_from| to |bb_to| -
|
||||
// is legitimate with respect to the SPIR-V rule that a definition must
|
||||
// dominate all of its uses. This is because adding such an edge can change
|
||||
|
@ -331,15 +331,12 @@ message TransformationCopyObject {
|
||||
// Id of the object to be copied
|
||||
uint32 object = 1;
|
||||
|
||||
// The id of an instruction in a block
|
||||
uint32 base_instruction_id = 2;
|
||||
|
||||
// An offset, such that OpCopyObject instruction should be inserted right
|
||||
// before the instruction |offset| instructions after |base_instruction_id|
|
||||
uint32 offset = 3;
|
||||
// A descriptor for an instruction in a block before which the new
|
||||
// OpCopyObject instruction should be inserted
|
||||
InstructionDescriptor instruction_to_insert_before = 2;
|
||||
|
||||
// A fresh id for the copied object
|
||||
uint32 fresh_id = 4;
|
||||
uint32 fresh_id = 3;
|
||||
|
||||
}
|
||||
|
||||
@ -354,16 +351,12 @@ message TransformationConstructComposite {
|
||||
// Ids of the objects that will form the components of the composite
|
||||
repeated uint32 component = 2;
|
||||
|
||||
// The id of an instruction in a block
|
||||
uint32 base_instruction_id = 3;
|
||||
|
||||
// An offset, such that OpCompositeConstruct instruction should be inserted
|
||||
// right before the instruction |offset| instructions after
|
||||
// |base_instruction_id|
|
||||
uint32 offset = 4;
|
||||
// A descriptor for an instruction in a block before which the new
|
||||
// OpCompositeConstruct instruction should be inserted
|
||||
InstructionDescriptor instruction_to_insert_before = 3;
|
||||
|
||||
// A fresh id for the composite object
|
||||
uint32 fresh_id = 5;
|
||||
uint32 fresh_id = 4;
|
||||
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "source/fuzz/transformation_construct_composite.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "source/opt/instruction.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace fuzz {
|
||||
@ -25,13 +27,14 @@ TransformationConstructComposite::TransformationConstructComposite(
|
||||
|
||||
TransformationConstructComposite::TransformationConstructComposite(
|
||||
uint32_t composite_type_id, std::vector<uint32_t> component,
|
||||
uint32_t base_instruction_id, uint32_t offset, uint32_t fresh_id) {
|
||||
const protobufs::InstructionDescriptor& instruction_to_insert_before,
|
||||
uint32_t fresh_id) {
|
||||
message_.set_composite_type_id(composite_type_id);
|
||||
for (auto a_component : component) {
|
||||
message_.add_component(a_component);
|
||||
}
|
||||
message_.set_base_instruction_id(base_instruction_id);
|
||||
message_.set_offset(offset);
|
||||
*message_.mutable_instruction_to_insert_before() =
|
||||
instruction_to_insert_before;
|
||||
message_.set_fresh_id(fresh_id);
|
||||
}
|
||||
|
||||
@ -42,24 +45,11 @@ bool TransformationConstructComposite::IsApplicable(
|
||||
return false;
|
||||
}
|
||||
|
||||
auto base_instruction =
|
||||
context->get_def_use_mgr()->GetDef(message_.base_instruction_id());
|
||||
if (!base_instruction) {
|
||||
// The given id to insert after is not defined.
|
||||
return false;
|
||||
}
|
||||
|
||||
auto destination_block = context->get_instr_block(base_instruction);
|
||||
if (!destination_block) {
|
||||
// The given id to insert after is not in a block.
|
||||
return false;
|
||||
}
|
||||
|
||||
auto insert_before = fuzzerutil::GetIteratorForBaseInstructionAndOffset(
|
||||
destination_block, base_instruction, message_.offset());
|
||||
|
||||
if (insert_before == destination_block->end()) {
|
||||
// The offset was inappropriate.
|
||||
auto insert_before =
|
||||
FindInstruction(message_.instruction_to_insert_before(), context);
|
||||
if (!insert_before) {
|
||||
// The instruction before which the composite should be inserted was not
|
||||
// found.
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -125,11 +115,11 @@ void TransformationConstructComposite::Apply(opt::IRContext* context,
|
||||
FactManager* fact_manager) const {
|
||||
// Use the base and offset information from the transformation to determine
|
||||
// where in the module a new instruction should be inserted.
|
||||
auto base_instruction =
|
||||
context->get_def_use_mgr()->GetDef(message_.base_instruction_id());
|
||||
auto destination_block = context->get_instr_block(base_instruction);
|
||||
auto insert_before = fuzzerutil::GetIteratorForBaseInstructionAndOffset(
|
||||
destination_block, base_instruction, message_.offset());
|
||||
auto insert_before_inst =
|
||||
FindInstruction(message_.instruction_to_insert_before(), context);
|
||||
auto destination_block = context->get_instr_block(insert_before_inst);
|
||||
auto insert_before = fuzzerutil::GetIteratorForInstruction(
|
||||
destination_block, insert_before_inst);
|
||||
|
||||
// Prepare the input operands for an OpCompositeConstruct instruction.
|
||||
opt::Instruction::OperandList in_operands;
|
||||
|
@ -28,10 +28,10 @@ class TransformationConstructComposite : public Transformation {
|
||||
explicit TransformationConstructComposite(
|
||||
const protobufs::TransformationConstructComposite& message);
|
||||
|
||||
TransformationConstructComposite(uint32_t composite_type_id,
|
||||
std::vector<uint32_t> component,
|
||||
uint32_t base_instruction_id,
|
||||
uint32_t offset, uint32_t fresh_id);
|
||||
TransformationConstructComposite(
|
||||
uint32_t composite_type_id, std::vector<uint32_t> component,
|
||||
const protobufs::InstructionDescriptor& instruction_to_insert_before,
|
||||
uint32_t fresh_id);
|
||||
|
||||
// - |message_.fresh_id| must not be used by the module.
|
||||
// - |message_.composite_type_id| must be the id of a composite type
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "source/fuzz/transformation_copy_object.h"
|
||||
|
||||
#include "source/fuzz/fuzzer_util.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "source/opt/instruction.h"
|
||||
#include "source/util/make_unique.h"
|
||||
|
||||
@ -25,13 +26,13 @@ TransformationCopyObject::TransformationCopyObject(
|
||||
const protobufs::TransformationCopyObject& message)
|
||||
: message_(message) {}
|
||||
|
||||
TransformationCopyObject::TransformationCopyObject(uint32_t object,
|
||||
uint32_t base_instruction_id,
|
||||
uint32_t offset,
|
||||
uint32_t fresh_id) {
|
||||
TransformationCopyObject::TransformationCopyObject(
|
||||
uint32_t object,
|
||||
const protobufs::InstructionDescriptor& instruction_to_insert_before,
|
||||
uint32_t fresh_id) {
|
||||
message_.set_object(object);
|
||||
message_.set_base_instruction_id(base_instruction_id);
|
||||
message_.set_offset(offset);
|
||||
*message_.mutable_instruction_to_insert_before() =
|
||||
instruction_to_insert_before;
|
||||
message_.set_fresh_id(fresh_id);
|
||||
}
|
||||
|
||||
@ -50,24 +51,10 @@ bool TransformationCopyObject::IsApplicable(
|
||||
return false;
|
||||
}
|
||||
|
||||
auto base_instruction =
|
||||
context->get_def_use_mgr()->GetDef(message_.base_instruction_id());
|
||||
if (!base_instruction) {
|
||||
// The given id to insert after is not defined.
|
||||
return false;
|
||||
}
|
||||
|
||||
auto destination_block = context->get_instr_block(base_instruction);
|
||||
if (!destination_block) {
|
||||
// The given id to insert after is not in a block.
|
||||
return false;
|
||||
}
|
||||
|
||||
auto insert_before = fuzzerutil::GetIteratorForBaseInstructionAndOffset(
|
||||
destination_block, base_instruction, message_.offset());
|
||||
|
||||
if (insert_before == destination_block->end()) {
|
||||
// The offset was inappropriate.
|
||||
auto insert_before =
|
||||
FindInstruction(message_.instruction_to_insert_before(), context);
|
||||
if (!insert_before) {
|
||||
// The instruction before which the copy should be inserted was not found.
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -86,7 +73,9 @@ bool TransformationCopyObject::IsApplicable(
|
||||
// insert it before the object's defining instruction.
|
||||
return !context->get_instr_block(object_inst) ||
|
||||
(object_inst != &*insert_before &&
|
||||
context->GetDominatorAnalysis(destination_block->GetParent())
|
||||
context
|
||||
->GetDominatorAnalysis(
|
||||
context->get_instr_block(insert_before)->GetParent())
|
||||
->Dominates(object_inst, &*insert_before));
|
||||
}
|
||||
|
||||
@ -94,13 +83,12 @@ void TransformationCopyObject::Apply(opt::IRContext* context,
|
||||
FactManager* fact_manager) const {
|
||||
auto object_inst = context->get_def_use_mgr()->GetDef(message_.object());
|
||||
assert(object_inst && "The object to be copied must exist.");
|
||||
auto base_instruction =
|
||||
context->get_def_use_mgr()->GetDef(message_.base_instruction_id());
|
||||
assert(base_instruction && "The base instruction must exist.");
|
||||
auto destination_block = context->get_instr_block(base_instruction);
|
||||
auto insert_before_inst =
|
||||
FindInstruction(message_.instruction_to_insert_before(), context);
|
||||
auto destination_block = context->get_instr_block(insert_before_inst);
|
||||
assert(destination_block && "The base instruction must be in a block.");
|
||||
auto insert_before = fuzzerutil::GetIteratorForBaseInstructionAndOffset(
|
||||
destination_block, base_instruction, message_.offset());
|
||||
auto insert_before = fuzzerutil::GetIteratorForInstruction(
|
||||
destination_block, insert_before_inst);
|
||||
assert(insert_before != destination_block->end() &&
|
||||
"There must be an instruction before which the copy can be inserted.");
|
||||
|
||||
|
@ -28,8 +28,10 @@ class TransformationCopyObject : public Transformation {
|
||||
explicit TransformationCopyObject(
|
||||
const protobufs::TransformationCopyObject& message);
|
||||
|
||||
TransformationCopyObject(uint32_t object, uint32_t base_instruction_id,
|
||||
uint32_t offset, uint32_t fresh_id);
|
||||
TransformationCopyObject(
|
||||
uint32_t object,
|
||||
const protobufs::InstructionDescriptor& instruction_to_insert_before,
|
||||
uint32_t fresh_id);
|
||||
|
||||
// - |message_.fresh_id| must not be used by the module.
|
||||
// - |message_.object| must be a result id that is a legitimate operand for
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "source/fuzz/transformation_construct_composite.h"
|
||||
#include "source/fuzz/data_descriptor.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
@ -144,11 +145,13 @@ TEST(TransformationConstructCompositeTest, ConstructArrays) {
|
||||
FactManager fact_manager;
|
||||
|
||||
// Make a vec2[3]
|
||||
TransformationConstructComposite make_vec2_array_length_3(37, {41, 45, 27},
|
||||
46, 0, 200);
|
||||
TransformationConstructComposite make_vec2_array_length_3(
|
||||
37, {41, 45, 27}, MakeInstructionDescriptor(46, SpvOpAccessChain, 0),
|
||||
200);
|
||||
// Bad: there are too many components
|
||||
TransformationConstructComposite make_vec2_array_length_3_bad(
|
||||
37, {41, 45, 27, 27}, 46, 0, 200);
|
||||
37, {41, 45, 27, 27}, MakeInstructionDescriptor(46, SpvOpAccessChain, 0),
|
||||
200);
|
||||
ASSERT_TRUE(
|
||||
make_vec2_array_length_3.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
@ -160,11 +163,11 @@ TEST(TransformationConstructCompositeTest, ConstructArrays) {
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 27, 200, {2}));
|
||||
|
||||
// Make a float[2]
|
||||
TransformationConstructComposite make_float_array_length_2(9, {24, 40}, 71, 1,
|
||||
201);
|
||||
TransformationConstructComposite make_float_array_length_2(
|
||||
9, {24, 40}, MakeInstructionDescriptor(71, SpvOpStore, 0), 201);
|
||||
// Bad: %41 does not have type float
|
||||
TransformationConstructComposite make_float_array_length_2_bad(9, {41, 40},
|
||||
71, 1, 201);
|
||||
TransformationConstructComposite make_float_array_length_2_bad(
|
||||
9, {41, 40}, MakeInstructionDescriptor(71, SpvOpStore, 0), 201);
|
||||
ASSERT_TRUE(
|
||||
make_float_array_length_2.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
@ -175,11 +178,13 @@ TEST(TransformationConstructCompositeTest, ConstructArrays) {
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 40, 201, {1}));
|
||||
|
||||
// Make a bool[3]
|
||||
TransformationConstructComposite make_bool_array_length_3(47, {33, 50, 50},
|
||||
33, 1, 202);
|
||||
TransformationConstructComposite make_bool_array_length_3(
|
||||
47, {33, 50, 50}, MakeInstructionDescriptor(33, SpvOpSelectionMerge, 0),
|
||||
202);
|
||||
// Bad: %54 is not available at the desired program point.
|
||||
TransformationConstructComposite make_bool_array_length_3_bad(
|
||||
47, {33, 54, 50}, 33, 1, 202);
|
||||
47, {33, 54, 50}, MakeInstructionDescriptor(33, SpvOpSelectionMerge, 0),
|
||||
202);
|
||||
ASSERT_TRUE(
|
||||
make_bool_array_length_3.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
@ -191,11 +196,11 @@ TEST(TransformationConstructCompositeTest, ConstructArrays) {
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 50, 202, {2}));
|
||||
|
||||
// make a uvec3[2][2]
|
||||
TransformationConstructComposite make_uvec3_array_length_2_2(58, {69, 100},
|
||||
64, 1, 203);
|
||||
// Bad: Offset 100 is too large.
|
||||
TransformationConstructComposite make_uvec3_array_length_2_2(
|
||||
58, {69, 100}, MakeInstructionDescriptor(64, SpvOpStore, 0), 203);
|
||||
// Bad: Skip count 100 is too large.
|
||||
TransformationConstructComposite make_uvec3_array_length_2_2_bad(
|
||||
58, {33, 54}, 64, 100, 203);
|
||||
58, {33, 54}, MakeInstructionDescriptor(64, SpvOpStore, 100), 203);
|
||||
ASSERT_TRUE(
|
||||
make_uvec3_array_length_2_2.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_uvec3_array_length_2_2_bad.IsApplicable(context.get(),
|
||||
@ -393,9 +398,11 @@ TEST(TransformationConstructCompositeTest, ConstructMatrices) {
|
||||
FactManager fact_manager;
|
||||
|
||||
// make a mat3x4
|
||||
TransformationConstructComposite make_mat34(32, {25, 28, 31}, 31, 2, 200);
|
||||
TransformationConstructComposite make_mat34(
|
||||
32, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200);
|
||||
// Bad: %35 is mat4x3, not mat3x4.
|
||||
TransformationConstructComposite make_mat34_bad(35, {25, 28, 31}, 31, 2, 200);
|
||||
TransformationConstructComposite make_mat34_bad(
|
||||
35, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200);
|
||||
ASSERT_TRUE(make_mat34.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_mat34_bad.IsApplicable(context.get(), fact_manager));
|
||||
make_mat34.Apply(context.get(), &fact_manager);
|
||||
@ -405,11 +412,11 @@ TEST(TransformationConstructCompositeTest, ConstructMatrices) {
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 31, 200, {2}));
|
||||
|
||||
// make a mat4x3
|
||||
TransformationConstructComposite make_mat43(35, {11, 13, 16, 100}, 31, 1,
|
||||
201);
|
||||
TransformationConstructComposite make_mat43(
|
||||
35, {11, 13, 16, 100}, MakeInstructionDescriptor(31, SpvOpStore, 0), 201);
|
||||
// Bad: %25 does not match the matrix's column type.
|
||||
TransformationConstructComposite make_mat43_bad(35, {25, 13, 16, 100}, 31, 1,
|
||||
201);
|
||||
TransformationConstructComposite make_mat43_bad(
|
||||
35, {25, 13, 16, 100}, MakeInstructionDescriptor(31, SpvOpStore, 0), 201);
|
||||
ASSERT_TRUE(make_mat43.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_mat43_bad.IsApplicable(context.get(), fact_manager));
|
||||
make_mat43.Apply(context.get(), &fact_manager);
|
||||
@ -592,9 +599,11 @@ TEST(TransformationConstructCompositeTest, ConstructStructs) {
|
||||
FactManager fact_manager;
|
||||
|
||||
// make an Inner
|
||||
TransformationConstructComposite make_inner(9, {25, 19}, 57, 0, 200);
|
||||
TransformationConstructComposite make_inner(
|
||||
9, {25, 19}, MakeInstructionDescriptor(57, SpvOpAccessChain, 0), 200);
|
||||
// Bad: Too few fields to make the struct.
|
||||
TransformationConstructComposite make_inner_bad(9, {25}, 57, 0, 200);
|
||||
TransformationConstructComposite make_inner_bad(
|
||||
9, {25}, MakeInstructionDescriptor(57, SpvOpAccessChain, 0), 200);
|
||||
ASSERT_TRUE(make_inner.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_inner_bad.IsApplicable(context.get(), fact_manager));
|
||||
make_inner.Apply(context.get(), &fact_manager);
|
||||
@ -603,10 +612,13 @@ TEST(TransformationConstructCompositeTest, ConstructStructs) {
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 19, 200, {1}));
|
||||
|
||||
// make an Outer
|
||||
TransformationConstructComposite make_outer(33, {46, 200, 56}, 200, 1, 201);
|
||||
TransformationConstructComposite make_outer(
|
||||
33, {46, 200, 56}, MakeInstructionDescriptor(200, SpvOpAccessChain, 0),
|
||||
201);
|
||||
// Bad: %200 is not available at the desired program point.
|
||||
TransformationConstructComposite make_outer_bad(33, {46, 200, 56}, 200, 0,
|
||||
201);
|
||||
TransformationConstructComposite make_outer_bad(
|
||||
33, {46, 200, 56},
|
||||
MakeInstructionDescriptor(200, SpvOpCompositeConstruct, 0), 201);
|
||||
ASSERT_TRUE(make_outer.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_outer_bad.IsApplicable(context.get(), fact_manager));
|
||||
make_outer.Apply(context.get(), &fact_manager);
|
||||
@ -900,9 +912,11 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) {
|
||||
|
||||
FactManager fact_manager;
|
||||
|
||||
TransformationConstructComposite make_vec2(7, {17, 11}, 100, 1, 200);
|
||||
TransformationConstructComposite make_vec2(
|
||||
7, {17, 11}, MakeInstructionDescriptor(100, SpvOpStore, 0), 200);
|
||||
// Bad: not enough data for a vec2
|
||||
TransformationConstructComposite make_vec2_bad(7, {11}, 100, 1, 200);
|
||||
TransformationConstructComposite make_vec2_bad(
|
||||
7, {11}, MakeInstructionDescriptor(100, SpvOpStore, 0), 200);
|
||||
ASSERT_TRUE(make_vec2.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_vec2_bad.IsApplicable(context.get(), fact_manager));
|
||||
make_vec2.Apply(context.get(), &fact_manager);
|
||||
@ -910,9 +924,13 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) {
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 17, 200, {0}));
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 11, 200, {1}));
|
||||
|
||||
TransformationConstructComposite make_vec3(25, {12, 32}, 35, 0, 201);
|
||||
TransformationConstructComposite make_vec3(
|
||||
25, {12, 32}, MakeInstructionDescriptor(35, SpvOpCompositeConstruct, 0),
|
||||
201);
|
||||
// Bad: too much data for a vec3
|
||||
TransformationConstructComposite make_vec3_bad(25, {12, 32, 32}, 35, 0, 201);
|
||||
TransformationConstructComposite make_vec3_bad(
|
||||
25, {12, 32, 32},
|
||||
MakeInstructionDescriptor(35, SpvOpCompositeConstruct, 0), 201);
|
||||
ASSERT_TRUE(make_vec3.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_vec3_bad.IsApplicable(context.get(), fact_manager));
|
||||
make_vec3.Apply(context.get(), &fact_manager);
|
||||
@ -920,10 +938,13 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) {
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 12, 201, {0}));
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 32, 201, {2}));
|
||||
|
||||
TransformationConstructComposite make_vec4(44, {32, 32, 10, 11}, 75, 0, 202);
|
||||
TransformationConstructComposite make_vec4(
|
||||
44, {32, 32, 10, 11}, MakeInstructionDescriptor(75, SpvOpAccessChain, 0),
|
||||
202);
|
||||
// Bad: id 48 is not available at the insertion points
|
||||
TransformationConstructComposite make_vec4_bad(44, {48, 32, 10, 11}, 75, 0,
|
||||
202);
|
||||
TransformationConstructComposite make_vec4_bad(
|
||||
44, {48, 32, 10, 11}, MakeInstructionDescriptor(75, SpvOpAccessChain, 0),
|
||||
202);
|
||||
ASSERT_TRUE(make_vec4.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_vec4_bad.IsApplicable(context.get(), fact_manager));
|
||||
make_vec4.Apply(context.get(), &fact_manager);
|
||||
@ -933,9 +954,11 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) {
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 10, 202, {2}));
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 11, 202, {3}));
|
||||
|
||||
TransformationConstructComposite make_ivec2(51, {126, 120}, 128, 0, 203);
|
||||
TransformationConstructComposite make_ivec2(
|
||||
51, {126, 120}, MakeInstructionDescriptor(128, SpvOpLoad, 0), 203);
|
||||
// Bad: if 128 is not available at the instruction that defines 128
|
||||
TransformationConstructComposite make_ivec2_bad(51, {128, 120}, 128, 0, 203);
|
||||
TransformationConstructComposite make_ivec2_bad(
|
||||
51, {128, 120}, MakeInstructionDescriptor(128, SpvOpLoad, 0), 203);
|
||||
ASSERT_TRUE(make_ivec2.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_ivec2_bad.IsApplicable(context.get(), fact_manager));
|
||||
make_ivec2.Apply(context.get(), &fact_manager);
|
||||
@ -943,10 +966,13 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) {
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 126, 203, {0}));
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 120, 203, {1}));
|
||||
|
||||
TransformationConstructComposite make_ivec3(114, {56, 117, 56}, 66, 1, 204);
|
||||
TransformationConstructComposite make_ivec3(
|
||||
114, {56, 117, 56}, MakeInstructionDescriptor(66, SpvOpAccessChain, 0),
|
||||
204);
|
||||
// Bad because 1300 is not an id
|
||||
TransformationConstructComposite make_ivec3_bad(114, {56, 117, 1300}, 66, 1,
|
||||
204);
|
||||
TransformationConstructComposite make_ivec3_bad(
|
||||
114, {56, 117, 1300}, MakeInstructionDescriptor(66, SpvOpAccessChain, 0),
|
||||
204);
|
||||
ASSERT_TRUE(make_ivec3.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_ivec3_bad.IsApplicable(context.get(), fact_manager));
|
||||
make_ivec3.Apply(context.get(), &fact_manager);
|
||||
@ -955,11 +981,13 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) {
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 117, 204, {1}));
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 56, 204, {2}));
|
||||
|
||||
TransformationConstructComposite make_ivec4(122, {56, 117, 117, 117}, 66, 0,
|
||||
205);
|
||||
TransformationConstructComposite make_ivec4(
|
||||
122, {56, 117, 117, 117}, MakeInstructionDescriptor(66, SpvOpIAdd, 0),
|
||||
205);
|
||||
// Bad because 86 is the wrong type.
|
||||
TransformationConstructComposite make_ivec4_bad(86, {56, 117, 117, 117}, 66,
|
||||
0, 205);
|
||||
TransformationConstructComposite make_ivec4_bad(
|
||||
86, {56, 117, 117, 117}, MakeInstructionDescriptor(66, SpvOpIAdd, 0),
|
||||
205);
|
||||
ASSERT_TRUE(make_ivec4.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_ivec4_bad.IsApplicable(context.get(), fact_manager));
|
||||
make_ivec4.Apply(context.get(), &fact_manager);
|
||||
@ -969,8 +997,10 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) {
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 117, 205, {2}));
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 117, 205, {3}));
|
||||
|
||||
TransformationConstructComposite make_uvec2(86, {18, 38}, 133, 2, 206);
|
||||
TransformationConstructComposite make_uvec2_bad(86, {18, 38}, 133, 200, 206);
|
||||
TransformationConstructComposite make_uvec2(
|
||||
86, {18, 38}, MakeInstructionDescriptor(133, SpvOpAccessChain, 0), 206);
|
||||
TransformationConstructComposite make_uvec2_bad(
|
||||
86, {18, 38}, MakeInstructionDescriptor(133, SpvOpAccessChain, 200), 206);
|
||||
ASSERT_TRUE(make_uvec2.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_uvec2_bad.IsApplicable(context.get(), fact_manager));
|
||||
make_uvec2.Apply(context.get(), &fact_manager);
|
||||
@ -978,10 +1008,11 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) {
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 18, 206, {0}));
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 38, 206, {1}));
|
||||
|
||||
TransformationConstructComposite make_uvec3(59, {14, 18, 136}, 137, 2, 207);
|
||||
TransformationConstructComposite make_uvec3(
|
||||
59, {14, 18, 136}, MakeInstructionDescriptor(137, SpvOpReturn, 0), 207);
|
||||
// Bad because 1300 is not an id
|
||||
TransformationConstructComposite make_uvec3_bad(59, {14, 18, 1300}, 137, 2,
|
||||
207);
|
||||
TransformationConstructComposite make_uvec3_bad(
|
||||
59, {14, 18, 1300}, MakeInstructionDescriptor(137, SpvOpReturn, 0), 207);
|
||||
ASSERT_TRUE(make_uvec3.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_uvec3_bad.IsApplicable(context.get(), fact_manager));
|
||||
make_uvec3.Apply(context.get(), &fact_manager);
|
||||
@ -990,11 +1021,13 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) {
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 18, 207, {1}));
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 136, 207, {2}));
|
||||
|
||||
TransformationConstructComposite make_uvec4(131, {14, 18, 136, 136}, 137, 0,
|
||||
208);
|
||||
TransformationConstructComposite make_uvec4(
|
||||
131, {14, 18, 136, 136},
|
||||
MakeInstructionDescriptor(137, SpvOpAccessChain, 0), 208);
|
||||
// Bad because 86 is the wrong type.
|
||||
TransformationConstructComposite make_uvec4_bad(86, {14, 18, 136, 136}, 137,
|
||||
0, 208);
|
||||
TransformationConstructComposite make_uvec4_bad(
|
||||
86, {14, 18, 136, 136},
|
||||
MakeInstructionDescriptor(137, SpvOpAccessChain, 0), 208);
|
||||
ASSERT_TRUE(make_uvec4.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_uvec4_bad.IsApplicable(context.get(), fact_manager));
|
||||
make_uvec4.Apply(context.get(), &fact_manager);
|
||||
@ -1004,19 +1037,21 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) {
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 136, 208, {2}));
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 136, 208, {3}));
|
||||
|
||||
TransformationConstructComposite make_bvec2(102,
|
||||
{
|
||||
111,
|
||||
41,
|
||||
},
|
||||
75, 0, 209);
|
||||
TransformationConstructComposite make_bvec2(
|
||||
102,
|
||||
{
|
||||
111,
|
||||
41,
|
||||
},
|
||||
MakeInstructionDescriptor(75, SpvOpAccessChain, 0), 209);
|
||||
// Bad because 0 is not a valid base instruction id
|
||||
TransformationConstructComposite make_bvec2_bad(102,
|
||||
{
|
||||
111,
|
||||
41,
|
||||
},
|
||||
0, 0, 209);
|
||||
TransformationConstructComposite make_bvec2_bad(
|
||||
102,
|
||||
{
|
||||
111,
|
||||
41,
|
||||
},
|
||||
MakeInstructionDescriptor(0, SpvOpExtInstImport, 0), 209);
|
||||
ASSERT_TRUE(make_bvec2.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_bvec2_bad.IsApplicable(context.get(), fact_manager));
|
||||
make_bvec2.Apply(context.get(), &fact_manager);
|
||||
@ -1024,9 +1059,11 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) {
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 111, 209, {0}));
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 41, 209, {1}));
|
||||
|
||||
TransformationConstructComposite make_bvec3(93, {108, 73}, 108, 1, 210);
|
||||
TransformationConstructComposite make_bvec3(
|
||||
93, {108, 73}, MakeInstructionDescriptor(108, SpvOpStore, 0), 210);
|
||||
// Bad because there are too many components for a bvec3
|
||||
TransformationConstructComposite make_bvec3_bad(93, {108, 108}, 108, 1, 210);
|
||||
TransformationConstructComposite make_bvec3_bad(
|
||||
93, {108, 108}, MakeInstructionDescriptor(108, SpvOpStore, 0), 210);
|
||||
ASSERT_TRUE(make_bvec3.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_bvec3_bad.IsApplicable(context.get(), fact_manager));
|
||||
make_bvec3.Apply(context.get(), &fact_manager);
|
||||
@ -1034,9 +1071,11 @@ TEST(TransformationConstructCompositeTest, ConstructVectors) {
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 108, 210, {0}));
|
||||
ASSERT_TRUE(SynonymFactHolds(fact_manager, 73, 210, {2}));
|
||||
|
||||
TransformationConstructComposite make_bvec4(70, {108, 108}, 108, 3, 211);
|
||||
TransformationConstructComposite make_bvec4(
|
||||
70, {108, 108}, MakeInstructionDescriptor(108, SpvOpBranch, 0), 211);
|
||||
// Bad because 21 is a type, not a result id
|
||||
TransformationConstructComposite make_bvec4_bad(70, {21, 108}, 108, 3, 211);
|
||||
TransformationConstructComposite make_bvec4_bad(
|
||||
70, {21, 108}, MakeInstructionDescriptor(108, SpvOpBranch, 0), 211);
|
||||
ASSERT_TRUE(make_bvec4.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(make_bvec4_bad.IsApplicable(context.get(), fact_manager));
|
||||
make_bvec4.Apply(context.get(), &fact_manager);
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "source/fuzz/transformation_copy_object.h"
|
||||
#include "source/fuzz/data_descriptor.h"
|
||||
#include "source/fuzz/instruction_descriptor.h"
|
||||
#include "test/fuzz/fuzz_test_util.h"
|
||||
|
||||
namespace spvtools {
|
||||
@ -49,7 +50,8 @@ TEST(TransformationCopyObjectTest, CopyBooleanConstants) {
|
||||
|
||||
ASSERT_EQ(0, fact_manager.GetIdsForWhichSynonymsAreKnown().size());
|
||||
|
||||
TransformationCopyObject copy_true(7, 5, 1, 100);
|
||||
TransformationCopyObject copy_true(
|
||||
7, MakeInstructionDescriptor(5, SpvOpReturn, 0), 100);
|
||||
ASSERT_TRUE(copy_true.IsApplicable(context.get(), fact_manager));
|
||||
copy_true.Apply(context.get(), &fact_manager);
|
||||
|
||||
@ -63,7 +65,8 @@ TEST(TransformationCopyObjectTest, CopyBooleanConstants) {
|
||||
ASSERT_TRUE(DataDescriptorEquals()(&descriptor_100,
|
||||
&fact_manager.GetSynonymsForId(7)[0]));
|
||||
|
||||
TransformationCopyObject copy_false(8, 100, 1, 101);
|
||||
TransformationCopyObject copy_false(
|
||||
8, MakeInstructionDescriptor(100, SpvOpReturn, 0), 101);
|
||||
ASSERT_TRUE(copy_false.IsApplicable(context.get(), fact_manager));
|
||||
copy_false.Apply(context.get(), &fact_manager);
|
||||
ASSERT_EQ(2, ids_for_which_synonyms_are_known.size());
|
||||
@ -74,7 +77,8 @@ TEST(TransformationCopyObjectTest, CopyBooleanConstants) {
|
||||
ASSERT_TRUE(DataDescriptorEquals()(&descriptor_101,
|
||||
&fact_manager.GetSynonymsForId(8)[0]));
|
||||
|
||||
TransformationCopyObject copy_false_again(101, 5, 3, 102);
|
||||
TransformationCopyObject copy_false_again(
|
||||
101, MakeInstructionDescriptor(5, SpvOpReturn, 0), 102);
|
||||
ASSERT_TRUE(copy_false_again.IsApplicable(context.get(), fact_manager));
|
||||
copy_false_again.Apply(context.get(), &fact_manager);
|
||||
ASSERT_EQ(3, ids_for_which_synonyms_are_known.size());
|
||||
@ -85,7 +89,8 @@ TEST(TransformationCopyObjectTest, CopyBooleanConstants) {
|
||||
ASSERT_TRUE(DataDescriptorEquals()(&descriptor_102,
|
||||
&fact_manager.GetSynonymsForId(101)[0]));
|
||||
|
||||
TransformationCopyObject copy_true_again(7, 102, 1, 103);
|
||||
TransformationCopyObject copy_true_again(
|
||||
7, MakeInstructionDescriptor(102, SpvOpReturn, 0), 103);
|
||||
ASSERT_TRUE(copy_true_again.IsApplicable(context.get(), fact_manager));
|
||||
copy_true_again.Apply(context.get(), &fact_manager);
|
||||
// This does re-uses an id for which synonyms are already known, so the count
|
||||
@ -318,90 +323,113 @@ TEST(TransformationCopyObjectTest, CheckIllegalCases) {
|
||||
FactManager fact_manager;
|
||||
|
||||
// Inapplicable because %18 is decorated.
|
||||
ASSERT_FALSE(TransformationCopyObject(18, 21, 0, 200)
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
18, MakeInstructionDescriptor(21, SpvOpAccessChain, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because %77 is decorated.
|
||||
ASSERT_FALSE(TransformationCopyObject(17, 17, 1, 200)
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
77, MakeInstructionDescriptor(77, SpvOpBranch, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because %80 is decorated.
|
||||
ASSERT_FALSE(TransformationCopyObject(80, 77, 0, 200)
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
80, MakeInstructionDescriptor(77, SpvOpIAdd, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because %84 is not available at the requested point
|
||||
ASSERT_FALSE(TransformationCopyObject(84, 32, 1, 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationCopyObject(
|
||||
84, MakeInstructionDescriptor(32, SpvOpCompositeExtract, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Fine because %84 is available at the requested point
|
||||
ASSERT_TRUE(TransformationCopyObject(84, 32, 2, 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_TRUE(
|
||||
TransformationCopyObject(
|
||||
84, MakeInstructionDescriptor(32, SpvOpCompositeConstruct, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because id %9 is already in use
|
||||
ASSERT_FALSE(TransformationCopyObject(84, 32, 2, 9)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationCopyObject(
|
||||
84, MakeInstructionDescriptor(32, SpvOpCompositeConstruct, 0), 9)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because the requested point is not in a block
|
||||
ASSERT_FALSE(TransformationCopyObject(84, 86, 3, 200)
|
||||
// Inapplicable because the requested point does not exist
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
84, MakeInstructionDescriptor(86, SpvOpReturn, 2), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because %9 is not in a function
|
||||
ASSERT_FALSE(TransformationCopyObject(9, 9, 1, 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because %9 is not in a function
|
||||
ASSERT_FALSE(TransformationCopyObject(9, 9, 1, 200)
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(9, SpvOpTypeInt, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because the insert point is right before, or inside, a chunk
|
||||
// of OpPhis
|
||||
ASSERT_FALSE(TransformationCopyObject(9, 30, 1, 200)
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(30, SpvOpPhi, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationCopyObject(9, 99, 1, 200)
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(99, SpvOpPhi, 1), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// OK, because the insert point is just after a chunk of OpPhis.
|
||||
ASSERT_TRUE(TransformationCopyObject(9, 96, 1, 200)
|
||||
ASSERT_TRUE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(96, SpvOpAccessChain, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because the insert point is right after an OpSelectionMerge
|
||||
ASSERT_FALSE(TransformationCopyObject(9, 58, 2, 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(58, SpvOpBranchConditional, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// OK, because the insert point is right before the OpSelectionMerge
|
||||
ASSERT_TRUE(TransformationCopyObject(9, 58, 1, 200)
|
||||
ASSERT_TRUE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(58, SpvOpSelectionMerge, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because the insert point is right after an OpSelectionMerge
|
||||
ASSERT_FALSE(TransformationCopyObject(9, 43, 2, 200)
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(43, SpvOpSwitch, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// OK, because the insert point is right before the OpSelectionMerge
|
||||
ASSERT_TRUE(TransformationCopyObject(9, 43, 1, 200)
|
||||
ASSERT_TRUE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(43, SpvOpSelectionMerge, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because the insert point is right after an OpLoopMerge
|
||||
ASSERT_FALSE(TransformationCopyObject(9, 40, 2, 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(
|
||||
TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(40, SpvOpBranchConditional, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// OK, because the insert point is right before the OpLoopMerge
|
||||
ASSERT_TRUE(TransformationCopyObject(9, 40, 1, 200)
|
||||
ASSERT_TRUE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(40, SpvOpLoopMerge, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because id %300 does not exist
|
||||
ASSERT_FALSE(TransformationCopyObject(300, 40, 1, 200)
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
300, MakeInstructionDescriptor(40, SpvOpLoopMerge, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// Inapplicable because the following instruction is OpVariable
|
||||
ASSERT_FALSE(TransformationCopyObject(9, 180, 0, 200)
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(180, SpvOpVariable, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationCopyObject(9, 181, 0, 200)
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(181, SpvOpVariable, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
ASSERT_FALSE(TransformationCopyObject(9, 182, 0, 200)
|
||||
ASSERT_FALSE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(182, SpvOpVariable, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
|
||||
// OK, because this is just past the group of OpVariable instructions.
|
||||
ASSERT_TRUE(TransformationCopyObject(9, 182, 1, 200)
|
||||
ASSERT_TRUE(TransformationCopyObject(
|
||||
9, MakeInstructionDescriptor(182, SpvOpAccessChain, 0), 200)
|
||||
.IsApplicable(context.get(), fact_manager));
|
||||
}
|
||||
|
||||
@ -470,13 +498,20 @@ TEST(TransformationCopyObjectTest, MiscellaneousCopies) {
|
||||
FactManager fact_manager;
|
||||
|
||||
std::vector<TransformationCopyObject> transformations = {
|
||||
TransformationCopyObject(19, 22, 1, 100),
|
||||
TransformationCopyObject(22, 22, 1, 101),
|
||||
TransformationCopyObject(12, 22, 1, 102),
|
||||
TransformationCopyObject(11, 22, 1, 103),
|
||||
TransformationCopyObject(16, 22, 1, 104),
|
||||
TransformationCopyObject(8, 22, 1, 105),
|
||||
TransformationCopyObject(17, 22, 1, 106)};
|
||||
TransformationCopyObject(19, MakeInstructionDescriptor(22, SpvOpStore, 0),
|
||||
100),
|
||||
TransformationCopyObject(
|
||||
22, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 101),
|
||||
TransformationCopyObject(
|
||||
12, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 102),
|
||||
TransformationCopyObject(
|
||||
11, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 103),
|
||||
TransformationCopyObject(
|
||||
16, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 104),
|
||||
TransformationCopyObject(
|
||||
8, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 105),
|
||||
TransformationCopyObject(
|
||||
17, MakeInstructionDescriptor(22, SpvOpCopyObject, 0), 106)};
|
||||
|
||||
for (auto& transformation : transformations) {
|
||||
ASSERT_TRUE(transformation.IsApplicable(context.get(), fact_manager));
|
||||
|
Loading…
Reference in New Issue
Block a user