#include "source/fuzz/transformation_add_local_variable.h"
#include "source/fuzz/fuzzer_util.h"
namespace spvtools {
namespace fuzz {
TransformationAddLocalVariable::TransformationAddLocalVariable(
spvtools::fuzz::protobufs::TransformationAddLocalVariable message)
: message_(std::move(message)) {}
TransformationAddLocalVariable::TransformationAddLocalVariable(
uint32_t fresh_id, uint32_t type_id, uint32_t function_id,
uint32_t initializer_id, bool value_is_irrelevant) {
message_.set_fresh_id(fresh_id);
message_.set_type_id(type_id);
message_.set_function_id(function_id);
message_.set_initializer_id(initializer_id);
message_.set_value_is_irrelevant(value_is_irrelevant);
}
bool TransformationAddLocalVariable::IsApplicable(
opt::IRContext* ir_context, const TransformationContext& ) const {
if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
return false;
}
auto type_instruction =
ir_context->get_def_use_mgr()->GetDef(message_.type_id());
if (!type_instruction ||
type_instruction->opcode() != spv::Op::OpTypePointer ||
spv::StorageClass(type_instruction->GetSingleWordInOperand(0)) !=
spv::StorageClass::Function) {
return false;
}
auto initializer_instruction =
ir_context->get_def_use_mgr()->GetDef(message_.initializer_id());
if (!initializer_instruction) {
return false;
}
if (!spvOpcodeIsConstant(initializer_instruction->opcode())) {
return false;
}
if (initializer_instruction->type_id() !=
type_instruction->GetSingleWordInOperand(1)) {
return false;
}
return fuzzerutil::FindFunction(ir_context, message_.function_id());
}
void TransformationAddLocalVariable::Apply(
opt::IRContext* ir_context,
TransformationContext* transformation_context) const {
opt::Instruction* new_instruction = fuzzerutil::AddLocalVariable(
ir_context, message_.fresh_id(), message_.type_id(),
message_.function_id(), message_.initializer_id());
ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction);
ir_context->set_instr_block(
new_instruction,
fuzzerutil::FindFunction(ir_context, message_.function_id())
->entry()
.get());
if (message_.value_is_irrelevant()) {
transformation_context->GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
message_.fresh_id());
}
}
protobufs::Transformation TransformationAddLocalVariable::ToMessage() const {
protobufs::Transformation result;
*result.mutable_add_local_variable() = message_;
return result;
}
std::unordered_set<uint32_t> TransformationAddLocalVariable::GetFreshIds()
const {
return {message_.fresh_id()};
}
}
}