1 // Copyright (c) 2020 Vasyl Teliman
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_permute_phi_operands.h"
16
17 #include <vector>
18
19 #include "source/fuzz/fuzzer_util.h"
20
21 namespace spvtools {
22 namespace fuzz {
23
TransformationPermutePhiOperands(protobufs::TransformationPermutePhiOperands message)24 TransformationPermutePhiOperands::TransformationPermutePhiOperands(
25 protobufs::TransformationPermutePhiOperands message)
26 : message_(std::move(message)) {}
27
TransformationPermutePhiOperands(uint32_t result_id,const std::vector<uint32_t> & permutation)28 TransformationPermutePhiOperands::TransformationPermutePhiOperands(
29 uint32_t result_id, const std::vector<uint32_t>& permutation) {
30 message_.set_result_id(result_id);
31
32 for (auto index : permutation) {
33 message_.add_permutation(index);
34 }
35 }
36
IsApplicable(opt::IRContext * ir_context,const TransformationContext &) const37 bool TransformationPermutePhiOperands::IsApplicable(
38 opt::IRContext* ir_context, const TransformationContext& /*unused*/) const {
39 // Check that |message_.result_id| is valid.
40 const auto* inst =
41 ir_context->get_def_use_mgr()->GetDef(message_.result_id());
42 if (!inst || inst->opcode() != SpvOpPhi) {
43 return false;
44 }
45
46 // Check that |message_.permutation| has expected size.
47 auto expected_permutation_size = inst->NumInOperands() / 2;
48 if (static_cast<uint32_t>(message_.permutation().size()) !=
49 expected_permutation_size) {
50 return false;
51 }
52
53 // Check that |message_.permutation| has elements in range
54 // [0, expected_permutation_size - 1].
55 std::vector<uint32_t> permutation(message_.permutation().begin(),
56 message_.permutation().end());
57 assert(!fuzzerutil::HasDuplicates(permutation) &&
58 "Permutation has duplicates");
59
60 // We must check whether the permutation is empty first because in that case
61 // |expected_permutation_size - 1| will produce
62 // |std::numeric_limits<uint32_t>::max()| since it's an unsigned integer.
63 return permutation.empty() ||
64 fuzzerutil::IsPermutationOfRange(permutation, 0,
65 expected_permutation_size - 1);
66 }
67
Apply(opt::IRContext * ir_context,TransformationContext *) const68 void TransformationPermutePhiOperands::Apply(
69 opt::IRContext* ir_context, TransformationContext* /*unused*/) const {
70 auto* inst = ir_context->get_def_use_mgr()->GetDef(message_.result_id());
71 assert(inst);
72
73 opt::Instruction::OperandList permuted_operands;
74 permuted_operands.reserve(inst->NumInOperands());
75
76 for (auto index : message_.permutation()) {
77 permuted_operands.push_back(std::move(inst->GetInOperand(2 * index)));
78 permuted_operands.push_back(std::move(inst->GetInOperand(2 * index + 1)));
79 }
80
81 inst->SetInOperands(std::move(permuted_operands));
82
83 // Update the def-use manager.
84 ir_context->UpdateDefUse(inst);
85 }
86
ToMessage() const87 protobufs::Transformation TransformationPermutePhiOperands::ToMessage() const {
88 protobufs::Transformation result;
89 *result.mutable_permute_phi_operands() = message_;
90 return result;
91 }
92
GetFreshIds() const93 std::unordered_set<uint32_t> TransformationPermutePhiOperands::GetFreshIds()
94 const {
95 return std::unordered_set<uint32_t>();
96 }
97
98 } // namespace fuzz
99 } // namespace spvtools
100