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,bool ignore_inapplicable_transformations)25 FuzzerPassInterchangeZeroLikeConstants::FuzzerPassInterchangeZeroLikeConstants(
26 opt::IRContext* ir_context, TransformationContext* transformation_context,
27 FuzzerContext* fuzzer_context,
28 protobufs::TransformationSequence* transformations,
29 bool ignore_inapplicable_transformations)
30 : FuzzerPass(ir_context, transformation_context, fuzzer_context,
31 transformations, ignore_inapplicable_transformations) {}
32
FindOrCreateToggledConstant(opt::Instruction * declaration)33 uint32_t FuzzerPassInterchangeZeroLikeConstants::FindOrCreateToggledConstant(
34 opt::Instruction* declaration) {
35 // |declaration| must not be a specialization constant because we do not know
36 // the value of specialization constants.
37 if (opt::IsSpecConstantInst(declaration->opcode())) {
38 return 0;
39 }
40
41 auto constant = GetIRContext()->get_constant_mgr()->FindDeclaredConstant(
42 declaration->result_id());
43
44 // This pass only toggles zero-like constants
45 if (!constant->IsZero()) {
46 return 0;
47 }
48
49 if (constant->AsScalarConstant()) {
50 return FindOrCreateNullConstant(declaration->type_id());
51 } else if (constant->AsNullConstant()) {
52 // Add declaration of equivalent scalar constant
53 auto kind = constant->type()->kind();
54 if (kind == opt::analysis::Type::kBool ||
55 kind == opt::analysis::Type::kInteger ||
56 kind == opt::analysis::Type::kFloat) {
57 return FindOrCreateZeroConstant(declaration->type_id(), false);
58 }
59 }
60
61 return 0;
62 }
63
Apply()64 void FuzzerPassInterchangeZeroLikeConstants::Apply() {
65 // Make vector keeping track of all the uses we want to replace.
66 // This is a vector of pairs, where the first element is an id use descriptor
67 // identifying the use of a constant id and the second is the id that should
68 // be used to replace it.
69 std::vector<std::pair<protobufs::IdUseDescriptor, uint32_t>> uses_to_replace;
70
71 for (auto constant : GetIRContext()->GetConstants()) {
72 uint32_t constant_id = constant->result_id();
73 if (GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
74 constant_id)) {
75 continue;
76 }
77
78 uint32_t toggled_id = FindOrCreateToggledConstant(constant);
79 if (!toggled_id) {
80 // Not a zero-like constant
81 continue;
82 }
83
84 assert(!GetTransformationContext()->GetFactManager()->IdIsIrrelevant(
85 toggled_id) &&
86 "FindOrCreateToggledConstant can't produce an irrelevant id");
87
88 // Record synonymous constants
89 ApplyTransformation(
90 TransformationRecordSynonymousConstants(constant_id, toggled_id));
91
92 // Find all the uses of the constant and, for each, probabilistically
93 // decide whether to replace it.
94 GetIRContext()->get_def_use_mgr()->ForEachUse(
95 constant_id,
96 [this, toggled_id, &uses_to_replace](opt::Instruction* use_inst,
97 uint32_t use_index) -> void {
98 if (GetFuzzerContext()->ChoosePercentage(
99 GetFuzzerContext()
100 ->GetChanceOfInterchangingZeroLikeConstants())) {
101 MaybeAddUseToReplace(use_inst, use_index, toggled_id,
102 &uses_to_replace);
103 }
104 });
105 }
106
107 // Replace the ids if it is allowed.
108 for (auto use_to_replace : uses_to_replace) {
109 MaybeApplyTransformation(TransformationReplaceIdWithSynonym(
110 use_to_replace.first, use_to_replace.second));
111 }
112 }
113 } // namespace fuzz
114 } // namespace spvtools
115