mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2025-01-12 17:30:15 +00:00
spirv-fuzz: Optimize transformations (#4216)
Avoids blanket invalidation of analyses in several transformations, instead updating the def-use manager and instruction to block mapping.
This commit is contained in:
parent
f227930153
commit
d0c73fcee1
@ -228,6 +228,11 @@ void TransformationAccessChain::Apply(
|
|||||||
|
|
||||||
uint32_t id_pairs_used = 0;
|
uint32_t id_pairs_used = 0;
|
||||||
|
|
||||||
|
opt::Instruction* instruction_to_insert_before =
|
||||||
|
FindInstruction(message_.instruction_to_insert_before(), ir_context);
|
||||||
|
opt::BasicBlock* enclosing_block =
|
||||||
|
ir_context->get_instr_block(instruction_to_insert_before);
|
||||||
|
|
||||||
// Go through the index ids in turn.
|
// Go through the index ids in turn.
|
||||||
for (auto index_id : message_.index_id()) {
|
for (auto index_id : message_.index_id()) {
|
||||||
uint32_t index_value;
|
uint32_t index_value;
|
||||||
@ -280,29 +285,37 @@ void TransformationAccessChain::Apply(
|
|||||||
|
|
||||||
// Clamp the integer and add the corresponding instructions in the module
|
// Clamp the integer and add the corresponding instructions in the module
|
||||||
// if |add_clamping_instructions| is set.
|
// if |add_clamping_instructions| is set.
|
||||||
auto instruction_to_insert_before =
|
|
||||||
FindInstruction(message_.instruction_to_insert_before(), ir_context);
|
|
||||||
|
|
||||||
// Compare the index with the bound via an instruction of the form:
|
// Compare the index with the bound via an instruction of the form:
|
||||||
// %fresh_ids.first = OpULessThanEqual %bool %int_id %bound_minus_one.
|
// %fresh_ids.first = OpULessThanEqual %bool %int_id %bound_minus_one.
|
||||||
fuzzerutil::UpdateModuleIdBound(ir_context, fresh_ids.first());
|
fuzzerutil::UpdateModuleIdBound(ir_context, fresh_ids.first());
|
||||||
instruction_to_insert_before->InsertBefore(MakeUnique<opt::Instruction>(
|
auto comparison_instruction = MakeUnique<opt::Instruction>(
|
||||||
ir_context, SpvOpULessThanEqual, bool_type_id, fresh_ids.first(),
|
ir_context, SpvOpULessThanEqual, bool_type_id, fresh_ids.first(),
|
||||||
opt::Instruction::OperandList(
|
opt::Instruction::OperandList(
|
||||||
{{SPV_OPERAND_TYPE_ID, {index_instruction->result_id()}},
|
{{SPV_OPERAND_TYPE_ID, {index_instruction->result_id()}},
|
||||||
{SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}})));
|
{SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}}));
|
||||||
|
auto comparison_instruction_ptr = comparison_instruction.get();
|
||||||
|
instruction_to_insert_before->InsertBefore(
|
||||||
|
std::move(comparison_instruction));
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(
|
||||||
|
comparison_instruction_ptr);
|
||||||
|
ir_context->set_instr_block(comparison_instruction_ptr, enclosing_block);
|
||||||
|
|
||||||
// Select the index if in-bounds, otherwise one less than the bound:
|
// Select the index if in-bounds, otherwise one less than the bound:
|
||||||
// %fresh_ids.second = OpSelect %int_type %fresh_ids.first %int_id
|
// %fresh_ids.second = OpSelect %int_type %fresh_ids.first %int_id
|
||||||
// %bound_minus_one
|
// %bound_minus_one
|
||||||
fuzzerutil::UpdateModuleIdBound(ir_context, fresh_ids.second());
|
fuzzerutil::UpdateModuleIdBound(ir_context, fresh_ids.second());
|
||||||
instruction_to_insert_before->InsertBefore(MakeUnique<opt::Instruction>(
|
auto select_instruction = MakeUnique<opt::Instruction>(
|
||||||
ir_context, SpvOpSelect, int_type_inst->result_id(),
|
ir_context, SpvOpSelect, int_type_inst->result_id(),
|
||||||
fresh_ids.second(),
|
fresh_ids.second(),
|
||||||
opt::Instruction::OperandList(
|
opt::Instruction::OperandList(
|
||||||
{{SPV_OPERAND_TYPE_ID, {fresh_ids.first()}},
|
{{SPV_OPERAND_TYPE_ID, {fresh_ids.first()}},
|
||||||
{SPV_OPERAND_TYPE_ID, {index_instruction->result_id()}},
|
{SPV_OPERAND_TYPE_ID, {index_instruction->result_id()}},
|
||||||
{SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}})));
|
{SPV_OPERAND_TYPE_ID, {bound_minus_one_id}}}));
|
||||||
|
auto select_instruction_ptr = select_instruction.get();
|
||||||
|
instruction_to_insert_before->InsertBefore(std::move(select_instruction));
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(select_instruction_ptr);
|
||||||
|
ir_context->set_instr_block(select_instruction_ptr, enclosing_block);
|
||||||
|
|
||||||
new_index_id = fresh_ids.second();
|
new_index_id = fresh_ids.second();
|
||||||
|
|
||||||
@ -326,13 +339,14 @@ void TransformationAccessChain::Apply(
|
|||||||
// Add the access chain instruction to the module, and update the module's
|
// Add the access chain instruction to the module, and update the module's
|
||||||
// id bound.
|
// id bound.
|
||||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||||
FindInstruction(message_.instruction_to_insert_before(), ir_context)
|
auto access_chain_instruction = MakeUnique<opt::Instruction>(
|
||||||
->InsertBefore(MakeUnique<opt::Instruction>(
|
ir_context, SpvOpAccessChain, result_type, message_.fresh_id(), operands);
|
||||||
ir_context, SpvOpAccessChain, result_type, message_.fresh_id(),
|
auto access_chain_instruction_ptr = access_chain_instruction.get();
|
||||||
operands));
|
instruction_to_insert_before->InsertBefore(
|
||||||
|
std::move(access_chain_instruction));
|
||||||
// Conservatively invalidate all analyses.
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(
|
||||||
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
|
access_chain_instruction_ptr);
|
||||||
|
ir_context->set_instr_block(access_chain_instruction_ptr, enclosing_block);
|
||||||
|
|
||||||
// If the base pointer's pointee value was irrelevant, the same is true of
|
// If the base pointer's pointee value was irrelevant, the same is true of
|
||||||
// the pointee value of the result of this access chain.
|
// the pointee value of the result of this access chain.
|
||||||
|
@ -99,15 +99,8 @@ void TransformationAddCopyMemory::Apply(
|
|||||||
auto* insert_before_inst =
|
auto* insert_before_inst =
|
||||||
FindInstruction(message_.instruction_descriptor(), ir_context);
|
FindInstruction(message_.instruction_descriptor(), ir_context);
|
||||||
assert(insert_before_inst);
|
assert(insert_before_inst);
|
||||||
|
opt::BasicBlock* enclosing_block =
|
||||||
auto insert_before_iter = fuzzerutil::GetIteratorForInstruction(
|
ir_context->get_instr_block(insert_before_inst);
|
||||||
ir_context->get_instr_block(insert_before_inst), insert_before_inst);
|
|
||||||
|
|
||||||
insert_before_iter.InsertBefore(MakeUnique<opt::Instruction>(
|
|
||||||
ir_context, SpvOpCopyMemory, 0, 0,
|
|
||||||
opt::Instruction::OperandList{
|
|
||||||
{SPV_OPERAND_TYPE_ID, {message_.fresh_id()}},
|
|
||||||
{SPV_OPERAND_TYPE_ID, {message_.source_id()}}}));
|
|
||||||
|
|
||||||
// Add global or local variable to copy memory into.
|
// Add global or local variable to copy memory into.
|
||||||
auto storage_class = static_cast<SpvStorageClass>(message_.storage_class());
|
auto storage_class = static_cast<SpvStorageClass>(message_.storage_class());
|
||||||
@ -118,23 +111,35 @@ void TransformationAddCopyMemory::Apply(
|
|||||||
storage_class);
|
storage_class);
|
||||||
|
|
||||||
if (storage_class == SpvStorageClassPrivate) {
|
if (storage_class == SpvStorageClassPrivate) {
|
||||||
|
opt::Instruction* new_global =
|
||||||
fuzzerutil::AddGlobalVariable(ir_context, message_.fresh_id(), type_id,
|
fuzzerutil::AddGlobalVariable(ir_context, message_.fresh_id(), type_id,
|
||||||
storage_class, message_.initializer_id());
|
storage_class, message_.initializer_id());
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_global);
|
||||||
} else {
|
} else {
|
||||||
assert(storage_class == SpvStorageClassFunction &&
|
assert(storage_class == SpvStorageClassFunction &&
|
||||||
"Storage class can be either Private or Function");
|
"Storage class can be either Private or Function");
|
||||||
fuzzerutil::AddLocalVariable(ir_context, message_.fresh_id(), type_id,
|
opt::Function* enclosing_function = enclosing_block->GetParent();
|
||||||
ir_context->get_instr_block(insert_before_inst)
|
opt::Instruction* new_local = fuzzerutil::AddLocalVariable(
|
||||||
->GetParent()
|
ir_context, message_.fresh_id(), type_id,
|
||||||
->result_id(),
|
enclosing_function->result_id(), message_.initializer_id());
|
||||||
message_.initializer_id());
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_local);
|
||||||
|
ir_context->set_instr_block(new_local, &*enclosing_function->entry());
|
||||||
}
|
}
|
||||||
|
|
||||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
auto insert_before_iter = fuzzerutil::GetIteratorForInstruction(
|
||||||
|
enclosing_block, insert_before_inst);
|
||||||
|
|
||||||
// Make sure our changes are analyzed
|
auto new_instruction = MakeUnique<opt::Instruction>(
|
||||||
ir_context->InvalidateAnalysesExceptFor(
|
ir_context, SpvOpCopyMemory, 0, 0,
|
||||||
opt::IRContext::Analysis::kAnalysisNone);
|
opt::Instruction::OperandList{
|
||||||
|
{SPV_OPERAND_TYPE_ID, {message_.fresh_id()}},
|
||||||
|
{SPV_OPERAND_TYPE_ID, {message_.source_id()}}});
|
||||||
|
auto new_instruction_ptr = new_instruction.get();
|
||||||
|
insert_before_iter.InsertBefore(std::move(new_instruction));
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr);
|
||||||
|
ir_context->set_instr_block(new_instruction_ptr, enclosing_block);
|
||||||
|
|
||||||
|
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||||
|
|
||||||
// Even though the copy memory instruction will - at least temporarily - lead
|
// Even though the copy memory instruction will - at least temporarily - lead
|
||||||
// to the destination and source pointers referring to identical values, this
|
// to the destination and source pointers referring to identical values, this
|
||||||
|
@ -102,14 +102,19 @@ void TransformationAddSynonym::Apply(
|
|||||||
opt::IRContext* ir_context,
|
opt::IRContext* ir_context,
|
||||||
TransformationContext* transformation_context) const {
|
TransformationContext* transformation_context) const {
|
||||||
// Add a synonymous instruction.
|
// Add a synonymous instruction.
|
||||||
FindInstruction(message_.insert_before(), ir_context)
|
auto new_instruction =
|
||||||
->InsertBefore(
|
MakeSynonymousInstruction(ir_context, *transformation_context);
|
||||||
MakeSynonymousInstruction(ir_context, *transformation_context));
|
auto new_instruction_ptr = new_instruction.get();
|
||||||
|
auto insert_before = FindInstruction(message_.insert_before(), ir_context);
|
||||||
|
insert_before->InsertBefore(std::move(new_instruction));
|
||||||
|
|
||||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.synonym_fresh_id());
|
fuzzerutil::UpdateModuleIdBound(ir_context, message_.synonym_fresh_id());
|
||||||
|
|
||||||
ir_context->InvalidateAnalysesExceptFor(
|
// Inform the def-use manager about the new instruction and record its basic
|
||||||
opt::IRContext::Analysis::kAnalysisNone);
|
// block.
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr);
|
||||||
|
ir_context->set_instr_block(new_instruction_ptr,
|
||||||
|
ir_context->get_instr_block(insert_before));
|
||||||
|
|
||||||
// Propagate PointeeValueIsIrrelevant fact.
|
// Propagate PointeeValueIsIrrelevant fact.
|
||||||
const auto* new_synonym_type = ir_context->get_type_mgr()->GetType(
|
const auto* new_synonym_type = ir_context->get_type_mgr()->GetType(
|
||||||
|
@ -91,13 +91,12 @@ void TransformationCompositeExtract::Apply(
|
|||||||
|
|
||||||
auto insert_before =
|
auto insert_before =
|
||||||
FindInstruction(message_.instruction_to_insert_before(), ir_context);
|
FindInstruction(message_.instruction_to_insert_before(), ir_context);
|
||||||
auto new_instruction = MakeUnique<opt::Instruction>(
|
opt::Instruction* new_instruction =
|
||||||
ir_context, SpvOpCompositeExtract, extracted_type, message_.fresh_id(),
|
insert_before->InsertBefore(MakeUnique<opt::Instruction>(
|
||||||
extract_operands);
|
ir_context, SpvOpCompositeExtract, extracted_type,
|
||||||
auto new_instruction_ptr = new_instruction.get();
|
message_.fresh_id(), extract_operands));
|
||||||
insert_before->InsertBefore(std::move(new_instruction));
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction);
|
||||||
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr);
|
ir_context->set_instr_block(new_instruction,
|
||||||
ir_context->set_instr_block(new_instruction_ptr,
|
|
||||||
ir_context->get_instr_block(insert_before));
|
ir_context->get_instr_block(insert_before));
|
||||||
|
|
||||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||||
|
@ -124,15 +124,21 @@ void TransformationCompositeInsert::Apply(
|
|||||||
auto composite_type_id =
|
auto composite_type_id =
|
||||||
fuzzerutil::GetTypeId(ir_context, message_.composite_id());
|
fuzzerutil::GetTypeId(ir_context, message_.composite_id());
|
||||||
|
|
||||||
FindInstruction(message_.instruction_to_insert_before(), ir_context)
|
auto insert_before =
|
||||||
->InsertBefore(MakeUnique<opt::Instruction>(
|
FindInstruction(message_.instruction_to_insert_before(), ir_context);
|
||||||
ir_context, SpvOpCompositeInsert, composite_type_id,
|
auto new_instruction = MakeUnique<opt::Instruction>(
|
||||||
message_.fresh_id(), std::move(in_operands)));
|
ir_context, SpvOpCompositeInsert, composite_type_id, message_.fresh_id(),
|
||||||
|
std::move(in_operands));
|
||||||
|
auto new_instruction_ptr = new_instruction.get();
|
||||||
|
insert_before->InsertBefore(std::move(new_instruction));
|
||||||
|
|
||||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||||
|
|
||||||
// We have modified the module so most analyzes are now invalid.
|
// Inform the def-use manager about the new instruction and record its basic
|
||||||
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
|
// block.
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr);
|
||||||
|
ir_context->set_instr_block(new_instruction_ptr,
|
||||||
|
ir_context->get_instr_block(insert_before));
|
||||||
|
|
||||||
// Add data synonym facts that arise from the insertion.
|
// Add data synonym facts that arise from the insertion.
|
||||||
AddDataSynonymFacts(ir_context, transformation_context);
|
AddDataSynonymFacts(ir_context, transformation_context);
|
||||||
|
@ -84,18 +84,16 @@ void TransformationEquationInstruction::Apply(
|
|||||||
rhs_id.push_back(id);
|
rhs_id.push_back(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto new_instruction = MakeUnique<opt::Instruction>(
|
|
||||||
ir_context, static_cast<SpvOp>(message_.opcode()),
|
|
||||||
MaybeGetResultTypeId(ir_context), message_.fresh_id(),
|
|
||||||
std::move(in_operands));
|
|
||||||
auto new_instruction_ptr = new_instruction.get();
|
|
||||||
|
|
||||||
auto insert_before =
|
auto insert_before =
|
||||||
FindInstruction(message_.instruction_to_insert_before(), ir_context);
|
FindInstruction(message_.instruction_to_insert_before(), ir_context);
|
||||||
insert_before->InsertBefore(std::move(new_instruction));
|
opt::Instruction* new_instruction =
|
||||||
|
insert_before->InsertBefore(MakeUnique<opt::Instruction>(
|
||||||
|
ir_context, static_cast<SpvOp>(message_.opcode()),
|
||||||
|
MaybeGetResultTypeId(ir_context), message_.fresh_id(),
|
||||||
|
std::move(in_operands)));
|
||||||
|
|
||||||
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr);
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction);
|
||||||
ir_context->set_instr_block(new_instruction_ptr,
|
ir_context->set_instr_block(new_instruction,
|
||||||
ir_context->get_instr_block(insert_before));
|
ir_context->get_instr_block(insert_before));
|
||||||
|
|
||||||
// Add an equation fact as long as the result id is not irrelevant (it could
|
// Add an equation fact as long as the result id is not irrelevant (it could
|
||||||
|
@ -83,12 +83,19 @@ void TransformationLoad::Apply(opt::IRContext* ir_context,
|
|||||||
uint32_t result_type = fuzzerutil::GetPointeeTypeIdFromPointerType(
|
uint32_t result_type = fuzzerutil::GetPointeeTypeIdFromPointerType(
|
||||||
ir_context, fuzzerutil::GetTypeId(ir_context, message_.pointer_id()));
|
ir_context, fuzzerutil::GetTypeId(ir_context, message_.pointer_id()));
|
||||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||||
FindInstruction(message_.instruction_to_insert_before(), ir_context)
|
auto insert_before =
|
||||||
->InsertBefore(MakeUnique<opt::Instruction>(
|
FindInstruction(message_.instruction_to_insert_before(), ir_context);
|
||||||
|
auto new_instruction = MakeUnique<opt::Instruction>(
|
||||||
ir_context, SpvOpLoad, result_type, message_.fresh_id(),
|
ir_context, SpvOpLoad, result_type, message_.fresh_id(),
|
||||||
opt::Instruction::OperandList(
|
opt::Instruction::OperandList(
|
||||||
{{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}})));
|
{{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}}));
|
||||||
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
|
auto new_instruction_ptr = new_instruction.get();
|
||||||
|
insert_before->InsertBefore(std::move(new_instruction));
|
||||||
|
// Inform the def-use manager about the new instruction and record its basic
|
||||||
|
// block.
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr);
|
||||||
|
ir_context->set_instr_block(new_instruction_ptr,
|
||||||
|
ir_context->get_instr_block(insert_before));
|
||||||
}
|
}
|
||||||
|
|
||||||
protobufs::Transformation TransformationLoad::ToMessage() const {
|
protobufs::Transformation TransformationLoad::ToMessage() const {
|
||||||
|
@ -92,36 +92,47 @@ void TransformationMutatePointer::Apply(
|
|||||||
auto* insert_before_inst =
|
auto* insert_before_inst =
|
||||||
FindInstruction(message_.insert_before(), ir_context);
|
FindInstruction(message_.insert_before(), ir_context);
|
||||||
assert(insert_before_inst && "|insert_before| descriptor is invalid");
|
assert(insert_before_inst && "|insert_before| descriptor is invalid");
|
||||||
|
opt::BasicBlock* enclosing_block =
|
||||||
|
ir_context->get_instr_block(insert_before_inst);
|
||||||
|
|
||||||
auto pointee_type_id = fuzzerutil::GetPointeeTypeIdFromPointerType(
|
auto pointee_type_id = fuzzerutil::GetPointeeTypeIdFromPointerType(
|
||||||
ir_context, fuzzerutil::GetTypeId(ir_context, message_.pointer_id()));
|
ir_context, fuzzerutil::GetTypeId(ir_context, message_.pointer_id()));
|
||||||
|
|
||||||
// Back up the original value.
|
// Back up the original value.
|
||||||
insert_before_inst->InsertBefore(MakeUnique<opt::Instruction>(
|
auto backup_instruction = MakeUnique<opt::Instruction>(
|
||||||
ir_context, SpvOpLoad, pointee_type_id, message_.fresh_id(),
|
ir_context, SpvOpLoad, pointee_type_id, message_.fresh_id(),
|
||||||
opt::Instruction::OperandList{
|
opt::Instruction::OperandList{
|
||||||
{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}}));
|
{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}}});
|
||||||
|
auto backup_instruction_ptr = backup_instruction.get();
|
||||||
|
insert_before_inst->InsertBefore(std::move(backup_instruction));
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(backup_instruction_ptr);
|
||||||
|
ir_context->set_instr_block(backup_instruction_ptr, enclosing_block);
|
||||||
|
|
||||||
// Insert a new value.
|
// Insert a new value.
|
||||||
insert_before_inst->InsertBefore(MakeUnique<opt::Instruction>(
|
auto new_value_instruction = MakeUnique<opt::Instruction>(
|
||||||
ir_context, SpvOpStore, 0, 0,
|
ir_context, SpvOpStore, 0, 0,
|
||||||
opt::Instruction::OperandList{
|
opt::Instruction::OperandList{
|
||||||
{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}},
|
{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}},
|
||||||
{SPV_OPERAND_TYPE_ID,
|
{SPV_OPERAND_TYPE_ID,
|
||||||
{fuzzerutil::MaybeGetZeroConstant(
|
{fuzzerutil::MaybeGetZeroConstant(
|
||||||
ir_context, *transformation_context, pointee_type_id, true)}}}));
|
ir_context, *transformation_context, pointee_type_id, true)}}});
|
||||||
|
auto new_value_instruction_ptr = new_value_instruction.get();
|
||||||
|
insert_before_inst->InsertBefore(std::move(new_value_instruction));
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_value_instruction_ptr);
|
||||||
|
ir_context->set_instr_block(new_value_instruction_ptr, enclosing_block);
|
||||||
|
|
||||||
// Restore the original value.
|
// Restore the original value.
|
||||||
insert_before_inst->InsertBefore(MakeUnique<opt::Instruction>(
|
auto restore_instruction = MakeUnique<opt::Instruction>(
|
||||||
ir_context, SpvOpStore, 0, 0,
|
ir_context, SpvOpStore, 0, 0,
|
||||||
opt::Instruction::OperandList{
|
opt::Instruction::OperandList{
|
||||||
{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}},
|
{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}},
|
||||||
{SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}}));
|
{SPV_OPERAND_TYPE_ID, {message_.fresh_id()}}});
|
||||||
|
auto restore_instruction_ptr = restore_instruction.get();
|
||||||
|
insert_before_inst->InsertBefore(std::move(restore_instruction));
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(restore_instruction_ptr);
|
||||||
|
ir_context->set_instr_block(restore_instruction_ptr, enclosing_block);
|
||||||
|
|
||||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||||
|
|
||||||
// Make sure analyses represent the correct state of the module.
|
|
||||||
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protobufs::Transformation TransformationMutatePointer::ToMessage() const {
|
protobufs::Transformation TransformationMutatePointer::ToMessage() const {
|
||||||
|
@ -104,6 +104,10 @@ void TransformationPushIdThroughVariable::Apply(
|
|||||||
auto value_instruction =
|
auto value_instruction =
|
||||||
ir_context->get_def_use_mgr()->GetDef(message_.value_id());
|
ir_context->get_def_use_mgr()->GetDef(message_.value_id());
|
||||||
|
|
||||||
|
opt::Instruction* insert_before =
|
||||||
|
FindInstruction(message_.instruction_descriptor(), ir_context);
|
||||||
|
opt::BasicBlock* enclosing_block = ir_context->get_instr_block(insert_before);
|
||||||
|
|
||||||
// A pointer type instruction pointing to the value type must be defined.
|
// A pointer type instruction pointing to the value type must be defined.
|
||||||
auto pointer_type_id = fuzzerutil::MaybeGetPointerType(
|
auto pointer_type_id = fuzzerutil::MaybeGetPointerType(
|
||||||
ir_context, value_instruction->type_id(),
|
ir_context, value_instruction->type_id(),
|
||||||
@ -112,36 +116,42 @@ void TransformationPushIdThroughVariable::Apply(
|
|||||||
|
|
||||||
// Adds whether a global or local variable.
|
// Adds whether a global or local variable.
|
||||||
if (message_.variable_storage_class() == SpvStorageClassPrivate) {
|
if (message_.variable_storage_class() == SpvStorageClassPrivate) {
|
||||||
fuzzerutil::AddGlobalVariable(ir_context, message_.variable_id(),
|
opt::Instruction* global_variable = fuzzerutil::AddGlobalVariable(
|
||||||
pointer_type_id, SpvStorageClassPrivate,
|
ir_context, message_.variable_id(), pointer_type_id,
|
||||||
message_.initializer_id());
|
SpvStorageClassPrivate, message_.initializer_id());
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(global_variable);
|
||||||
} else {
|
} else {
|
||||||
auto function_id = ir_context
|
opt::Function* function =
|
||||||
->get_instr_block(FindInstruction(
|
ir_context
|
||||||
message_.instruction_descriptor(), ir_context))
|
->get_instr_block(
|
||||||
->GetParent()
|
FindInstruction(message_.instruction_descriptor(), ir_context))
|
||||||
->result_id();
|
->GetParent();
|
||||||
fuzzerutil::AddLocalVariable(ir_context, message_.variable_id(),
|
opt::Instruction* local_variable = fuzzerutil::AddLocalVariable(
|
||||||
pointer_type_id, function_id,
|
ir_context, message_.variable_id(), pointer_type_id,
|
||||||
message_.initializer_id());
|
function->result_id(), message_.initializer_id());
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(local_variable);
|
||||||
|
ir_context->set_instr_block(local_variable, &*function->entry());
|
||||||
}
|
}
|
||||||
|
|
||||||
// First, insert the OpLoad instruction before |instruction_descriptor| and
|
// First, insert the OpLoad instruction before |instruction_descriptor| and
|
||||||
// then insert the OpStore instruction before the OpLoad instruction.
|
// then insert the OpStore instruction before the OpLoad instruction.
|
||||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.value_synonym_id());
|
fuzzerutil::UpdateModuleIdBound(ir_context, message_.value_synonym_id());
|
||||||
FindInstruction(message_.instruction_descriptor(), ir_context)
|
opt::Instruction* load_instruction =
|
||||||
->InsertBefore(MakeUnique<opt::Instruction>(
|
insert_before->InsertBefore(MakeUnique<opt::Instruction>(
|
||||||
ir_context, SpvOpLoad, value_instruction->type_id(),
|
ir_context, SpvOpLoad, value_instruction->type_id(),
|
||||||
message_.value_synonym_id(),
|
message_.value_synonym_id(),
|
||||||
opt::Instruction::OperandList(
|
opt::Instruction::OperandList(
|
||||||
{{SPV_OPERAND_TYPE_ID, {message_.variable_id()}}})))
|
{{SPV_OPERAND_TYPE_ID, {message_.variable_id()}}})));
|
||||||
->InsertBefore(MakeUnique<opt::Instruction>(
|
opt::Instruction* store_instruction =
|
||||||
|
load_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||||
ir_context, SpvOpStore, 0, 0,
|
ir_context, SpvOpStore, 0, 0,
|
||||||
opt::Instruction::OperandList(
|
opt::Instruction::OperandList(
|
||||||
{{SPV_OPERAND_TYPE_ID, {message_.variable_id()}},
|
{{SPV_OPERAND_TYPE_ID, {message_.variable_id()}},
|
||||||
{SPV_OPERAND_TYPE_ID, {message_.value_id()}}})));
|
{SPV_OPERAND_TYPE_ID, {message_.value_id()}}})));
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(store_instruction);
|
||||||
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
|
ir_context->set_instr_block(store_instruction, enclosing_block);
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(load_instruction);
|
||||||
|
ir_context->set_instr_block(load_instruction, enclosing_block);
|
||||||
|
|
||||||
// We should be able to create a synonym of |value_id| if it's not irrelevant.
|
// We should be able to create a synonym of |value_id| if it's not irrelevant.
|
||||||
if (fuzzerutil::CanMakeSynonymOf(ir_context, *transformation_context,
|
if (fuzzerutil::CanMakeSynonymOf(ir_context, *transformation_context,
|
||||||
|
@ -253,28 +253,39 @@ void TransformationReplaceConstantWithUniform::Apply(
|
|||||||
auto* insert_before_inst = GetInsertBeforeInstruction(ir_context);
|
auto* insert_before_inst = GetInsertBeforeInstruction(ir_context);
|
||||||
assert(insert_before_inst &&
|
assert(insert_before_inst &&
|
||||||
"There must exist an insertion point for OpAccessChain and OpLoad");
|
"There must exist an insertion point for OpAccessChain and OpLoad");
|
||||||
|
opt::BasicBlock* enclosing_block =
|
||||||
|
ir_context->get_instr_block(insert_before_inst);
|
||||||
|
|
||||||
// Add an access chain instruction to target the uniform element.
|
// Add an access chain instruction to target the uniform element.
|
||||||
insert_before_inst->InsertBefore(
|
auto access_chain_instruction =
|
||||||
MakeAccessChainInstruction(ir_context, constant_type_id));
|
MakeAccessChainInstruction(ir_context, constant_type_id);
|
||||||
|
auto access_chain_instruction_ptr = access_chain_instruction.get();
|
||||||
|
insert_before_inst->InsertBefore(std::move(access_chain_instruction));
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(
|
||||||
|
access_chain_instruction_ptr);
|
||||||
|
ir_context->set_instr_block(access_chain_instruction_ptr, enclosing_block);
|
||||||
|
|
||||||
// Add a load from this access chain.
|
// Add a load from this access chain.
|
||||||
insert_before_inst->InsertBefore(
|
auto load_instruction = MakeLoadInstruction(ir_context, constant_type_id);
|
||||||
MakeLoadInstruction(ir_context, constant_type_id));
|
auto load_instruction_ptr = load_instruction.get();
|
||||||
|
insert_before_inst->InsertBefore(std::move(load_instruction));
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(load_instruction_ptr);
|
||||||
|
ir_context->set_instr_block(load_instruction_ptr, enclosing_block);
|
||||||
|
|
||||||
// Adjust the instruction containing the usage of the constant so that this
|
// Adjust the instruction containing the usage of the constant so that this
|
||||||
// usage refers instead to the result of the load.
|
// usage refers instead to the result of the load.
|
||||||
instruction_containing_constant_use->SetInOperand(
|
instruction_containing_constant_use->SetInOperand(
|
||||||
message_.id_use_descriptor().in_operand_index(),
|
message_.id_use_descriptor().in_operand_index(),
|
||||||
{message_.fresh_id_for_load()});
|
{message_.fresh_id_for_load()});
|
||||||
|
ir_context->get_def_use_mgr()->EraseUseRecordsOfOperandIds(
|
||||||
|
instruction_containing_constant_use);
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstUse(
|
||||||
|
instruction_containing_constant_use);
|
||||||
|
|
||||||
// Update the module id bound to reflect the new instructions.
|
// Update the module id bound to reflect the new instructions.
|
||||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id_for_load());
|
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id_for_load());
|
||||||
fuzzerutil::UpdateModuleIdBound(ir_context,
|
fuzzerutil::UpdateModuleIdBound(ir_context,
|
||||||
message_.fresh_id_for_access_chain());
|
message_.fresh_id_for_access_chain());
|
||||||
|
|
||||||
ir_context->InvalidateAnalysesExceptFor(
|
|
||||||
opt::IRContext::Analysis::kAnalysisNone);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protobufs::Transformation TransformationReplaceConstantWithUniform::ToMessage()
|
protobufs::Transformation TransformationReplaceConstantWithUniform::ToMessage()
|
||||||
|
@ -87,6 +87,10 @@ void TransformationReplaceCopyObjectWithStoreLoad::Apply(
|
|||||||
assert(copy_object_instruction &&
|
assert(copy_object_instruction &&
|
||||||
copy_object_instruction->opcode() == SpvOpCopyObject &&
|
copy_object_instruction->opcode() == SpvOpCopyObject &&
|
||||||
"The required OpCopyObject instruction must be defined.");
|
"The required OpCopyObject instruction must be defined.");
|
||||||
|
|
||||||
|
opt::BasicBlock* enclosing_block =
|
||||||
|
ir_context->get_instr_block(copy_object_instruction);
|
||||||
|
|
||||||
// Get id used as a source by the OpCopyObject instruction.
|
// Get id used as a source by the OpCopyObject instruction.
|
||||||
uint32_t src_operand = copy_object_instruction->GetSingleWordInOperand(0);
|
uint32_t src_operand = copy_object_instruction->GetSingleWordInOperand(0);
|
||||||
// A pointer type instruction pointing to the value type must be defined.
|
// A pointer type instruction pointing to the value type must be defined.
|
||||||
@ -97,37 +101,46 @@ void TransformationReplaceCopyObjectWithStoreLoad::Apply(
|
|||||||
|
|
||||||
// Adds a global or local variable (according to the storage class).
|
// Adds a global or local variable (according to the storage class).
|
||||||
if (message_.variable_storage_class() == SpvStorageClassPrivate) {
|
if (message_.variable_storage_class() == SpvStorageClassPrivate) {
|
||||||
fuzzerutil::AddGlobalVariable(ir_context, message_.fresh_variable_id(),
|
opt::Instruction* new_global = fuzzerutil::AddGlobalVariable(
|
||||||
pointer_type_id, SpvStorageClassPrivate,
|
ir_context, message_.fresh_variable_id(), pointer_type_id,
|
||||||
message_.variable_initializer_id());
|
SpvStorageClassPrivate, message_.variable_initializer_id());
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_global);
|
||||||
} else {
|
} else {
|
||||||
auto function_id = ir_context->get_instr_block(copy_object_instruction)
|
opt::Function* function =
|
||||||
->GetParent()
|
ir_context->get_instr_block(copy_object_instruction)->GetParent();
|
||||||
->result_id();
|
opt::Instruction* new_local = fuzzerutil::AddLocalVariable(
|
||||||
fuzzerutil::AddLocalVariable(ir_context, message_.fresh_variable_id(),
|
ir_context, message_.fresh_variable_id(), pointer_type_id,
|
||||||
pointer_type_id, function_id,
|
function->result_id(), message_.variable_initializer_id());
|
||||||
message_.variable_initializer_id());
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_local);
|
||||||
|
ir_context->set_instr_block(new_local, &*function->begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
// First, insert the OpLoad instruction before the OpCopyObject instruction
|
// First, insert the OpLoad instruction before the OpCopyObject instruction
|
||||||
// and then insert the OpStore instruction before the OpLoad instruction.
|
// and then insert the OpStore instruction before the OpLoad instruction.
|
||||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_variable_id());
|
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_variable_id());
|
||||||
copy_object_instruction
|
opt::Instruction* load_instruction =
|
||||||
->InsertBefore(MakeUnique<opt::Instruction>(
|
copy_object_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||||
ir_context, SpvOpLoad, copy_object_instruction->type_id(),
|
ir_context, SpvOpLoad, copy_object_instruction->type_id(),
|
||||||
message_.copy_object_result_id(),
|
message_.copy_object_result_id(),
|
||||||
opt::Instruction::OperandList(
|
opt::Instruction::OperandList(
|
||||||
{{SPV_OPERAND_TYPE_ID, {message_.fresh_variable_id()}}})))
|
{{SPV_OPERAND_TYPE_ID, {message_.fresh_variable_id()}}})));
|
||||||
->InsertBefore(MakeUnique<opt::Instruction>(
|
opt::Instruction* store_instruction =
|
||||||
|
load_instruction->InsertBefore(MakeUnique<opt::Instruction>(
|
||||||
ir_context, SpvOpStore, 0, 0,
|
ir_context, SpvOpStore, 0, 0,
|
||||||
opt::Instruction::OperandList(
|
opt::Instruction::OperandList(
|
||||||
{{SPV_OPERAND_TYPE_ID, {message_.fresh_variable_id()}},
|
{{SPV_OPERAND_TYPE_ID, {message_.fresh_variable_id()}},
|
||||||
{SPV_OPERAND_TYPE_ID, {src_operand}}})));
|
{SPV_OPERAND_TYPE_ID, {src_operand}}})));
|
||||||
|
|
||||||
|
// Register the new instructions with the def-use manager, and record their
|
||||||
|
// enclosing block.
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(store_instruction);
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(load_instruction);
|
||||||
|
ir_context->set_instr_block(store_instruction, enclosing_block);
|
||||||
|
ir_context->set_instr_block(load_instruction, enclosing_block);
|
||||||
|
|
||||||
// Remove the CopyObject instruction.
|
// Remove the CopyObject instruction.
|
||||||
ir_context->KillInst(copy_object_instruction);
|
ir_context->KillInst(copy_object_instruction);
|
||||||
|
|
||||||
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
|
|
||||||
|
|
||||||
if (!transformation_context->GetFactManager()->IdIsIrrelevant(
|
if (!transformation_context->GetFactManager()->IdIsIrrelevant(
|
||||||
message_.copy_object_result_id()) &&
|
message_.copy_object_result_id()) &&
|
||||||
!transformation_context->GetFactManager()->IdIsIrrelevant(src_operand)) {
|
!transformation_context->GetFactManager()->IdIsIrrelevant(src_operand)) {
|
||||||
|
@ -107,9 +107,12 @@ void TransformationReplaceIrrelevantId::Apply(
|
|||||||
message_.id_use_descriptor().in_operand_index(),
|
message_.id_use_descriptor().in_operand_index(),
|
||||||
{message_.replacement_id()});
|
{message_.replacement_id()});
|
||||||
|
|
||||||
// Invalidate the analyses, since the usage of ids has been changed.
|
ir_context->get_def_use_mgr()->EraseUseRecordsOfOperandIds(
|
||||||
ir_context->InvalidateAnalysesExceptFor(
|
instruction_to_change);
|
||||||
opt::IRContext::Analysis::kAnalysisNone);
|
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 TransformationReplaceIrrelevantId::ToMessage() const {
|
protobufs::Transformation TransformationReplaceIrrelevantId::ToMessage() const {
|
||||||
|
@ -109,13 +109,20 @@ bool TransformationStore::IsApplicable(
|
|||||||
|
|
||||||
void TransformationStore::Apply(opt::IRContext* ir_context,
|
void TransformationStore::Apply(opt::IRContext* ir_context,
|
||||||
TransformationContext* /*unused*/) const {
|
TransformationContext* /*unused*/) const {
|
||||||
FindInstruction(message_.instruction_to_insert_before(), ir_context)
|
auto insert_before =
|
||||||
->InsertBefore(MakeUnique<opt::Instruction>(
|
FindInstruction(message_.instruction_to_insert_before(), ir_context);
|
||||||
|
auto new_instruction = MakeUnique<opt::Instruction>(
|
||||||
ir_context, SpvOpStore, 0, 0,
|
ir_context, SpvOpStore, 0, 0,
|
||||||
opt::Instruction::OperandList(
|
opt::Instruction::OperandList(
|
||||||
{{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}},
|
{{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}},
|
||||||
{SPV_OPERAND_TYPE_ID, {message_.value_id()}}})));
|
{SPV_OPERAND_TYPE_ID, {message_.value_id()}}}));
|
||||||
ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
|
auto new_instruction_ptr = new_instruction.get();
|
||||||
|
insert_before->InsertBefore(std::move(new_instruction));
|
||||||
|
// Inform the def-use manager about the new instruction and record its basic
|
||||||
|
// block.
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction_ptr);
|
||||||
|
ir_context->set_instr_block(new_instruction_ptr,
|
||||||
|
ir_context->get_instr_block(insert_before));
|
||||||
}
|
}
|
||||||
|
|
||||||
protobufs::Transformation TransformationStore::ToMessage() const {
|
protobufs::Transformation TransformationStore::ToMessage() const {
|
||||||
|
@ -130,13 +130,18 @@ void TransformationVectorShuffle::Apply(
|
|||||||
|
|
||||||
// Add a shuffle instruction right before the instruction identified by
|
// Add a shuffle instruction right before the instruction identified by
|
||||||
// |message_.instruction_to_insert_before|.
|
// |message_.instruction_to_insert_before|.
|
||||||
FindInstruction(message_.instruction_to_insert_before(), ir_context)
|
auto insert_before =
|
||||||
->InsertBefore(MakeUnique<opt::Instruction>(
|
FindInstruction(message_.instruction_to_insert_before(), ir_context);
|
||||||
|
opt::Instruction* new_instruction =
|
||||||
|
insert_before->InsertBefore(MakeUnique<opt::Instruction>(
|
||||||
ir_context, SpvOpVectorShuffle, result_type_id, message_.fresh_id(),
|
ir_context, SpvOpVectorShuffle, result_type_id, message_.fresh_id(),
|
||||||
shuffle_operands));
|
shuffle_operands));
|
||||||
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
|
||||||
ir_context->InvalidateAnalysesExceptFor(
|
// Inform the def-use manager about the new instruction and record its basic
|
||||||
opt::IRContext::Analysis::kAnalysisNone);
|
// block.
|
||||||
|
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction);
|
||||||
|
ir_context->set_instr_block(new_instruction,
|
||||||
|
ir_context->get_instr_block(insert_before));
|
||||||
|
|
||||||
AddDataSynonymFacts(ir_context, transformation_context);
|
AddDataSynonymFacts(ir_context, transformation_context);
|
||||||
}
|
}
|
||||||
|
@ -341,7 +341,26 @@ TEST(TransformationPushIdThroughVariableTest, Apply) {
|
|||||||
auto transformation = TransformationPushIdThroughVariable(
|
auto transformation = TransformationPushIdThroughVariable(
|
||||||
value_id, value_synonym_id, variable_id, variable_storage_class,
|
value_id, value_synonym_id, variable_id, variable_storage_class,
|
||||||
initializer_id, instruction_descriptor);
|
initializer_id, instruction_descriptor);
|
||||||
|
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(value_synonym_id));
|
||||||
|
ASSERT_EQ(nullptr, context->get_instr_block(value_synonym_id));
|
||||||
|
ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(variable_id));
|
||||||
|
ASSERT_EQ(nullptr, context->get_instr_block(variable_id));
|
||||||
ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
|
ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
|
||||||
|
ASSERT_EQ(SpvOpLoad,
|
||||||
|
context->get_def_use_mgr()->GetDef(value_synonym_id)->opcode());
|
||||||
|
ASSERT_EQ(36, context->get_instr_block(value_synonym_id)->id());
|
||||||
|
ASSERT_EQ(SpvOpVariable,
|
||||||
|
context->get_def_use_mgr()->GetDef(variable_id)->opcode());
|
||||||
|
ASSERT_EQ(5, context->get_instr_block(variable_id)->id());
|
||||||
|
uint32_t variable_use_count = 0;
|
||||||
|
context->get_def_use_mgr()->ForEachUse(
|
||||||
|
variable_id,
|
||||||
|
[&variable_use_count](opt::Instruction* inst, uint32_t /*unused*/) {
|
||||||
|
ASSERT_TRUE(inst->opcode() == SpvOpLoad ||
|
||||||
|
inst->opcode() == SpvOpStore);
|
||||||
|
variable_use_count++;
|
||||||
|
});
|
||||||
|
ASSERT_EQ(2, variable_use_count);
|
||||||
|
|
||||||
value_id = 21;
|
value_id = 21;
|
||||||
value_synonym_id = 102;
|
value_synonym_id = 102;
|
||||||
|
Loading…
Reference in New Issue
Block a user