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