1 // Copyright (c) 2019 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/fact_manager/irrelevant_value_facts.h"
16 
17 #include "source/fuzz/data_descriptor.h"
18 #include "source/fuzz/fact_manager/data_synonym_and_id_equation_facts.h"
19 #include "source/fuzz/fact_manager/dead_block_facts.h"
20 #include "source/fuzz/fuzzer_util.h"
21 #include "source/opt/ir_context.h"
22 
23 namespace spvtools {
24 namespace fuzz {
25 namespace fact_manager {
26 
IrrelevantValueFacts(opt::IRContext * ir_context)27 IrrelevantValueFacts::IrrelevantValueFacts(opt::IRContext* ir_context)
28     : ir_context_(ir_context) {}
29 
MaybeAddFact(const protobufs::FactPointeeValueIsIrrelevant & fact,const DataSynonymAndIdEquationFacts & data_synonym_and_id_equation_facts)30 bool IrrelevantValueFacts::MaybeAddFact(
31     const protobufs::FactPointeeValueIsIrrelevant& fact,
32     const DataSynonymAndIdEquationFacts& data_synonym_and_id_equation_facts) {
33   const auto* inst = ir_context_->get_def_use_mgr()->GetDef(fact.pointer_id());
34   if (!inst || !inst->type_id()) {
35     // The id must exist in the module and have type id.
36     return false;
37   }
38 
39   if (!ir_context_->get_type_mgr()->GetType(inst->type_id())->AsPointer()) {
40     // The id must be a pointer.
41     return false;
42   }
43 
44   if (!data_synonym_and_id_equation_facts.GetSynonymsForId(fact.pointer_id())
45            .empty()) {
46     // Irrelevant id cannot participate in DataSynonym facts.
47     return false;
48   }
49 
50   pointers_to_irrelevant_pointees_ids_.insert(fact.pointer_id());
51   return true;
52 }
53 
MaybeAddFact(const protobufs::FactIdIsIrrelevant & fact,const DataSynonymAndIdEquationFacts & data_synonym_and_id_equation_facts)54 bool IrrelevantValueFacts::MaybeAddFact(
55     const protobufs::FactIdIsIrrelevant& fact,
56     const DataSynonymAndIdEquationFacts& data_synonym_and_id_equation_facts) {
57   const auto* inst = ir_context_->get_def_use_mgr()->GetDef(fact.result_id());
58   if (!inst || !inst->type_id()) {
59     // The id must exist in the module and have type id.
60     return false;
61   }
62 
63   if (ir_context_->get_type_mgr()->GetType(inst->type_id())->AsPointer()) {
64     // The id may not be a pointer.
65     return false;
66   }
67 
68   if (!data_synonym_and_id_equation_facts.GetSynonymsForId(fact.result_id())
69            .empty()) {
70     // Irrelevant id cannot participate in DataSynonym facts.
71     return false;
72   }
73 
74   irrelevant_ids_.insert(fact.result_id());
75   return true;
76 }
77 
PointeeValueIsIrrelevant(uint32_t pointer_id) const78 bool IrrelevantValueFacts::PointeeValueIsIrrelevant(uint32_t pointer_id) const {
79   return pointers_to_irrelevant_pointees_ids_.count(pointer_id) != 0;
80 }
81 
IdIsIrrelevant(uint32_t result_id,const DeadBlockFacts & dead_block_facts) const82 bool IrrelevantValueFacts::IdIsIrrelevant(
83     uint32_t result_id, const DeadBlockFacts& dead_block_facts) const {
84   // The id is irrelevant if it has been declared irrelevant.
85   if (irrelevant_ids_.count(result_id)) {
86     return true;
87   }
88 
89   // The id must have a non-pointer type to be irrelevant.
90   auto def = ir_context_->get_def_use_mgr()->GetDef(result_id);
91   if (!def) {
92     return false;
93   }
94   auto type = ir_context_->get_type_mgr()->GetType(def->type_id());
95   if (!type || type->AsPointer()) {
96     return false;
97   }
98 
99   // The id is irrelevant if it is in a dead block.
100   return ir_context_->get_instr_block(result_id) &&
101          dead_block_facts.BlockIsDead(
102              ir_context_->get_instr_block(result_id)->id());
103 }
104 
GetIrrelevantIds(const DeadBlockFacts & dead_block_facts) const105 std::unordered_set<uint32_t> IrrelevantValueFacts::GetIrrelevantIds(
106     const DeadBlockFacts& dead_block_facts) const {
107   // Get all the ids that have been declared irrelevant.
108   auto irrelevant_ids = irrelevant_ids_;
109 
110   // Get all the non-pointer ids declared in dead blocks that have a type.
111   for (uint32_t block_id : dead_block_facts.GetDeadBlocks()) {
112     auto block = fuzzerutil::MaybeFindBlock(ir_context_, block_id);
113     // It is possible and allowed for the block not to exist, e.g. it could have
114     // been merged with another block.
115     if (!block) {
116       continue;
117     }
118     block->ForEachInst([this, &irrelevant_ids](opt::Instruction* inst) {
119       // The instruction must have a result id and a type, and it must not be a
120       // pointer.
121       if (inst->HasResultId() && inst->type_id() &&
122           !ir_context_->get_type_mgr()->GetType(inst->type_id())->AsPointer()) {
123         irrelevant_ids.emplace(inst->result_id());
124       }
125     });
126   }
127 
128   return irrelevant_ids;
129 }
130 
131 }  // namespace fact_manager
132 }  // namespace fuzz
133 }  // namespace spvtools
134