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 "fact_manager.h"
16 
17 #include <sstream>
18 #include <unordered_map>
19 
20 #include "source/fuzz/uniform_buffer_element_descriptor.h"
21 #include "source/opt/ir_context.h"
22 
23 namespace spvtools {
24 namespace fuzz {
25 namespace {
26 
ToString(const protobufs::FactConstantUniform & fact)27 std::string ToString(const protobufs::FactConstantUniform& fact) {
28   std::stringstream stream;
29   stream << "(" << fact.uniform_buffer_element_descriptor().descriptor_set()
30          << ", " << fact.uniform_buffer_element_descriptor().binding() << ")[";
31 
32   bool first = true;
33   for (auto index : fact.uniform_buffer_element_descriptor().index()) {
34     if (first) {
35       first = false;
36     } else {
37       stream << ", ";
38     }
39     stream << index;
40   }
41 
42   stream << "] == [";
43 
44   first = true;
45   for (auto constant_word : fact.constant_word()) {
46     if (first) {
47       first = false;
48     } else {
49       stream << ", ";
50     }
51     stream << constant_word;
52   }
53 
54   stream << "]";
55   return stream.str();
56 }
57 
ToString(const protobufs::FactDataSynonym & fact)58 std::string ToString(const protobufs::FactDataSynonym& fact) {
59   std::stringstream stream;
60   stream << fact.data1() << " = " << fact.data2();
61   return stream.str();
62 }
63 
ToString(const protobufs::FactIdEquation & fact)64 std::string ToString(const protobufs::FactIdEquation& fact) {
65   std::stringstream stream;
66   stream << fact.lhs_id();
67   stream << " " << static_cast<SpvOp>(fact.opcode());
68   for (auto rhs_id : fact.rhs_id()) {
69     stream << " " << rhs_id;
70   }
71   return stream.str();
72 }
73 
ToString(const protobufs::Fact & fact)74 std::string ToString(const protobufs::Fact& fact) {
75   switch (fact.fact_case()) {
76     case protobufs::Fact::kConstantUniformFact:
77       return ToString(fact.constant_uniform_fact());
78     case protobufs::Fact::kDataSynonymFact:
79       return ToString(fact.data_synonym_fact());
80     case protobufs::Fact::kIdEquationFact:
81       return ToString(fact.id_equation_fact());
82     default:
83       assert(false && "Stringification not supported for this fact.");
84       return "";
85   }
86 }
87 
88 }  // namespace
89 
FactManager(opt::IRContext * ir_context)90 FactManager::FactManager(opt::IRContext* ir_context)
91     : constant_uniform_facts_(ir_context),
92       data_synonym_and_id_equation_facts_(ir_context),
93       dead_block_facts_(ir_context),
94       livesafe_function_facts_(ir_context),
95       irrelevant_value_facts_(ir_context) {}
96 
AddInitialFacts(const MessageConsumer & message_consumer,const protobufs::FactSequence & facts)97 void FactManager::AddInitialFacts(const MessageConsumer& message_consumer,
98                                   const protobufs::FactSequence& facts) {
99   for (auto& fact : facts.fact()) {
100     if (!MaybeAddFact(fact)) {
101       auto message = "Invalid fact " + ToString(fact) + " ignored.";
102       message_consumer(SPV_MSG_WARNING, nullptr, {}, message.c_str());
103     }
104   }
105 }
106 
MaybeAddFact(const fuzz::protobufs::Fact & fact)107 bool FactManager::MaybeAddFact(const fuzz::protobufs::Fact& fact) {
108   switch (fact.fact_case()) {
109     case protobufs::Fact::kBlockIsDeadFact:
110       return dead_block_facts_.MaybeAddFact(fact.block_is_dead_fact());
111     case protobufs::Fact::kConstantUniformFact:
112       return constant_uniform_facts_.MaybeAddFact(fact.constant_uniform_fact());
113     case protobufs::Fact::kDataSynonymFact:
114       return data_synonym_and_id_equation_facts_.MaybeAddFact(
115           fact.data_synonym_fact(), dead_block_facts_, irrelevant_value_facts_);
116     case protobufs::Fact::kFunctionIsLivesafeFact:
117       return livesafe_function_facts_.MaybeAddFact(
118           fact.function_is_livesafe_fact());
119     case protobufs::Fact::kIdEquationFact:
120       return data_synonym_and_id_equation_facts_.MaybeAddFact(
121           fact.id_equation_fact(), dead_block_facts_, irrelevant_value_facts_);
122     case protobufs::Fact::kIdIsIrrelevant:
123       return irrelevant_value_facts_.MaybeAddFact(
124           fact.id_is_irrelevant(), data_synonym_and_id_equation_facts_);
125     case protobufs::Fact::kPointeeValueIsIrrelevantFact:
126       return irrelevant_value_facts_.MaybeAddFact(
127           fact.pointee_value_is_irrelevant_fact(),
128           data_synonym_and_id_equation_facts_);
129     case protobufs::Fact::FACT_NOT_SET:
130       assert(false && "The fact must be set");
131       return false;
132   }
133 
134   assert(false && "Unreachable");
135   return false;
136 }
137 
AddFactDataSynonym(const protobufs::DataDescriptor & data1,const protobufs::DataDescriptor & data2)138 void FactManager::AddFactDataSynonym(const protobufs::DataDescriptor& data1,
139                                      const protobufs::DataDescriptor& data2) {
140   protobufs::FactDataSynonym fact;
141   *fact.mutable_data1() = data1;
142   *fact.mutable_data2() = data2;
143   auto success = data_synonym_and_id_equation_facts_.MaybeAddFact(
144       fact, dead_block_facts_, irrelevant_value_facts_);
145   (void)success;  // Keep compilers happy in release mode.
146   assert(success && "Unable to create DataSynonym fact");
147 }
148 
GetConstantsAvailableFromUniformsForType(uint32_t type_id) const149 std::vector<uint32_t> FactManager::GetConstantsAvailableFromUniformsForType(
150     uint32_t type_id) const {
151   return constant_uniform_facts_.GetConstantsAvailableFromUniformsForType(
152       type_id);
153 }
154 
155 std::vector<protobufs::UniformBufferElementDescriptor>
GetUniformDescriptorsForConstant(uint32_t constant_id) const156 FactManager::GetUniformDescriptorsForConstant(uint32_t constant_id) const {
157   return constant_uniform_facts_.GetUniformDescriptorsForConstant(constant_id);
158 }
159 
GetConstantFromUniformDescriptor(const protobufs::UniformBufferElementDescriptor & uniform_descriptor) const160 uint32_t FactManager::GetConstantFromUniformDescriptor(
161     const protobufs::UniformBufferElementDescriptor& uniform_descriptor) const {
162   return constant_uniform_facts_.GetConstantFromUniformDescriptor(
163       uniform_descriptor);
164 }
165 
GetTypesForWhichUniformValuesAreKnown() const166 std::vector<uint32_t> FactManager::GetTypesForWhichUniformValuesAreKnown()
167     const {
168   return constant_uniform_facts_.GetTypesForWhichUniformValuesAreKnown();
169 }
170 
171 const std::vector<std::pair<protobufs::FactConstantUniform, uint32_t>>&
GetConstantUniformFactsAndTypes() const172 FactManager::GetConstantUniformFactsAndTypes() const {
173   return constant_uniform_facts_.GetConstantUniformFactsAndTypes();
174 }
175 
GetIdsForWhichSynonymsAreKnown() const176 std::vector<uint32_t> FactManager::GetIdsForWhichSynonymsAreKnown() const {
177   return data_synonym_and_id_equation_facts_.GetIdsForWhichSynonymsAreKnown();
178 }
179 
GetAllSynonyms() const180 std::vector<const protobufs::DataDescriptor*> FactManager::GetAllSynonyms()
181     const {
182   return data_synonym_and_id_equation_facts_.GetAllKnownSynonyms();
183 }
184 
185 std::vector<const protobufs::DataDescriptor*>
GetSynonymsForDataDescriptor(const protobufs::DataDescriptor & data_descriptor) const186 FactManager::GetSynonymsForDataDescriptor(
187     const protobufs::DataDescriptor& data_descriptor) const {
188   return data_synonym_and_id_equation_facts_.GetSynonymsForDataDescriptor(
189       data_descriptor);
190 }
191 
GetSynonymsForId(uint32_t id) const192 std::vector<const protobufs::DataDescriptor*> FactManager::GetSynonymsForId(
193     uint32_t id) const {
194   return data_synonym_and_id_equation_facts_.GetSynonymsForId(id);
195 }
196 
IsSynonymous(const protobufs::DataDescriptor & data_descriptor1,const protobufs::DataDescriptor & data_descriptor2) const197 bool FactManager::IsSynonymous(
198     const protobufs::DataDescriptor& data_descriptor1,
199     const protobufs::DataDescriptor& data_descriptor2) const {
200   return data_synonym_and_id_equation_facts_.IsSynonymous(data_descriptor1,
201                                                           data_descriptor2);
202 }
203 
BlockIsDead(uint32_t block_id) const204 bool FactManager::BlockIsDead(uint32_t block_id) const {
205   return dead_block_facts_.BlockIsDead(block_id);
206 }
207 
AddFactBlockIsDead(uint32_t block_id)208 void FactManager::AddFactBlockIsDead(uint32_t block_id) {
209   protobufs::FactBlockIsDead fact;
210   fact.set_block_id(block_id);
211   auto success = dead_block_facts_.MaybeAddFact(fact);
212   (void)success;  // Keep compilers happy in release mode.
213   assert(success && "|block_id| is invalid");
214 }
215 
FunctionIsLivesafe(uint32_t function_id) const216 bool FactManager::FunctionIsLivesafe(uint32_t function_id) const {
217   return livesafe_function_facts_.FunctionIsLivesafe(function_id);
218 }
219 
AddFactFunctionIsLivesafe(uint32_t function_id)220 void FactManager::AddFactFunctionIsLivesafe(uint32_t function_id) {
221   protobufs::FactFunctionIsLivesafe fact;
222   fact.set_function_id(function_id);
223   auto success = livesafe_function_facts_.MaybeAddFact(fact);
224   (void)success;  // Keep compilers happy in release mode.
225   assert(success && "|function_id| is invalid");
226 }
227 
PointeeValueIsIrrelevant(uint32_t pointer_id) const228 bool FactManager::PointeeValueIsIrrelevant(uint32_t pointer_id) const {
229   return irrelevant_value_facts_.PointeeValueIsIrrelevant(pointer_id);
230 }
231 
IdIsIrrelevant(uint32_t result_id) const232 bool FactManager::IdIsIrrelevant(uint32_t result_id) const {
233   return irrelevant_value_facts_.IdIsIrrelevant(result_id, dead_block_facts_);
234 }
235 
GetIrrelevantIds() const236 std::unordered_set<uint32_t> FactManager::GetIrrelevantIds() const {
237   return irrelevant_value_facts_.GetIrrelevantIds(dead_block_facts_);
238 }
239 
AddFactValueOfPointeeIsIrrelevant(uint32_t pointer_id)240 void FactManager::AddFactValueOfPointeeIsIrrelevant(uint32_t pointer_id) {
241   protobufs::FactPointeeValueIsIrrelevant fact;
242   fact.set_pointer_id(pointer_id);
243   auto success = irrelevant_value_facts_.MaybeAddFact(
244       fact, data_synonym_and_id_equation_facts_);
245   (void)success;  // Keep compilers happy in release mode.
246   assert(success && "|pointer_id| is invalid");
247 }
248 
AddFactIdIsIrrelevant(uint32_t result_id)249 void FactManager::AddFactIdIsIrrelevant(uint32_t result_id) {
250   protobufs::FactIdIsIrrelevant fact;
251   fact.set_result_id(result_id);
252   auto success = irrelevant_value_facts_.MaybeAddFact(
253       fact, data_synonym_and_id_equation_facts_);
254   (void)success;  // Keep compilers happy in release mode.
255   assert(success && "|result_id| is invalid");
256 }
257 
AddFactIdEquation(uint32_t lhs_id,SpvOp opcode,const std::vector<uint32_t> & rhs_id)258 void FactManager::AddFactIdEquation(uint32_t lhs_id, SpvOp opcode,
259                                     const std::vector<uint32_t>& rhs_id) {
260   protobufs::FactIdEquation fact;
261   fact.set_lhs_id(lhs_id);
262   fact.set_opcode(opcode);
263   for (auto an_rhs_id : rhs_id) {
264     fact.add_rhs_id(an_rhs_id);
265   }
266   auto success = data_synonym_and_id_equation_facts_.MaybeAddFact(
267       fact, dead_block_facts_, irrelevant_value_facts_);
268   (void)success;  // Keep compilers happy in release mode.
269   assert(success && "Can't create IdIsIrrelevant fact");
270 }
271 
ComputeClosureOfFacts(uint32_t maximum_equivalence_class_size)272 void FactManager::ComputeClosureOfFacts(
273     uint32_t maximum_equivalence_class_size) {
274   data_synonym_and_id_equation_facts_.ComputeClosureOfFacts(
275       maximum_equivalence_class_size);
276 }
277 
278 }  // namespace fuzz
279 }  // namespace spvtools
280