1 // Copyright (c) 2020 Stefano Milizia
2 // Copyright (c) 2020 Google LLC
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 #include "source/fuzz/fuzzer_pass_interchange_zero_like_constants.h"
17
18 #include "source/fuzz/fuzzer_util.h"
19 #include "source/fuzz/id_use_descriptor.h"
20 #include "source/fuzz/transformation_record_synonymous_constants.h"
21 #include "source/fuzz/transformation_replace_id_with_synonym.h"
22
23 namespace spvtools {
24 namespace fuzz {
FuzzerPassInterchangeZeroLikeConstants(opt::IRContext * ir_context,TransformationContext * transformation_context,FuzzerContext * fuzzer_context,protobufs::TransformationSequence * transformations)25 FuzzerPassInterchangeZeroLikeConstants::FuzzerPassInterchangeZeroLikeConstants(
26 opt::IRContext* ir_context, TransformationContext* transformation_context,
27 FuzzerContext* fuzzer_context,
28 protobufs::TransformationSequence* transformations)
29 : FuzzerPass(ir_context, transformation_context, fuzzer_context,
30 transformations) {}
31
FindOrCreateToggledConstant(opt::Instruction * declaration)32 uint32_t FuzzerPassInterchangeZeroLikeConstants::FindOrCreateToggledConstant(
33 opt::Instruction* declaration) {
34 // |declaration| must not be a specialization constant because we do not know
35 // the value of specialization constants.
36 if (opt::IsSpecConstantInst(declaration->opcode())) {
37 return 0;
38 }
39
40 auto constant = GetIRContext()->get_constant_mgr()->FindDeclaredConstant(
41 declaration->result_id());
42
43 // This pass only toggles zero-like constants
44 if (!constant->IsZero()) {
45 return 0;
46 }
47
48 if (constant->AsScalarConstant()) {
49 return FindOrCreateNullConstant(declaration->type_id());
50 } else if (constant->AsNullConstant()) {
51 // Add declaration of equivalent scalar constant
52 auto kind = constant->type()->kind();
53 if (kind == opt::analysis::Type::kBool ||
54 kind == opt::analysis::Type::kInteger ||
55 kind == opt::analysis::Type::kFloat) {
56 return FindOrCreateZeroConstant(declaration->type_id(), false);
57 }
58 }
59
60 return 0;
61 }
62
Apply()63 void FuzzerPassInterchangeZeroLikeConstants::Apply() {
64 // Make vector keeping track of all the uses we want to replace.
65 // This is a vector of pairs, where the first element is an id use descriptor
66 // identifying the use of a constant id and the second is the id that should
67 // be used to replace it.
68 std::vector<std::pair<protobufs::IdUseDescriptor, uint32_t>> uses_to_replace;
69
70 for (auto constant : GetIRContext()->GetConstants()) {
71 uint32_t constant_id = constant->result_id();
72 if (GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
73 constant_id)) {
74 continue;
75 }
76
77 uint32_t toggled_id = FindOrCreateToggledConstant(constant);
78 if (!toggled_id) {
79 // Not a zero-like constant
80 continue;
81 }
82
83 assert(!GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
84 toggled_id) &&
85 "FindOrCreateToggledConstant can't produce an irrelevant id");
86
87 // Record synonymous constants
88 ApplyTransformation(
89 TransformationRecordSynonymousConstants(constant_id, toggled_id));
90
91 // Find all the uses of the constant and, for each, probabilistically
92 // decide whether to replace it.
93 GetIRContext()->get_def_use_mgr()->ForEachUse(
94 constant_id,
95 [this, toggled_id, &uses_to_replace](opt::Instruction* use_inst,
96 uint32_t use_index) -> void {
97 if (GetFuzzerContext()->ChoosePercentage(
98 GetFuzzerContext()
99 ->GetChanceOfInterchangingZeroLikeConstants())) {
100 MaybeAddUseToReplace(use_inst, use_index, toggled_id,
101 &uses_to_replace);
102 }
103 });
104 }
105
106 // Replace the ids if it is allowed.
107 for (auto use_to_replace : uses_to_replace) {
108 MaybeApplyTransformation(TransformationReplaceIdWithSynonym(
109 use_to_replace.first, use_to_replace.second));
110 }
111 }
112 } // namespace fuzz
113 } // namespace spvtools
114