• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "source/fuzz/transformation_composite_extract.h"
16 
17 #include <vector>
18 
19 #include "source/fuzz/data_descriptor.h"
20 #include "source/fuzz/fuzzer_util.h"
21 #include "source/fuzz/instruction_descriptor.h"
22 
23 namespace spvtools {
24 namespace fuzz {
25 
TransformationCompositeExtract(const spvtools::fuzz::protobufs::TransformationCompositeExtract & message)26 TransformationCompositeExtract::TransformationCompositeExtract(
27     const spvtools::fuzz::protobufs::TransformationCompositeExtract& message)
28     : message_(message) {}
29 
TransformationCompositeExtract(const protobufs::InstructionDescriptor & instruction_to_insert_before,uint32_t fresh_id,uint32_t composite_id,std::vector<uint32_t> && index)30 TransformationCompositeExtract::TransformationCompositeExtract(
31     const protobufs::InstructionDescriptor& instruction_to_insert_before,
32     uint32_t fresh_id, uint32_t composite_id, std::vector<uint32_t>&& index) {
33   *message_.mutable_instruction_to_insert_before() =
34       instruction_to_insert_before;
35   message_.set_fresh_id(fresh_id);
36   message_.set_composite_id(composite_id);
37   for (auto an_index : index) {
38     message_.add_index(an_index);
39   }
40 }
41 
IsApplicable(opt::IRContext * context,const spvtools::fuzz::FactManager &) const42 bool TransformationCompositeExtract::IsApplicable(
43     opt::IRContext* context,
44     const spvtools::fuzz::FactManager& /*unused*/) const {
45   if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
46     return false;
47   }
48   auto instruction_to_insert_before =
49       FindInstruction(message_.instruction_to_insert_before(), context);
50   if (!instruction_to_insert_before) {
51     return false;
52   }
53   auto composite_instruction =
54       context->get_def_use_mgr()->GetDef(message_.composite_id());
55   if (!composite_instruction) {
56     return false;
57   }
58   if (auto block = context->get_instr_block(composite_instruction)) {
59     if (composite_instruction == instruction_to_insert_before ||
60         !context->GetDominatorAnalysis(block->GetParent())
61              ->Dominates(composite_instruction, instruction_to_insert_before)) {
62       return false;
63     }
64   }
65   assert(composite_instruction->type_id() &&
66          "An instruction in a block cannot have a result id but no type id.");
67 
68   auto composite_type =
69       context->get_type_mgr()->GetType(composite_instruction->type_id());
70   if (!composite_type) {
71     return false;
72   }
73 
74   if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
75           SpvOpCompositeExtract, instruction_to_insert_before)) {
76     return false;
77   }
78 
79   return fuzzerutil::WalkCompositeTypeIndices(
80              context, composite_instruction->type_id(), message_.index()) != 0;
81 }
82 
Apply(opt::IRContext * context,spvtools::fuzz::FactManager * fact_manager) const83 void TransformationCompositeExtract::Apply(
84     opt::IRContext* context, spvtools::fuzz::FactManager* fact_manager) const {
85   opt::Instruction::OperandList extract_operands;
86   extract_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.composite_id()}});
87   for (auto an_index : message_.index()) {
88     extract_operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {an_index}});
89   }
90   auto composite_instruction =
91       context->get_def_use_mgr()->GetDef(message_.composite_id());
92   auto extracted_type = fuzzerutil::WalkCompositeTypeIndices(
93       context, composite_instruction->type_id(), message_.index());
94 
95   FindInstruction(message_.instruction_to_insert_before(), context)
96       ->InsertBefore(MakeUnique<opt::Instruction>(
97           context, SpvOpCompositeExtract, extracted_type, message_.fresh_id(),
98           extract_operands));
99 
100   fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
101 
102   context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
103 
104   // Add the fact that the id storing the extracted element is synonymous with
105   // the index into the structure.
106   std::vector<uint32_t> indices;
107   for (auto an_index : message_.index()) {
108     indices.push_back(an_index);
109   }
110   protobufs::DataDescriptor data_descriptor_for_extracted_element =
111       MakeDataDescriptor(message_.composite_id(), std::move(indices));
112   protobufs::DataDescriptor data_descriptor_for_result_id =
113       MakeDataDescriptor(message_.fresh_id(), {});
114   fact_manager->AddFactDataSynonym(data_descriptor_for_extracted_element,
115                                    data_descriptor_for_result_id, context);
116 }
117 
ToMessage() const118 protobufs::Transformation TransformationCompositeExtract::ToMessage() const {
119   protobufs::Transformation result;
120   *result.mutable_composite_extract() = message_;
121   return result;
122 }
123 
124 }  // namespace fuzz
125 }  // namespace spvtools
126