SPIRV-Tools/source/fuzz/id_use_descriptor.cpp
Alastair Donaldson a8ae579f7a
Add transformation to replace a boolean constant with a numeric comparison (#2659)
The transformation can, for example, replace "true" with "12.0 > 6.0",
if constants for those floating-point values are available.

This introduces a new 'id use descriptor' structure, which provides a
way to describe a particular use of an id, and which will be heavily
used in future transformations.  Describing an id use is trivial if
the use occurs in an instruction that itself generates an id, but is
less straightforward if the id of interest is used by an instruction
such as OpStore that does not have a result id.  The 'id use
descriptor' structure caters for such cases.
2019-06-06 22:22:35 +01:00

83 lines
3.0 KiB
C++

// Copyright (c) 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "source/fuzz/id_use_descriptor.h"
namespace spvtools {
namespace fuzz {
opt::Instruction* transformation::FindInstruction(
const protobufs::IdUseDescriptor& descriptor,
spvtools::opt::IRContext* context) {
for (auto& function : *context->module()) {
for (auto& block : function) {
bool found_base = block.id() == descriptor.base_instruction_result_id();
uint32_t num_ignored = 0;
for (auto& instruction : block) {
if (instruction.HasResultId() &&
instruction.result_id() ==
descriptor.base_instruction_result_id()) {
assert(!found_base &&
"It should not be possible to find the base instruction "
"multiple times.");
found_base = true;
assert(num_ignored == 0 &&
"The skipped instruction count should only be incremented "
"after the instruction base has been found.");
}
if (found_base &&
instruction.opcode() == descriptor.target_instruction_opcode()) {
if (num_ignored == descriptor.num_opcodes_to_ignore()) {
if (descriptor.in_operand_index() >= instruction.NumInOperands()) {
return nullptr;
}
auto in_operand =
instruction.GetInOperand(descriptor.in_operand_index());
if (in_operand.type != SPV_OPERAND_TYPE_ID) {
return nullptr;
}
if (in_operand.words[0] != descriptor.id_of_interest()) {
return nullptr;
}
return &instruction;
}
num_ignored++;
}
}
if (found_base) {
// We found the base instruction, but did not find the target
// instruction in the same block.
return nullptr;
}
}
}
return nullptr;
}
protobufs::IdUseDescriptor transformation::MakeIdUseDescriptor(
uint32_t id_of_interest, SpvOp target_instruction_opcode,
uint32_t in_operand_index, uint32_t base_instruction_result_id,
uint32_t num_opcodes_to_ignore) {
protobufs::IdUseDescriptor result;
result.set_id_of_interest(id_of_interest);
result.set_target_instruction_opcode(target_instruction_opcode);
result.set_in_operand_index(in_operand_index);
result.set_base_instruction_result_id(base_instruction_result_id);
result.set_num_opcodes_to_ignore(num_opcodes_to_ignore);
return result;
}
} // namespace fuzz
} // namespace spvtools