blob: 1082caf86b9fa3d8cf03721728e67e465ee3876f [file] [log] [blame]
Andrea Falcone1c4977f2020-07-23 10:58:25 -04001// 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_copy_object.h"
16
17#include "source/fuzz/fuzzer_util.h"
18#include "source/fuzz/instruction_descriptor.h"
19#include "source/opt/instruction.h"
20#include "source/util/make_unique.h"
21
22namespace spvtools {
23namespace fuzz {
24
25TransformationCopyObject::TransformationCopyObject(
26 const protobufs::TransformationCopyObject& message)
27 : message_(message) {}
28
29TransformationCopyObject::TransformationCopyObject(
30 uint32_t object,
31 const protobufs::InstructionDescriptor& instruction_to_insert_before,
32 uint32_t fresh_id) {
33 message_.set_object(object);
34 *message_.mutable_instruction_to_insert_before() =
35 instruction_to_insert_before;
36 message_.set_fresh_id(fresh_id);
37}
38
39bool TransformationCopyObject::IsApplicable(
40 opt::IRContext* context, const FactManager& /*fact_manager*/) const {
41 if (!fuzzerutil::IsFreshId(context, message_.fresh_id())) {
42 // We require the id for the object copy to be unused.
43 return false;
44 }
45 // The id of the object to be copied must exist
46 auto object_inst = context->get_def_use_mgr()->GetDef(message_.object());
47 if (!object_inst) {
48 return false;
49 }
50 if (!fuzzerutil::CanMakeSynonymOf(context, object_inst)) {
51 return false;
52 }
53
54 auto insert_before =
55 FindInstruction(message_.instruction_to_insert_before(), context);
56 if (!insert_before) {
57 // The instruction before which the copy should be inserted was not found.
58 return false;
59 }
60
61 if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCopyObject,
62 insert_before)) {
63 return false;
64 }
65
66 // |message_object| must be available at the point where we want to add the
67 // copy. It is available if it is at global scope (in which case it has no
68 // block), or if it dominates the point of insertion but is different from the
69 // point of insertion.
70 //
71 // The reason why the object needs to be different from the insertion point is
72 // that the copy will be added *before* this point, and we do not want to
73 // insert it before the object's defining instruction.
74 return !context->get_instr_block(object_inst) ||
75 (object_inst != &*insert_before &&
76 context
77 ->GetDominatorAnalysis(
78 context->get_instr_block(insert_before)->GetParent())
79 ->Dominates(object_inst, &*insert_before));
80}
81
82void TransformationCopyObject::Apply(opt::IRContext* context,
83 FactManager* fact_manager) const {
84 auto object_inst = context->get_def_use_mgr()->GetDef(message_.object());
85 assert(object_inst && "The object to be copied must exist.");
86 auto insert_before_inst =
87 FindInstruction(message_.instruction_to_insert_before(), context);
88 auto destination_block = context->get_instr_block(insert_before_inst);
89 assert(destination_block && "The base instruction must be in a block.");
90 auto insert_before = fuzzerutil::GetIteratorForInstruction(
91 destination_block, insert_before_inst);
92 assert(insert_before != destination_block->end() &&
93 "There must be an instruction before which the copy can be inserted.");
94
95 opt::Instruction::OperandList operands = {
96 {SPV_OPERAND_TYPE_ID, {message_.object()}}};
97 insert_before->InsertBefore(MakeUnique<opt::Instruction>(
98 context, SpvOp::SpvOpCopyObject, object_inst->type_id(),
99 message_.fresh_id(), operands));
100
101 fuzzerutil::UpdateModuleIdBound(context, message_.fresh_id());
102 context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
103
104 protobufs::Fact fact;
105 fact.mutable_id_synonym_fact()->set_id(message_.object());
106 fact.mutable_id_synonym_fact()->mutable_data_descriptor()->set_object(
107 message_.fresh_id());
108 fact_manager->AddFact(fact, context);
109}
110
111protobufs::Transformation TransformationCopyObject::ToMessage() const {
112 protobufs::Transformation result;
113 *result.mutable_copy_object() = message_;
114 return result;
115}
116
117} // namespace fuzz
118} // namespace spvtools