• 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(protobufs::TransformationCompositeExtract message)26 TransformationCompositeExtract::TransformationCompositeExtract(
27     protobufs::TransformationCompositeExtract message)
28     : message_(std::move(message)) {}
29 
TransformationCompositeExtract(const protobufs::InstructionDescriptor & instruction_to_insert_before,uint32_t fresh_id,uint32_t composite_id,const 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,
33     const std::vector<uint32_t>& index) {
34   *message_.mutable_instruction_to_insert_before() =
35       instruction_to_insert_before;
36   message_.set_fresh_id(fresh_id);
37   message_.set_composite_id(composite_id);
38   for (auto an_index : index) {
39     message_.add_index(an_index);
40   }
41 }
42 
IsApplicable(opt::IRContext * ir_context,const TransformationContext &) const43 bool TransformationCompositeExtract::IsApplicable(
44     opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
45   if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
46     return false;
47   }
48   auto instruction_to_insert_before =
49       FindInstruction(message_.instruction_to_insert_before(), ir_context);
50   if (!instruction_to_insert_before) {
51     return false;
52   }
53   auto composite_instruction =
54       ir_context->get_def_use_mgr()->GetDef(message_.composite_id());
55   if (!composite_instruction) {
56     return false;
57   }
58   if (!fuzzerutil::IdIsAvailableBeforeInstruction(
59           ir_context, instruction_to_insert_before, message_.composite_id())) {
60     return false;
61   }
62 
63   auto composite_type =
64       ir_context->get_type_mgr()->GetType(composite_instruction->type_id());
65   if (!fuzzerutil::IsCompositeType(composite_type)) {
66     return false;
67   }
68 
69   if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
70           SpvOpCompositeExtract, instruction_to_insert_before)) {
71     return false;
72   }
73 
74   return fuzzerutil::WalkCompositeTypeIndices(ir_context,
75                                               composite_instruction->type_id(),
76                                               message_.index()) != 0;
77 }
78 
Apply(opt::IRContext * ir_context,TransformationContext * transformation_context) const79 void TransformationCompositeExtract::Apply(
80     opt::IRContext* ir_context,
81     TransformationContext* transformation_context) const {
82   opt::Instruction::OperandList extract_operands;
83   extract_operands.push_back({SPV_OPERAND_TYPE_ID, {message_.composite_id()}});
84   for (auto an_index : message_.index()) {
85     extract_operands.push_back({SPV_OPERAND_TYPE_LITERAL_INTEGER, {an_index}});
86   }
87   auto composite_instruction =
88       ir_context->get_def_use_mgr()->GetDef(message_.composite_id());
89   auto extracted_type = fuzzerutil::WalkCompositeTypeIndices(
90       ir_context, composite_instruction->type_id(), message_.index());
91 
92   auto insert_before =
93       FindInstruction(message_.instruction_to_insert_before(), ir_context);
94   opt::Instruction* new_instruction =
95       insert_before->InsertBefore(MakeUnique<opt::Instruction>(
96           ir_context, SpvOpCompositeExtract, extracted_type,
97           message_.fresh_id(), extract_operands));
98   ir_context->get_def_use_mgr()->AnalyzeInstDefUse(new_instruction);
99   ir_context->set_instr_block(new_instruction,
100                               ir_context->get_instr_block(insert_before));
101 
102   fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
103 
104   // No analyses need to be invalidated since the transformation is local to a
105   // block and the def-use and instruction-to-block mappings have been updated.
106 
107   AddDataSynonymFacts(ir_context, transformation_context);
108 }
109 
ToMessage() const110 protobufs::Transformation TransformationCompositeExtract::ToMessage() const {
111   protobufs::Transformation result;
112   *result.mutable_composite_extract() = message_;
113   return result;
114 }
115 
GetFreshIds() const116 std::unordered_set<uint32_t> TransformationCompositeExtract::GetFreshIds()
117     const {
118   return {message_.fresh_id()};
119 }
120 
AddDataSynonymFacts(opt::IRContext * ir_context,TransformationContext * transformation_context) const121 void TransformationCompositeExtract::AddDataSynonymFacts(
122     opt::IRContext* ir_context,
123     TransformationContext* transformation_context) const {
124   // Don't add synonyms if the composite being extracted from is not suitable,
125   // or if the result id into which we are extracting is irrelevant.
126   if (!fuzzerutil::CanMakeSynonymOf(
127           ir_context, *transformation_context,
128           ir_context->get_def_use_mgr()->GetDef(message_.composite_id())) ||
129       transformation_context->GetFactManager()->IdIsIrrelevant(
130           message_.fresh_id())) {
131     return;
132   }
133 
134   // Add the fact that the id storing the extracted element is synonymous with
135   // the index into the structure.
136   std::vector<uint32_t> indices(message_.index().begin(),
137                                 message_.index().end());
138   auto data_descriptor_for_extracted_element =
139       MakeDataDescriptor(message_.composite_id(), indices);
140   auto data_descriptor_for_result_id =
141       MakeDataDescriptor(message_.fresh_id(), {});
142   transformation_context->GetFactManager()->AddFactDataSynonym(
143       data_descriptor_for_extracted_element, data_descriptor_for_result_id);
144 }
145 
146 }  // namespace fuzz
147 }  // namespace spvtools
148