| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- // 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/transformation_vector_shuffle.h"
- #include "source/fuzz/fuzzer_util.h"
- #include "source/fuzz/instruction_descriptor.h"
- namespace spvtools {
- namespace fuzz {
- TransformationVectorShuffle::TransformationVectorShuffle(
- protobufs::TransformationVectorShuffle message)
- : message_(std::move(message)) {}
- TransformationVectorShuffle::TransformationVectorShuffle(
- const protobufs::InstructionDescriptor& instruction_to_insert_before,
- uint32_t fresh_id, uint32_t vector1, uint32_t vector2,
- const std::vector<uint32_t>& component) {
- *message_.mutable_instruction_to_insert_before() =
- instruction_to_insert_before;
- message_.set_fresh_id(fresh_id);
- message_.set_vector1(vector1);
- message_.set_vector2(vector2);
- for (auto a_component : component) {
- message_.add_component(a_component);
- }
- }
- bool TransformationVectorShuffle::IsApplicable(
- opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
- // The fresh id must not already be in use.
- if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
- return false;
- }
- // The instruction before which the shuffle will be inserted must exist.
- auto instruction_to_insert_before =
- FindInstruction(message_.instruction_to_insert_before(), ir_context);
- if (!instruction_to_insert_before) {
- return false;
- }
- // The first vector must be an instruction with a type id
- auto vector1_instruction =
- ir_context->get_def_use_mgr()->GetDef(message_.vector1());
- if (!vector1_instruction || !vector1_instruction->type_id()) {
- return false;
- }
- // The second vector must be an instruction with a type id
- auto vector2_instruction =
- ir_context->get_def_use_mgr()->GetDef(message_.vector2());
- if (!vector2_instruction || !vector2_instruction->type_id()) {
- return false;
- }
- auto vector1_type =
- ir_context->get_type_mgr()->GetType(vector1_instruction->type_id());
- // The first vector instruction's type must actually be a vector type.
- if (!vector1_type->AsVector()) {
- return false;
- }
- auto vector2_type =
- ir_context->get_type_mgr()->GetType(vector2_instruction->type_id());
- // The second vector instruction's type must actually be a vector type.
- if (!vector2_type->AsVector()) {
- return false;
- }
- // The element types of the vectors must be the same.
- if (vector1_type->AsVector()->element_type() !=
- vector2_type->AsVector()->element_type()) {
- return false;
- }
- uint32_t combined_size = vector1_type->AsVector()->element_count() +
- vector2_type->AsVector()->element_count();
- for (auto a_compoment : message_.component()) {
- // 0xFFFFFFFF is used to represent an undefined component. Unless
- // undefined, a component must be less than the combined size of the
- // vectors.
- if (a_compoment != 0xFFFFFFFF && a_compoment >= combined_size) {
- return false;
- }
- }
- // The module must already declare an appropriate type in which to store the
- // result of the shuffle.
- if (!GetResultTypeId(ir_context, *vector1_type->AsVector()->element_type())) {
- return false;
- }
- // Each of the vectors used in the shuffle must be available at the insertion
- // point.
- for (auto used_instruction : {vector1_instruction, vector2_instruction}) {
- if (auto block = ir_context->get_instr_block(used_instruction)) {
- if (!ir_context->GetDominatorAnalysis(block->GetParent())
- ->Dominates(used_instruction, instruction_to_insert_before)) {
- return false;
- }
- }
- }
- // It must be legitimate to insert an OpVectorShuffle before the identified
- // instruction.
- return fuzzerutil::CanInsertOpcodeBeforeInstruction(
- spv::Op::OpVectorShuffle, instruction_to_insert_before);
- }
- void TransformationVectorShuffle::Apply(
- opt::IRContext* ir_context,
- TransformationContext* transformation_context) const {
- // Make input operands for a shuffle instruction - these comprise the two
- // vectors being shuffled, followed by the integer literal components.
- opt::Instruction::OperandList shuffle_operands = {
- {SPV_OPERAND_TYPE_ID, {message_.vector1()}},
- {SPV_OPERAND_TYPE_ID, {message_.vector2()}}};
- for (auto a_component : message_.component()) {
- shuffle_operands.push_back(
- {SPV_OPERAND_TYPE_LITERAL_INTEGER, {a_component}});
- }
- uint32_t result_type_id = GetResultTypeId(
- ir_context,
- *GetVectorType(ir_context, message_.vector1())->element_type());
- // Add a shuffle instruction right before the instruction identified by
- // |message_.instruction_to_insert_before|.
- auto insert_before =
- FindInstruction(message_.instruction_to_insert_before(), ir_context);
- opt::Instruction* new_instruction =
- insert_before->InsertBefore(MakeUnique<opt::Instruction>(
- ir_context, spv::Op::OpVectorShuffle, result_type_id,
- message_.fresh_id(), shuffle_operands));
- fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
- // Inform the def-use manager about the new instruction and record its basic
- // 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);
- }
- protobufs::Transformation TransformationVectorShuffle::ToMessage() const {
- protobufs::Transformation result;
- *result.mutable_vector_shuffle() = message_;
- return result;
- }
- uint32_t TransformationVectorShuffle::GetResultTypeId(
- opt::IRContext* ir_context, const opt::analysis::Type& element_type) const {
- opt::analysis::Vector result_type(
- &element_type, static_cast<uint32_t>(message_.component_size()));
- return ir_context->get_type_mgr()->GetId(&result_type);
- }
- opt::analysis::Vector* TransformationVectorShuffle::GetVectorType(
- opt::IRContext* ir_context, uint32_t id_of_vector) {
- return ir_context->get_type_mgr()
- ->GetType(ir_context->get_def_use_mgr()->GetDef(id_of_vector)->type_id())
- ->AsVector();
- }
- std::unordered_set<uint32_t> TransformationVectorShuffle::GetFreshIds() const {
- return {message_.fresh_id()};
- }
- void TransformationVectorShuffle::AddDataSynonymFacts(
- opt::IRContext* ir_context,
- TransformationContext* transformation_context) const {
- // If the new instruction is irrelevant (because it is in a dead block), it
- // cannot participate in any DataSynonym fact.
- if (transformation_context->GetFactManager()->IdIsIrrelevant(
- message_.fresh_id())) {
- return;
- }
- // Add synonym facts relating the defined elements of the shuffle result to
- // the vector components that they come from.
- for (uint32_t component_index = 0;
- component_index < static_cast<uint32_t>(message_.component_size());
- component_index++) {
- uint32_t component = message_.component(component_index);
- if (component == 0xFFFFFFFF) {
- // This component is undefined, we do not introduce a synonym.
- continue;
- }
- // This describes the element of the result vector associated with
- // |component_index|.
- protobufs::DataDescriptor descriptor_for_result_component =
- MakeDataDescriptor(message_.fresh_id(), {component_index});
- protobufs::DataDescriptor descriptor_for_source_component;
- // Get a data descriptor for the component of the input vector to which
- // |component| refers.
- if (component <
- GetVectorType(ir_context, message_.vector1())->element_count()) {
- // Check that the first vector can participate in data synonym facts.
- if (!fuzzerutil::CanMakeSynonymOf(
- ir_context, *transformation_context,
- *ir_context->get_def_use_mgr()->GetDef(message_.vector1()))) {
- continue;
- }
- descriptor_for_source_component =
- MakeDataDescriptor(message_.vector1(), {component});
- } else {
- // Check that the second vector can participate in data synonym facts.
- if (!fuzzerutil::CanMakeSynonymOf(
- ir_context, *transformation_context,
- *ir_context->get_def_use_mgr()->GetDef(message_.vector2()))) {
- continue;
- }
- auto index_into_vector_2 =
- component -
- GetVectorType(ir_context, message_.vector1())->element_count();
- assert(
- index_into_vector_2 <
- GetVectorType(ir_context, message_.vector2())->element_count() &&
- "Vector shuffle index is out of bounds.");
- descriptor_for_source_component =
- MakeDataDescriptor(message_.vector2(), {index_into_vector_2});
- }
- // Add a fact relating this input vector component with the associated
- // result component.
- transformation_context->GetFactManager()->AddFactDataSynonym(
- descriptor_for_result_component, descriptor_for_source_component);
- }
- }
- } // namespace fuzz
- } // namespace spvtools
|