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 <limits>
16
17 #include "source/fuzz/fact_manager.h"
18 #include "source/fuzz/uniform_buffer_element_descriptor.h"
19 #include "test/fuzz/fuzz_test_util.h"
20
21 namespace spvtools {
22 namespace fuzz {
23 namespace {
24
25 using opt::analysis::BoolConstant;
26 using opt::analysis::FloatConstant;
27 using opt::analysis::IntConstant;
28 using opt::analysis::ScalarConstant;
29
30 using opt::analysis::Bool;
31 using opt::analysis::Float;
32 using opt::analysis::Integer;
33 using opt::analysis::Type;
34
AddFactHelper(FactManager * fact_manager,opt::IRContext * context,std::vector<uint32_t> && words,const protobufs::UniformBufferElementDescriptor & descriptor)35 bool AddFactHelper(
36 FactManager* fact_manager, opt::IRContext* context,
37 std::vector<uint32_t>&& words,
38 const protobufs::UniformBufferElementDescriptor& descriptor) {
39 protobufs::FactConstantUniform constant_uniform_fact;
40 for (auto word : words) {
41 constant_uniform_fact.add_constant_word(word);
42 }
43 *constant_uniform_fact.mutable_uniform_buffer_element_descriptor() =
44 descriptor;
45 protobufs::Fact fact;
46 *fact.mutable_constant_uniform_fact() = constant_uniform_fact;
47 return fact_manager->AddFact(fact, context);
48 }
49
TEST(FactManagerTest,ConstantsAvailableViaUniforms)50 TEST(FactManagerTest, ConstantsAvailableViaUniforms) {
51 std::string shader = R"(
52 OpCapability Shader
53 OpCapability Int64
54 OpCapability Float64
55 %1 = OpExtInstImport "GLSL.std.450"
56 OpMemoryModel Logical GLSL450
57 OpEntryPoint Fragment %4 "main"
58 OpExecutionMode %4 OriginUpperLeft
59 OpSource GLSL 450
60 OpName %4 "main"
61 OpDecorate %100 DescriptorSet 0
62 OpDecorate %100 Binding 0
63 OpDecorate %200 DescriptorSet 0
64 OpDecorate %200 Binding 1
65 OpDecorate %300 DescriptorSet 0
66 OpDecorate %300 Binding 2
67 OpDecorate %400 DescriptorSet 0
68 OpDecorate %400 Binding 3
69 OpDecorate %500 DescriptorSet 0
70 OpDecorate %500 Binding 4
71 OpDecorate %600 DescriptorSet 0
72 OpDecorate %600 Binding 5
73 OpDecorate %700 DescriptorSet 0
74 OpDecorate %700 Binding 6
75 OpDecorate %800 DescriptorSet 1
76 OpDecorate %800 Binding 0
77 OpDecorate %900 DescriptorSet 1
78 OpDecorate %900 Binding 1
79 OpDecorate %1000 DescriptorSet 1
80 OpDecorate %1000 Binding 2
81 OpDecorate %1100 DescriptorSet 1
82 OpDecorate %1100 Binding 3
83 OpDecorate %1200 DescriptorSet 1
84 OpDecorate %1200 Binding 4
85 OpDecorate %1300 DescriptorSet 1
86 OpDecorate %1300 Binding 5
87 OpDecorate %1400 DescriptorSet 1
88 OpDecorate %1400 Binding 6
89 OpDecorate %1500 DescriptorSet 2
90 OpDecorate %1500 Binding 0
91 OpDecorate %1600 DescriptorSet 2
92 OpDecorate %1600 Binding 1
93 OpDecorate %1700 DescriptorSet 2
94 OpDecorate %1700 Binding 2
95 OpDecorate %1800 DescriptorSet 2
96 OpDecorate %1800 Binding 3
97 OpDecorate %1900 DescriptorSet 2
98 OpDecorate %1900 Binding 4
99 %2 = OpTypeVoid
100 %3 = OpTypeFunction %2
101 %10 = OpTypeInt 32 0
102 %11 = OpTypeInt 32 1
103 %12 = OpTypeInt 64 0
104 %13 = OpTypeInt 64 1
105 %15 = OpTypeFloat 32
106 %16 = OpTypeFloat 64
107 %17 = OpConstant %11 5
108 %18 = OpConstant %11 20
109 %19 = OpTypeVector %10 4
110 %20 = OpConstant %11 6
111 %21 = OpTypeVector %12 4
112 %22 = OpConstant %11 10
113 %23 = OpTypeVector %11 4
114
115 %102 = OpTypeStruct %10 %10 %23
116 %101 = OpTypePointer Uniform %102
117 %100 = OpVariable %101 Uniform
118
119 %203 = OpTypeArray %23 %17
120 %202 = OpTypeArray %203 %18
121 %201 = OpTypePointer Uniform %202
122 %200 = OpVariable %201 Uniform
123
124 %305 = OpTypeStruct %16 %16 %16 %11 %16
125 %304 = OpTypeStruct %16 %16 %305
126 %303 = OpTypeStruct %304
127 %302 = OpTypeStruct %10 %303
128 %301 = OpTypePointer Uniform %302
129 %300 = OpVariable %301 Uniform
130
131 %400 = OpVariable %101 Uniform
132
133 %500 = OpVariable %201 Uniform
134
135 %604 = OpTypeArray %13 %20
136 %603 = OpTypeArray %604 %20
137 %602 = OpTypeArray %603 %20
138 %601 = OpTypePointer Uniform %602
139 %600 = OpVariable %601 Uniform
140
141 %703 = OpTypeArray %13 %20
142 %702 = OpTypeArray %703 %20
143 %701 = OpTypePointer Uniform %702
144 %700 = OpVariable %701 Uniform
145
146 %802 = OpTypeStruct %702 %602 %19 %202 %302
147 %801 = OpTypePointer Uniform %802
148 %800 = OpVariable %801 Uniform
149
150 %902 = OpTypeStruct %702 %802 %19 %202 %302
151 %901 = OpTypePointer Uniform %902
152 %900 = OpVariable %901 Uniform
153
154 %1003 = OpTypeStruct %802
155 %1002 = OpTypeArray %1003 %20
156 %1001 = OpTypePointer Uniform %1002
157 %1000 = OpVariable %1001 Uniform
158
159 %1101 = OpTypePointer Uniform %21
160 %1100 = OpVariable %1101 Uniform
161
162 %1202 = OpTypeArray %21 %20
163 %1201 = OpTypePointer Uniform %1202
164 %1200 = OpVariable %1201 Uniform
165
166 %1302 = OpTypeArray %21 %20
167 %1301 = OpTypePointer Uniform %1302
168 %1300 = OpVariable %1301 Uniform
169
170 %1402 = OpTypeArray %15 %22
171 %1401 = OpTypePointer Uniform %1402
172 %1400 = OpVariable %1401 Uniform
173
174 %1501 = OpTypePointer Uniform %1402
175 %1500 = OpVariable %1501 Uniform
176
177 %1602 = OpTypeArray %1402 %22
178 %1601 = OpTypePointer Uniform %1602
179 %1600 = OpVariable %1601 Uniform
180
181 %1704 = OpTypeStruct %16 %16 %16
182 %1703 = OpTypeArray %1704 %22
183 %1702 = OpTypeArray %1703 %22
184 %1701 = OpTypePointer Uniform %1702
185 %1700 = OpVariable %1701 Uniform
186
187 %1800 = OpVariable %1701 Uniform
188
189 %1906 = OpTypeStruct %16
190 %1905 = OpTypeStruct %1906
191 %1904 = OpTypeStruct %1905
192 %1903 = OpTypeStruct %1904
193 %1902 = OpTypeStruct %1903
194 %1901 = OpTypePointer Uniform %1902
195 %1900 = OpVariable %1901 Uniform
196
197 %4 = OpFunction %2 None %3
198 %5 = OpLabel
199 OpReturn
200 OpFunctionEnd
201 )";
202
203 const auto env = SPV_ENV_UNIVERSAL_1_3;
204 const auto consumer = nullptr;
205 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
206 ASSERT_TRUE(IsValid(env, context.get()));
207
208 uint32_t buffer_int32_min[1];
209 uint32_t buffer_int64_1[2];
210 uint32_t buffer_int64_max[2];
211 uint32_t buffer_uint64_1[2];
212 uint32_t buffer_uint64_max[2];
213 uint32_t buffer_float_10[1];
214 uint32_t buffer_double_10[2];
215 uint32_t buffer_double_20[2];
216
217 {
218 int32_t temp = std::numeric_limits<int32_t>::min();
219 std::memcpy(&buffer_int32_min, &temp, sizeof(temp));
220 }
221
222 {
223 int64_t temp = 1;
224 std::memcpy(&buffer_int64_1, &temp, sizeof(temp));
225 }
226
227 {
228 int64_t temp = std::numeric_limits<int64_t>::max();
229 std::memcpy(&buffer_int64_max, &temp, sizeof(temp));
230 }
231
232 {
233 uint64_t temp = 1;
234 std::memcpy(&buffer_uint64_1, &temp, sizeof(temp));
235 }
236
237 {
238 uint64_t temp = std::numeric_limits<uint64_t>::max();
239 std::memcpy(&buffer_uint64_max, &temp, sizeof(temp));
240 }
241
242 {
243 float temp = 10.0f;
244 std::memcpy(&buffer_float_10, &temp, sizeof(float));
245 }
246
247 {
248 double temp = 10.0;
249 std::memcpy(&buffer_double_10, &temp, sizeof(temp));
250 }
251
252 {
253 double temp = 20.0;
254 std::memcpy(&buffer_double_20, &temp, sizeof(temp));
255 }
256
257 FactManager fact_manager;
258
259 uint32_t type_int32_id = 11;
260 uint32_t type_int64_id = 13;
261 uint32_t type_uint32_id = 10;
262 uint32_t type_uint64_id = 12;
263 uint32_t type_float_id = 15;
264 uint32_t type_double_id = 16;
265
266 // Initially there should be no facts about uniforms.
267 ASSERT_TRUE(fact_manager
268 .GetConstantsAvailableFromUniformsForType(context.get(),
269 type_uint32_id)
270 .empty());
271
272 // In the comments that follow we write v[...][...] to refer to uniform
273 // variable v indexed with some given indices, when in practice v is
274 // identified via a (descriptor set, binding) pair.
275
276 // 100[2][3] == int(1)
277 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1},
278 MakeUniformBufferElementDescriptor(0, 0, {2, 3})));
279
280 // 200[1][2][3] == int(1)
281 ASSERT_TRUE(
282 AddFactHelper(&fact_manager, context.get(), {1},
283 MakeUniformBufferElementDescriptor(0, 1, {1, 2, 3})));
284
285 // 300[1][0][2][3] == int(1)
286 ASSERT_TRUE(
287 AddFactHelper(&fact_manager, context.get(), {1},
288 MakeUniformBufferElementDescriptor(0, 2, {1, 0, 2, 3})));
289
290 // 400[2][3] = int32_min
291 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_int32_min[0]},
292 MakeUniformBufferElementDescriptor(0, 3, {2, 3})));
293
294 // 500[1][2][3] = int32_min
295 ASSERT_TRUE(
296 AddFactHelper(&fact_manager, context.get(), {buffer_int32_min[0]},
297 MakeUniformBufferElementDescriptor(0, 4, {1, 2, 3})));
298
299 // 600[1][2][3] = int64_max
300 ASSERT_TRUE(AddFactHelper(
301 &fact_manager, context.get(), {buffer_int64_max[0], buffer_int64_max[1]},
302 MakeUniformBufferElementDescriptor(0, 5, {1, 2, 3})));
303
304 // 700[1][1] = int64_max
305 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(),
306 {buffer_int64_max[0], buffer_int64_max[1]},
307 MakeUniformBufferElementDescriptor(0, 6, {1, 1})));
308
309 // 800[2][3] = uint(1)
310 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1},
311 MakeUniformBufferElementDescriptor(1, 0, {2, 3})));
312
313 // 900[1][2][3] = uint(1)
314 ASSERT_TRUE(
315 AddFactHelper(&fact_manager, context.get(), {1},
316 MakeUniformBufferElementDescriptor(1, 1, {1, 2, 3})));
317
318 // 1000[1][0][2][3] = uint(1)
319 ASSERT_TRUE(
320 AddFactHelper(&fact_manager, context.get(), {1},
321 MakeUniformBufferElementDescriptor(1, 2, {1, 0, 2, 3})));
322
323 // 1100[0] = uint64(1)
324 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(),
325 {buffer_uint64_1[0], buffer_uint64_1[1]},
326 MakeUniformBufferElementDescriptor(1, 3, {0})));
327
328 // 1200[0][0] = uint64_max
329 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(),
330 {buffer_uint64_max[0], buffer_uint64_max[1]},
331 MakeUniformBufferElementDescriptor(1, 4, {0, 0})));
332
333 // 1300[1][0] = uint64_max
334 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(),
335 {buffer_uint64_max[0], buffer_uint64_max[1]},
336 MakeUniformBufferElementDescriptor(1, 5, {1, 0})));
337
338 // 1400[6] = float(10.0)
339 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]},
340 MakeUniformBufferElementDescriptor(1, 6, {6})));
341
342 // 1500[7] = float(10.0)
343 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]},
344 MakeUniformBufferElementDescriptor(2, 0, {7})));
345
346 // 1600[9][9] = float(10.0)
347 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {buffer_float_10[0]},
348 MakeUniformBufferElementDescriptor(2, 1, {9, 9})));
349
350 // 1700[9][9][1] = double(10.0)
351 ASSERT_TRUE(AddFactHelper(
352 &fact_manager, context.get(), {buffer_double_10[0], buffer_double_10[1]},
353 MakeUniformBufferElementDescriptor(2, 2, {9, 9, 1})));
354
355 // 1800[9][9][2] = double(10.0)
356 ASSERT_TRUE(AddFactHelper(
357 &fact_manager, context.get(), {buffer_double_10[0], buffer_double_10[1]},
358 MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2})));
359
360 // 1900[0][0][0][0][0] = double(20.0)
361 ASSERT_TRUE(AddFactHelper(
362 &fact_manager, context.get(), {buffer_double_20[0], buffer_double_20[1]},
363 MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0})));
364
365 opt::Instruction::OperandList operands = {
366 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}};
367 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
368 context.get(), SpvOpConstant, type_int32_id, 50, operands));
369 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int32_min[0]}}};
370 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
371 context.get(), SpvOpConstant, type_int32_id, 51, operands));
372 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int64_max[0]}},
373 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int64_max[1]}}};
374 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
375 context.get(), SpvOpConstant, type_int64_id, 52, operands));
376 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}};
377 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
378 context.get(), SpvOpConstant, type_uint32_id, 53, operands));
379 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_1[0]}},
380 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_1[1]}}};
381 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
382 context.get(), SpvOpConstant, type_uint64_id, 54, operands));
383 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_max[0]}},
384 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_max[1]}}};
385 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
386 context.get(), SpvOpConstant, type_uint64_id, 55, operands));
387 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_float_10[0]}}};
388 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
389 context.get(), SpvOpConstant, type_float_id, 56, operands));
390 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_10[0]}},
391 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_10[1]}}};
392 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
393 context.get(), SpvOpConstant, type_double_id, 57, operands));
394 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_20[0]}},
395 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_20[1]}}};
396 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
397 context.get(), SpvOpConstant, type_double_id, 58, operands));
398
399 // A duplicate of the constant with id 59.
400 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}};
401 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
402 context.get(), SpvOpConstant, type_int32_id, 59, operands));
403
404 context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
405
406 // Constants 1 and int32_min are available.
407 ASSERT_EQ(2, fact_manager
408 .GetConstantsAvailableFromUniformsForType(context.get(),
409 type_int32_id)
410 .size());
411 // Constant int64_max is available.
412 ASSERT_EQ(1, fact_manager
413 .GetConstantsAvailableFromUniformsForType(context.get(),
414 type_int64_id)
415 .size());
416 // Constant 1u is available.
417 ASSERT_EQ(1, fact_manager
418 .GetConstantsAvailableFromUniformsForType(context.get(),
419 type_uint32_id)
420 .size());
421 // Constants 1u and uint64_max are available.
422 ASSERT_EQ(2, fact_manager
423 .GetConstantsAvailableFromUniformsForType(context.get(),
424 type_uint64_id)
425 .size());
426 // Constant 10.0 is available.
427 ASSERT_EQ(1, fact_manager
428 .GetConstantsAvailableFromUniformsForType(context.get(),
429 type_float_id)
430 .size());
431 // Constants 10.0 and 20.0 are available.
432 ASSERT_EQ(2, fact_manager
433 .GetConstantsAvailableFromUniformsForType(context.get(),
434 type_double_id)
435 .size());
436
437 ASSERT_EQ(std::numeric_limits<int64_t>::max(),
438 context->get_constant_mgr()
439 ->FindDeclaredConstant(
440 fact_manager.GetConstantsAvailableFromUniformsForType(
441 context.get(), type_int64_id)[0])
442 ->AsIntConstant()
443 ->GetS64());
444 ASSERT_EQ(1, context->get_constant_mgr()
445 ->FindDeclaredConstant(
446 fact_manager.GetConstantsAvailableFromUniformsForType(
447 context.get(), type_uint32_id)[0])
448 ->AsIntConstant()
449 ->GetU32());
450 ASSERT_EQ(10.0f,
451 context->get_constant_mgr()
452 ->FindDeclaredConstant(
453 fact_manager.GetConstantsAvailableFromUniformsForType(
454 context.get(), type_float_id)[0])
455 ->AsFloatConstant()
456 ->GetFloat());
457 const std::vector<uint32_t>& double_constant_ids =
458 fact_manager.GetConstantsAvailableFromUniformsForType(context.get(),
459 type_double_id);
460 ASSERT_EQ(10.0, context->get_constant_mgr()
461 ->FindDeclaredConstant(double_constant_ids[0])
462 ->AsFloatConstant()
463 ->GetDouble());
464 ASSERT_EQ(20.0, context->get_constant_mgr()
465 ->FindDeclaredConstant(double_constant_ids[1])
466 ->AsFloatConstant()
467 ->GetDouble());
468
469 const std::vector<protobufs::UniformBufferElementDescriptor>
470 descriptors_for_double_10 = fact_manager.GetUniformDescriptorsForConstant(
471 context.get(), double_constant_ids[0]);
472 ASSERT_EQ(2, descriptors_for_double_10.size());
473 {
474 auto temp = MakeUniformBufferElementDescriptor(2, 2, {9, 9, 1});
475 ASSERT_TRUE(UniformBufferElementDescriptorEquals()(
476 &temp, &descriptors_for_double_10[0]));
477 }
478 {
479 auto temp = MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2});
480 ASSERT_TRUE(UniformBufferElementDescriptorEquals()(
481 &temp, &descriptors_for_double_10[1]));
482 }
483 const std::vector<protobufs::UniformBufferElementDescriptor>
484 descriptors_for_double_20 = fact_manager.GetUniformDescriptorsForConstant(
485 context.get(), double_constant_ids[1]);
486 ASSERT_EQ(1, descriptors_for_double_20.size());
487 {
488 auto temp = MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0});
489 ASSERT_TRUE(UniformBufferElementDescriptorEquals()(
490 &temp, &descriptors_for_double_20[0]));
491 }
492
493 auto constant_1_id = fact_manager.GetConstantFromUniformDescriptor(
494 context.get(), MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2}));
495 ASSERT_TRUE(constant_1_id);
496
497 auto constant_2_id = fact_manager.GetConstantFromUniformDescriptor(
498 context.get(), MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0}));
499 ASSERT_TRUE(constant_2_id);
500
501 ASSERT_EQ(double_constant_ids[0], constant_1_id);
502
503 ASSERT_EQ(double_constant_ids[1], constant_2_id);
504 }
505
TEST(FactManagerTest,TwoConstantsWithSameValue)506 TEST(FactManagerTest, TwoConstantsWithSameValue) {
507 std::string shader = R"(
508 OpCapability Shader
509 %1 = OpExtInstImport "GLSL.std.450"
510 OpMemoryModel Logical GLSL450
511 OpEntryPoint Fragment %4 "main"
512 OpExecutionMode %4 OriginUpperLeft
513 OpSource ESSL 310
514 OpName %4 "main"
515 OpName %8 "x"
516 OpName %10 "buf"
517 OpMemberName %10 0 "a"
518 OpName %12 ""
519 OpDecorate %8 RelaxedPrecision
520 OpMemberDecorate %10 0 RelaxedPrecision
521 OpMemberDecorate %10 0 Offset 0
522 OpDecorate %10 Block
523 OpDecorate %12 DescriptorSet 0
524 OpDecorate %12 Binding 0
525 %2 = OpTypeVoid
526 %3 = OpTypeFunction %2
527 %6 = OpTypeInt 32 1
528 %7 = OpTypePointer Function %6
529 %9 = OpConstant %6 1
530 %20 = OpConstant %6 1
531 %10 = OpTypeStruct %6
532 %11 = OpTypePointer Uniform %10
533 %12 = OpVariable %11 Uniform
534 %4 = OpFunction %2 None %3
535 %5 = OpLabel
536 %8 = OpVariable %7 Function
537 OpStore %8 %9
538 OpReturn
539 OpFunctionEnd
540 )";
541
542 const auto env = SPV_ENV_UNIVERSAL_1_3;
543 const auto consumer = nullptr;
544 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
545 ASSERT_TRUE(IsValid(env, context.get()));
546
547 FactManager fact_manager;
548
549 auto uniform_buffer_element_descriptor =
550 MakeUniformBufferElementDescriptor(0, 0, {0});
551
552 // (0, 0, [0]) = int(1)
553 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), {1},
554 uniform_buffer_element_descriptor));
555 auto constants =
556 fact_manager.GetConstantsAvailableFromUniformsForType(context.get(), 6);
557 ASSERT_EQ(1, constants.size());
558 ASSERT_TRUE(constants[0] == 9 || constants[0] == 20);
559
560 auto constant = fact_manager.GetConstantFromUniformDescriptor(
561 context.get(), uniform_buffer_element_descriptor);
562 ASSERT_TRUE(constant == 9 || constant == 20);
563
564 // Because the constants with ids 9 and 20 are equal, we should get the same
565 // single uniform buffer element descriptor when we look up the descriptors
566 // for either one of them.
567 for (auto constant_id : {9u, 20u}) {
568 auto descriptors = fact_manager.GetUniformDescriptorsForConstant(
569 context.get(), constant_id);
570 ASSERT_EQ(1, descriptors.size());
571 ASSERT_TRUE(UniformBufferElementDescriptorEquals()(
572 &uniform_buffer_element_descriptor, &descriptors[0]));
573 }
574 }
575
TEST(FactManagerTest,NonFiniteFactsAreNotValid)576 TEST(FactManagerTest, NonFiniteFactsAreNotValid) {
577 std::string shader = R"(
578 OpCapability Shader
579 OpCapability Float64
580 %1 = OpExtInstImport "GLSL.std.450"
581 OpMemoryModel Logical GLSL450
582 OpEntryPoint Fragment %4 "main"
583 OpExecutionMode %4 OriginUpperLeft
584 OpSource ESSL 310
585 OpName %4 "main"
586 OpName %7 "buf"
587 OpMemberName %7 0 "f"
588 OpMemberName %7 1 "d"
589 OpName %9 ""
590 OpMemberDecorate %7 0 Offset 0
591 OpMemberDecorate %7 1 Offset 8
592 OpDecorate %7 Block
593 OpDecorate %9 DescriptorSet 0
594 OpDecorate %9 Binding 0
595 %2 = OpTypeVoid
596 %3 = OpTypeFunction %2
597 %6 = OpTypeFloat 32
598 %10 = OpTypeFloat 64
599 %7 = OpTypeStruct %6 %10
600 %8 = OpTypePointer Uniform %7
601 %9 = OpVariable %8 Uniform
602 %4 = OpFunction %2 None %3
603 %5 = OpLabel
604 OpReturn
605 OpFunctionEnd
606 )";
607
608 const auto env = SPV_ENV_UNIVERSAL_1_3;
609 const auto consumer = nullptr;
610 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
611 ASSERT_TRUE(IsValid(env, context.get()));
612
613 FactManager fact_manager;
614 auto uniform_buffer_element_descriptor_f =
615 MakeUniformBufferElementDescriptor(0, 0, {0});
616
617 auto uniform_buffer_element_descriptor_d =
618 MakeUniformBufferElementDescriptor(0, 0, {1});
619
620 if (std::numeric_limits<float>::has_infinity) {
621 // f == +inf
622 float positive_infinity_float = std::numeric_limits<float>::infinity();
623 uint32_t words[1];
624 memcpy(words, &positive_infinity_float, sizeof(float));
625 ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), {words[0]},
626 uniform_buffer_element_descriptor_f));
627 // f == -inf
628 float negative_infinity_float = std::numeric_limits<float>::infinity();
629 memcpy(words, &negative_infinity_float, sizeof(float));
630 ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), {words[0]},
631 uniform_buffer_element_descriptor_f));
632 }
633
634 if (std::numeric_limits<float>::has_quiet_NaN) {
635 // f == NaN
636 float quiet_nan_float = std::numeric_limits<float>::quiet_NaN();
637 uint32_t words[1];
638 memcpy(words, &quiet_nan_float, sizeof(float));
639 ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), {words[0]},
640 uniform_buffer_element_descriptor_f));
641 }
642
643 if (std::numeric_limits<double>::has_infinity) {
644 // d == +inf
645 double positive_infinity_double = std::numeric_limits<double>::infinity();
646 uint32_t words[2];
647 memcpy(words, &positive_infinity_double, sizeof(double));
648 ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(),
649 {words[0], words[1]},
650 uniform_buffer_element_descriptor_d));
651 // d == -inf
652 double negative_infinity_double = -std::numeric_limits<double>::infinity();
653 memcpy(words, &negative_infinity_double, sizeof(double));
654 ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(),
655 {words[0], words[1]},
656 uniform_buffer_element_descriptor_d));
657 }
658
659 if (std::numeric_limits<double>::has_quiet_NaN) {
660 // d == NaN
661 double quiet_nan_double = std::numeric_limits<double>::quiet_NaN();
662 uint32_t words[2];
663 memcpy(words, &quiet_nan_double, sizeof(double));
664 ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(),
665 {words[0], words[1]},
666 uniform_buffer_element_descriptor_d));
667 }
668 }
669
TEST(FactManagerTest,AmbiguousFact)670 TEST(FactManagerTest, AmbiguousFact) {
671 // This test came from the following GLSL:
672 //
673 // #version 310 es
674 //
675 // precision highp float;
676 //
677 // layout(set = 0, binding = 0) uniform buf {
678 // float f;
679 // };
680 //
681 // layout(set = 0, binding = 0) uniform buf2 {
682 // float g;
683 // };
684 //
685 // void main() {
686 //
687 // }
688
689 std::string shader = R"(
690 OpCapability Shader
691 %1 = OpExtInstImport "GLSL.std.450"
692 OpMemoryModel Logical GLSL450
693 OpEntryPoint Fragment %4 "main"
694 OpExecutionMode %4 OriginUpperLeft
695 OpSource ESSL 310
696 OpName %4 "main"
697 OpName %7 "buf"
698 OpMemberName %7 0 "f"
699 OpName %9 ""
700 OpName %10 "buf2"
701 OpMemberName %10 0 "g"
702 OpName %12 ""
703 OpMemberDecorate %7 0 Offset 0
704 OpDecorate %7 Block
705 OpDecorate %9 DescriptorSet 0
706 OpDecorate %9 Binding 0
707 OpMemberDecorate %10 0 Offset 0
708 OpDecorate %10 Block
709 OpDecorate %12 DescriptorSet 0
710 OpDecorate %12 Binding 0
711 %2 = OpTypeVoid
712 %3 = OpTypeFunction %2
713 %6 = OpTypeFloat 32
714 %7 = OpTypeStruct %6
715 %8 = OpTypePointer Uniform %7
716 %9 = OpVariable %8 Uniform
717 %10 = OpTypeStruct %6
718 %11 = OpTypePointer Uniform %10
719 %12 = OpVariable %11 Uniform
720 %4 = OpFunction %2 None %3
721 %5 = OpLabel
722 OpReturn
723 OpFunctionEnd
724 )";
725
726 const auto env = SPV_ENV_UNIVERSAL_1_3;
727 const auto consumer = nullptr;
728 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
729 ASSERT_TRUE(IsValid(env, context.get()));
730
731 FactManager fact_manager;
732 auto uniform_buffer_element_descriptor =
733 MakeUniformBufferElementDescriptor(0, 0, {0});
734
735 // The fact cannot be added because it is ambiguous: there are two uniforms
736 // with descriptor set 0 and binding 0.
737 ASSERT_FALSE(AddFactHelper(&fact_manager, context.get(), {1},
738 uniform_buffer_element_descriptor));
739 }
740
TEST(FactManagerTest,RecursiveAdditionOfFacts)741 TEST(FactManagerTest, RecursiveAdditionOfFacts) {
742 std::string shader = R"(
743 OpCapability Shader
744 %1 = OpExtInstImport "GLSL.std.450"
745 OpMemoryModel Logical GLSL450
746 OpEntryPoint Fragment %12 "main"
747 OpExecutionMode %12 OriginUpperLeft
748 OpSource ESSL 310
749 %2 = OpTypeVoid
750 %3 = OpTypeFunction %2
751 %6 = OpTypeFloat 32
752 %7 = OpTypeVector %6 4
753 %8 = OpTypeMatrix %7 4
754 %9 = OpConstant %6 0
755 %10 = OpConstantComposite %7 %9 %9 %9 %9
756 %11 = OpConstantComposite %8 %10 %10 %10 %10
757 %12 = OpFunction %2 None %3
758 %13 = OpLabel
759 OpReturn
760 OpFunctionEnd
761 )";
762
763 const auto env = SPV_ENV_UNIVERSAL_1_3;
764 const auto consumer = nullptr;
765 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
766 ASSERT_TRUE(IsValid(env, context.get()));
767
768 FactManager fact_manager;
769
770 fact_manager.AddFactDataSynonym(MakeDataDescriptor(10, {}),
771 MakeDataDescriptor(11, {2}), context.get());
772
773 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {}),
774 MakeDataDescriptor(11, {2})));
775 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {0}),
776 MakeDataDescriptor(11, {2, 0})));
777 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {1}),
778 MakeDataDescriptor(11, {2, 1})));
779 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {2}),
780 MakeDataDescriptor(11, {2, 2})));
781 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(10, {3}),
782 MakeDataDescriptor(11, {2, 3})));
783 }
784
TEST(FactManagerTest,LogicalNotEquationFacts)785 TEST(FactManagerTest, LogicalNotEquationFacts) {
786 std::string shader = R"(
787 OpCapability Shader
788 %1 = OpExtInstImport "GLSL.std.450"
789 OpMemoryModel Logical GLSL450
790 OpEntryPoint Fragment %12 "main"
791 OpExecutionMode %12 OriginUpperLeft
792 OpSource ESSL 310
793 %2 = OpTypeVoid
794 %3 = OpTypeFunction %2
795 %6 = OpTypeBool
796 %7 = OpConstantTrue %6
797 %12 = OpFunction %2 None %3
798 %13 = OpLabel
799 %14 = OpLogicalNot %6 %7
800 %15 = OpCopyObject %6 %7
801 %16 = OpCopyObject %6 %14
802 %17 = OpLogicalNot %6 %16
803 OpReturn
804 OpFunctionEnd
805 )";
806
807 const auto env = SPV_ENV_UNIVERSAL_1_3;
808 const auto consumer = nullptr;
809 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
810 ASSERT_TRUE(IsValid(env, context.get()));
811
812 FactManager fact_manager;
813
814 fact_manager.AddFactDataSynonym(MakeDataDescriptor(15, {}),
815 MakeDataDescriptor(7, {}), context.get());
816 fact_manager.AddFactDataSynonym(MakeDataDescriptor(16, {}),
817 MakeDataDescriptor(14, {}), context.get());
818 fact_manager.AddFactIdEquation(14, SpvOpLogicalNot, {7}, context.get());
819 fact_manager.AddFactIdEquation(17, SpvOpLogicalNot, {16}, context.get());
820
821 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(15, {}),
822 MakeDataDescriptor(7, {})));
823 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}),
824 MakeDataDescriptor(7, {})));
825 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(15, {}),
826 MakeDataDescriptor(17, {})));
827 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(16, {}),
828 MakeDataDescriptor(14, {})));
829 }
830
TEST(FactManagerTest,SignedNegateEquationFacts)831 TEST(FactManagerTest, SignedNegateEquationFacts) {
832 std::string shader = R"(
833 OpCapability Shader
834 %1 = OpExtInstImport "GLSL.std.450"
835 OpMemoryModel Logical GLSL450
836 OpEntryPoint Fragment %12 "main"
837 OpExecutionMode %12 OriginUpperLeft
838 OpSource ESSL 310
839 %2 = OpTypeVoid
840 %3 = OpTypeFunction %2
841 %6 = OpTypeInt 32 1
842 %7 = OpConstant %6 24
843 %12 = OpFunction %2 None %3
844 %13 = OpLabel
845 %14 = OpSNegate %6 %7
846 %15 = OpSNegate %6 %14
847 OpReturn
848 OpFunctionEnd
849 )";
850
851 const auto env = SPV_ENV_UNIVERSAL_1_3;
852 const auto consumer = nullptr;
853 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
854 ASSERT_TRUE(IsValid(env, context.get()));
855
856 FactManager fact_manager;
857
858 fact_manager.AddFactIdEquation(14, SpvOpSNegate, {7}, context.get());
859 fact_manager.AddFactIdEquation(15, SpvOpSNegate, {14}, context.get());
860
861 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(7, {}),
862 MakeDataDescriptor(15, {})));
863 }
864
TEST(FactManagerTest,AddSubNegateFacts1)865 TEST(FactManagerTest, AddSubNegateFacts1) {
866 std::string shader = R"(
867 OpCapability Shader
868 %1 = OpExtInstImport "GLSL.std.450"
869 OpMemoryModel Logical GLSL450
870 OpEntryPoint Fragment %12 "main"
871 OpExecutionMode %12 OriginUpperLeft
872 OpSource ESSL 310
873 %2 = OpTypeVoid
874 %3 = OpTypeFunction %2
875 %6 = OpTypeInt 32 1
876 %15 = OpConstant %6 24
877 %16 = OpConstant %6 37
878 %12 = OpFunction %2 None %3
879 %13 = OpLabel
880 %14 = OpIAdd %6 %15 %16
881 %17 = OpCopyObject %6 %15
882 %18 = OpCopyObject %6 %16
883 %19 = OpISub %6 %14 %18 ; ==> synonymous(%19, %15)
884 %20 = OpISub %6 %14 %17 ; ==> synonymous(%20, %16)
885 %21 = OpCopyObject %6 %14
886 %22 = OpISub %6 %16 %21
887 %23 = OpCopyObject %6 %22
888 %24 = OpSNegate %6 %23 ; ==> synonymous(%24, %15)
889 OpReturn
890 OpFunctionEnd
891 )";
892
893 const auto env = SPV_ENV_UNIVERSAL_1_3;
894 const auto consumer = nullptr;
895 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
896 ASSERT_TRUE(IsValid(env, context.get()));
897
898 FactManager fact_manager;
899
900 fact_manager.AddFactIdEquation(14, SpvOpIAdd, {15, 16}, context.get());
901 fact_manager.AddFactDataSynonym(MakeDataDescriptor(17, {}),
902 MakeDataDescriptor(15, {}), context.get());
903 fact_manager.AddFactDataSynonym(MakeDataDescriptor(18, {}),
904 MakeDataDescriptor(16, {}), context.get());
905 fact_manager.AddFactIdEquation(19, SpvOpISub, {14, 18}, context.get());
906 fact_manager.AddFactIdEquation(20, SpvOpISub, {14, 17}, context.get());
907 fact_manager.AddFactDataSynonym(MakeDataDescriptor(21, {}),
908 MakeDataDescriptor(14, {}), context.get());
909 fact_manager.AddFactIdEquation(22, SpvOpISub, {16, 21}, context.get());
910 fact_manager.AddFactDataSynonym(MakeDataDescriptor(23, {}),
911 MakeDataDescriptor(22, {}), context.get());
912 fact_manager.AddFactIdEquation(24, SpvOpSNegate, {23}, context.get());
913
914 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(19, {}),
915 MakeDataDescriptor(15, {})));
916 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(20, {}),
917 MakeDataDescriptor(16, {})));
918 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(24, {}),
919 MakeDataDescriptor(15, {})));
920 }
921
TEST(FactManagerTest,AddSubNegateFacts2)922 TEST(FactManagerTest, AddSubNegateFacts2) {
923 std::string shader = R"(
924 OpCapability Shader
925 %1 = OpExtInstImport "GLSL.std.450"
926 OpMemoryModel Logical GLSL450
927 OpEntryPoint Fragment %12 "main"
928 OpExecutionMode %12 OriginUpperLeft
929 OpSource ESSL 310
930 %2 = OpTypeVoid
931 %3 = OpTypeFunction %2
932 %6 = OpTypeInt 32 1
933 %15 = OpConstant %6 24
934 %16 = OpConstant %6 37
935 %12 = OpFunction %2 None %3
936 %13 = OpLabel
937 %14 = OpISub %6 %15 %16
938 %17 = OpIAdd %6 %14 %16 ; ==> synonymous(%17, %15)
939 %18 = OpIAdd %6 %16 %14 ; ==> synonymous(%17, %18, %15)
940 %19 = OpISub %6 %14 %15
941 %20 = OpSNegate %6 %19 ; ==> synonymous(%20, %16)
942 %21 = OpISub %6 %14 %19 ; ==> synonymous(%21, %15)
943 %22 = OpISub %6 %14 %18
944 %23 = OpSNegate %6 %22 ; ==> synonymous(%23, %16)
945 OpReturn
946 OpFunctionEnd
947 )";
948
949 const auto env = SPV_ENV_UNIVERSAL_1_3;
950 const auto consumer = nullptr;
951 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
952 ASSERT_TRUE(IsValid(env, context.get()));
953
954 FactManager fact_manager;
955
956 fact_manager.AddFactIdEquation(14, SpvOpISub, {15, 16}, context.get());
957 fact_manager.AddFactIdEquation(17, SpvOpIAdd, {14, 16}, context.get());
958
959 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}),
960 MakeDataDescriptor(15, {})));
961
962 fact_manager.AddFactIdEquation(18, SpvOpIAdd, {16, 14}, context.get());
963
964 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(18, {}),
965 MakeDataDescriptor(15, {})));
966 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}),
967 MakeDataDescriptor(18, {})));
968
969 fact_manager.AddFactIdEquation(19, SpvOpISub, {14, 15}, context.get());
970 fact_manager.AddFactIdEquation(20, SpvOpSNegate, {19}, context.get());
971
972 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(20, {}),
973 MakeDataDescriptor(16, {})));
974
975 fact_manager.AddFactIdEquation(21, SpvOpISub, {14, 19}, context.get());
976 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(21, {}),
977 MakeDataDescriptor(15, {})));
978
979 fact_manager.AddFactIdEquation(22, SpvOpISub, {14, 18}, context.get());
980 fact_manager.AddFactIdEquation(23, SpvOpSNegate, {22}, context.get());
981 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(23, {}),
982 MakeDataDescriptor(16, {})));
983 }
984
TEST(FactManagerTest,EquationAndEquivalenceFacts)985 TEST(FactManagerTest, EquationAndEquivalenceFacts) {
986 std::string shader = R"(
987 OpCapability Shader
988 %1 = OpExtInstImport "GLSL.std.450"
989 OpMemoryModel Logical GLSL450
990 OpEntryPoint Fragment %12 "main"
991 OpExecutionMode %12 OriginUpperLeft
992 OpSource ESSL 310
993 %2 = OpTypeVoid
994 %3 = OpTypeFunction %2
995 %6 = OpTypeInt 32 1
996 %15 = OpConstant %6 24
997 %16 = OpConstant %6 37
998 %12 = OpFunction %2 None %3
999 %13 = OpLabel
1000 %14 = OpISub %6 %15 %16
1001 %114 = OpCopyObject %6 %14
1002 %17 = OpIAdd %6 %114 %16 ; ==> synonymous(%17, %15)
1003 %18 = OpIAdd %6 %16 %114 ; ==> synonymous(%17, %18, %15)
1004 %19 = OpISub %6 %114 %15
1005 %119 = OpCopyObject %6 %19
1006 %20 = OpSNegate %6 %119 ; ==> synonymous(%20, %16)
1007 %21 = OpISub %6 %14 %19 ; ==> synonymous(%21, %15)
1008 %22 = OpISub %6 %14 %18
1009 %220 = OpCopyObject %6 %22
1010 %23 = OpSNegate %6 %220 ; ==> synonymous(%23, %16)
1011 OpReturn
1012 OpFunctionEnd
1013 )";
1014
1015 const auto env = SPV_ENV_UNIVERSAL_1_3;
1016 const auto consumer = nullptr;
1017 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1018 ASSERT_TRUE(IsValid(env, context.get()));
1019
1020 FactManager fact_manager;
1021
1022 fact_manager.AddFactIdEquation(14, SpvOpISub, {15, 16}, context.get());
1023 fact_manager.AddFactDataSynonym(MakeDataDescriptor(114, {}),
1024 MakeDataDescriptor(14, {}), context.get());
1025 fact_manager.AddFactIdEquation(17, SpvOpIAdd, {114, 16}, context.get());
1026
1027 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}),
1028 MakeDataDescriptor(15, {})));
1029
1030 fact_manager.AddFactIdEquation(18, SpvOpIAdd, {16, 114}, context.get());
1031
1032 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(18, {}),
1033 MakeDataDescriptor(15, {})));
1034 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(17, {}),
1035 MakeDataDescriptor(18, {})));
1036
1037 fact_manager.AddFactIdEquation(19, SpvOpISub, {14, 15}, context.get());
1038 fact_manager.AddFactDataSynonym(MakeDataDescriptor(119, {}),
1039 MakeDataDescriptor(19, {}), context.get());
1040 fact_manager.AddFactIdEquation(20, SpvOpSNegate, {119}, context.get());
1041
1042 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(20, {}),
1043 MakeDataDescriptor(16, {})));
1044
1045 fact_manager.AddFactIdEquation(21, SpvOpISub, {14, 19}, context.get());
1046 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(21, {}),
1047 MakeDataDescriptor(15, {})));
1048
1049 fact_manager.AddFactIdEquation(22, SpvOpISub, {14, 18}, context.get());
1050 fact_manager.AddFactDataSynonym(MakeDataDescriptor(22, {}),
1051 MakeDataDescriptor(220, {}), context.get());
1052 fact_manager.AddFactIdEquation(23, SpvOpSNegate, {220}, context.get());
1053 ASSERT_TRUE(fact_manager.IsSynonymous(MakeDataDescriptor(23, {}),
1054 MakeDataDescriptor(16, {})));
1055 }
1056
1057 } // namespace
1058 } // namespace fuzz
1059 } // namespace spvtools
1060