• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2020 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_equation_instruction.h"
16 
17 #include "source/fuzz/fuzzer_util.h"
18 #include "source/fuzz/instruction_descriptor.h"
19 
20 namespace spvtools {
21 namespace fuzz {
22 
TransformationEquationInstruction(const spvtools::fuzz::protobufs::TransformationEquationInstruction & message)23 TransformationEquationInstruction::TransformationEquationInstruction(
24     const spvtools::fuzz::protobufs::TransformationEquationInstruction& message)
25     : message_(message) {}
26 
TransformationEquationInstruction(uint32_t fresh_id,SpvOp opcode,const std::vector<uint32_t> & in_operand_id,const protobufs::InstructionDescriptor & instruction_to_insert_before)27 TransformationEquationInstruction::TransformationEquationInstruction(
28     uint32_t fresh_id, SpvOp opcode, const std::vector<uint32_t>& in_operand_id,
29     const protobufs::InstructionDescriptor& instruction_to_insert_before) {
30   message_.set_fresh_id(fresh_id);
31   message_.set_opcode(opcode);
32   for (auto id : in_operand_id) {
33     message_.add_in_operand_id(id);
34   }
35   *message_.mutable_instruction_to_insert_before() =
36       instruction_to_insert_before;
37 }
38 
IsApplicable(opt::IRContext * ir_context,const TransformationContext &) const39 bool TransformationEquationInstruction::IsApplicable(
40     opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
41   // The result id must be fresh.
42   if (!fuzzerutil::IsFreshId(ir_context, message_.fresh_id())) {
43     return false;
44   }
45   // The instruction to insert before must exist.
46   auto insert_before =
47       FindInstruction(message_.instruction_to_insert_before(), ir_context);
48   if (!insert_before) {
49     return false;
50   }
51   // The input ids must all exist, not be OpUndef, and be available before this
52   // instruction.
53   for (auto id : message_.in_operand_id()) {
54     auto inst = ir_context->get_def_use_mgr()->GetDef(id);
55     if (!inst) {
56       return false;
57     }
58     if (inst->opcode() == SpvOpUndef) {
59       return false;
60     }
61     if (!fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, insert_before,
62                                                     id)) {
63       return false;
64     }
65   }
66 
67   return MaybeGetResultType(ir_context) != 0;
68 }
69 
Apply(opt::IRContext * ir_context,TransformationContext * transformation_context) const70 void TransformationEquationInstruction::Apply(
71     opt::IRContext* ir_context,
72     TransformationContext* transformation_context) const {
73   fuzzerutil::UpdateModuleIdBound(ir_context, message_.fresh_id());
74 
75   opt::Instruction::OperandList in_operands;
76   std::vector<uint32_t> rhs_id;
77   for (auto id : message_.in_operand_id()) {
78     in_operands.push_back({SPV_OPERAND_TYPE_ID, {id}});
79     rhs_id.push_back(id);
80   }
81 
82   FindInstruction(message_.instruction_to_insert_before(), ir_context)
83       ->InsertBefore(MakeUnique<opt::Instruction>(
84           ir_context, static_cast<SpvOp>(message_.opcode()),
85           MaybeGetResultType(ir_context), message_.fresh_id(), in_operands));
86 
87   ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
88 
89   transformation_context->GetFactManager()->AddFactIdEquation(
90       message_.fresh_id(), static_cast<SpvOp>(message_.opcode()), rhs_id,
91       ir_context);
92 }
93 
ToMessage() const94 protobufs::Transformation TransformationEquationInstruction::ToMessage() const {
95   protobufs::Transformation result;
96   *result.mutable_equation_instruction() = message_;
97   return result;
98 }
99 
MaybeGetResultType(opt::IRContext * ir_context) const100 uint32_t TransformationEquationInstruction::MaybeGetResultType(
101     opt::IRContext* ir_context) const {
102   switch (static_cast<SpvOp>(message_.opcode())) {
103     case SpvOpIAdd:
104     case SpvOpISub: {
105       if (message_.in_operand_id().size() != 2) {
106         return 0;
107       }
108       uint32_t first_operand_width = 0;
109       uint32_t first_operand_type_id = 0;
110       for (uint32_t index = 0; index < 2; index++) {
111         auto operand_inst = ir_context->get_def_use_mgr()->GetDef(
112             message_.in_operand_id(index));
113         if (!operand_inst || !operand_inst->type_id()) {
114           return 0;
115         }
116         auto operand_type =
117             ir_context->get_type_mgr()->GetType(operand_inst->type_id());
118         if (!(operand_type->AsInteger() ||
119               (operand_type->AsVector() &&
120                operand_type->AsVector()->element_type()->AsInteger()))) {
121           return 0;
122         }
123         uint32_t operand_width =
124             operand_type->AsInteger()
125                 ? 1
126                 : operand_type->AsVector()->element_count();
127         if (index == 0) {
128           first_operand_width = operand_width;
129           first_operand_type_id = operand_inst->type_id();
130         } else {
131           assert(first_operand_width != 0 &&
132                  "The first operand should have been processed.");
133           if (operand_width != first_operand_width) {
134             return 0;
135           }
136         }
137       }
138       assert(first_operand_type_id != 0 &&
139              "A type must have been found for the first operand.");
140       return first_operand_type_id;
141     }
142     case SpvOpLogicalNot: {
143       if (message_.in_operand_id().size() != 1) {
144         return 0;
145       }
146       auto operand_inst =
147           ir_context->get_def_use_mgr()->GetDef(message_.in_operand_id(0));
148       if (!operand_inst || !operand_inst->type_id()) {
149         return 0;
150       }
151       auto operand_type =
152           ir_context->get_type_mgr()->GetType(operand_inst->type_id());
153       if (!(operand_type->AsBool() ||
154             (operand_type->AsVector() &&
155              operand_type->AsVector()->element_type()->AsBool()))) {
156         return 0;
157       }
158       return operand_inst->type_id();
159     }
160     case SpvOpSNegate: {
161       if (message_.in_operand_id().size() != 1) {
162         return 0;
163       }
164       auto operand_inst =
165           ir_context->get_def_use_mgr()->GetDef(message_.in_operand_id(0));
166       if (!operand_inst || !operand_inst->type_id()) {
167         return 0;
168       }
169       auto operand_type =
170           ir_context->get_type_mgr()->GetType(operand_inst->type_id());
171       if (!(operand_type->AsInteger() ||
172             (operand_type->AsVector() &&
173              operand_type->AsVector()->element_type()->AsInteger()))) {
174         return 0;
175       }
176       return operand_inst->type_id();
177     }
178 
179     default:
180       assert(false && "Inappropriate opcode for equation instruction.");
181       return 0;
182   }
183 }
184 
185 }  // namespace fuzz
186 }  // namespace spvtools
187