• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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