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