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/fact_manager.h"
18
19 #include "gtest/gtest.h"
20 #include "source/fuzz/fuzzer_util.h"
21 #include "source/fuzz/uniform_buffer_element_descriptor.h"
22 #include "test/fuzz/fuzz_test_util.h"
23
24 namespace spvtools {
25 namespace fuzz {
26 namespace {
27
28 using opt::analysis::BoolConstant;
29 using opt::analysis::FloatConstant;
30 using opt::analysis::IntConstant;
31 using opt::analysis::ScalarConstant;
32
33 using opt::analysis::Bool;
34 using opt::analysis::Float;
35 using opt::analysis::Integer;
36 using opt::analysis::Type;
37
AddFactHelper(FactManager * fact_manager,const std::vector<uint32_t> & words,const protobufs::UniformBufferElementDescriptor & descriptor)38 bool AddFactHelper(
39 FactManager* fact_manager, const std::vector<uint32_t>& words,
40 const protobufs::UniformBufferElementDescriptor& descriptor) {
41 protobufs::FactConstantUniform constant_uniform_fact;
42 for (auto word : words) {
43 constant_uniform_fact.add_constant_word(word);
44 }
45 *constant_uniform_fact.mutable_uniform_buffer_element_descriptor() =
46 descriptor;
47 protobufs::Fact fact;
48 *fact.mutable_constant_uniform_fact() = constant_uniform_fact;
49 return fact_manager->MaybeAddFact(fact);
50 }
51
TEST(ConstantUniformFactsTest,ConstantsAvailableViaUniforms)52 TEST(ConstantUniformFactsTest, ConstantsAvailableViaUniforms) {
53 std::string shader = R"(
54 OpCapability Shader
55 OpCapability Int64
56 OpCapability Float64
57 %1 = OpExtInstImport "GLSL.std.450"
58 OpMemoryModel Logical GLSL450
59 OpEntryPoint Fragment %4 "main"
60 OpExecutionMode %4 OriginUpperLeft
61 OpSource GLSL 450
62 OpName %4 "main"
63 OpDecorate %100 DescriptorSet 0
64 OpDecorate %100 Binding 0
65 OpDecorate %200 DescriptorSet 0
66 OpDecorate %200 Binding 1
67 OpDecorate %300 DescriptorSet 0
68 OpDecorate %300 Binding 2
69 OpDecorate %400 DescriptorSet 0
70 OpDecorate %400 Binding 3
71 OpDecorate %500 DescriptorSet 0
72 OpDecorate %500 Binding 4
73 OpDecorate %600 DescriptorSet 0
74 OpDecorate %600 Binding 5
75 OpDecorate %700 DescriptorSet 0
76 OpDecorate %700 Binding 6
77 OpDecorate %800 DescriptorSet 1
78 OpDecorate %800 Binding 0
79 OpDecorate %900 DescriptorSet 1
80 OpDecorate %900 Binding 1
81 OpDecorate %1000 DescriptorSet 1
82 OpDecorate %1000 Binding 2
83 OpDecorate %1100 DescriptorSet 1
84 OpDecorate %1100 Binding 3
85 OpDecorate %1200 DescriptorSet 1
86 OpDecorate %1200 Binding 4
87 OpDecorate %1300 DescriptorSet 1
88 OpDecorate %1300 Binding 5
89 OpDecorate %1400 DescriptorSet 1
90 OpDecorate %1400 Binding 6
91 OpDecorate %1500 DescriptorSet 2
92 OpDecorate %1500 Binding 0
93 OpDecorate %1600 DescriptorSet 2
94 OpDecorate %1600 Binding 1
95 OpDecorate %1700 DescriptorSet 2
96 OpDecorate %1700 Binding 2
97 OpDecorate %1800 DescriptorSet 2
98 OpDecorate %1800 Binding 3
99 OpDecorate %1900 DescriptorSet 2
100 OpDecorate %1900 Binding 4
101 %2 = OpTypeVoid
102 %3 = OpTypeFunction %2
103 %10 = OpTypeInt 32 0
104 %11 = OpTypeInt 32 1
105 %12 = OpTypeInt 64 0
106 %13 = OpTypeInt 64 1
107 %15 = OpTypeFloat 32
108 %16 = OpTypeFloat 64
109 %17 = OpConstant %11 5
110 %18 = OpConstant %11 20
111 %19 = OpTypeVector %10 4
112 %20 = OpConstant %11 6
113 %21 = OpTypeVector %12 4
114 %22 = OpConstant %11 10
115 %23 = OpTypeVector %11 4
116
117 %102 = OpTypeStruct %10 %10 %23
118 %101 = OpTypePointer Uniform %102
119 %100 = OpVariable %101 Uniform
120
121 %203 = OpTypeArray %23 %17
122 %202 = OpTypeArray %203 %18
123 %201 = OpTypePointer Uniform %202
124 %200 = OpVariable %201 Uniform
125
126 %305 = OpTypeStruct %16 %16 %16 %11 %16
127 %304 = OpTypeStruct %16 %16 %305
128 %303 = OpTypeStruct %304
129 %302 = OpTypeStruct %10 %303
130 %301 = OpTypePointer Uniform %302
131 %300 = OpVariable %301 Uniform
132
133 %400 = OpVariable %101 Uniform
134
135 %500 = OpVariable %201 Uniform
136
137 %604 = OpTypeArray %13 %20
138 %603 = OpTypeArray %604 %20
139 %602 = OpTypeArray %603 %20
140 %601 = OpTypePointer Uniform %602
141 %600 = OpVariable %601 Uniform
142
143 %703 = OpTypeArray %13 %20
144 %702 = OpTypeArray %703 %20
145 %701 = OpTypePointer Uniform %702
146 %700 = OpVariable %701 Uniform
147
148 %802 = OpTypeStruct %702 %602 %19 %202 %302
149 %801 = OpTypePointer Uniform %802
150 %800 = OpVariable %801 Uniform
151
152 %902 = OpTypeStruct %702 %802 %19 %202 %302
153 %901 = OpTypePointer Uniform %902
154 %900 = OpVariable %901 Uniform
155
156 %1003 = OpTypeStruct %802
157 %1002 = OpTypeArray %1003 %20
158 %1001 = OpTypePointer Uniform %1002
159 %1000 = OpVariable %1001 Uniform
160
161 %1101 = OpTypePointer Uniform %21
162 %1100 = OpVariable %1101 Uniform
163
164 %1202 = OpTypeArray %21 %20
165 %1201 = OpTypePointer Uniform %1202
166 %1200 = OpVariable %1201 Uniform
167
168 %1302 = OpTypeArray %21 %20
169 %1301 = OpTypePointer Uniform %1302
170 %1300 = OpVariable %1301 Uniform
171
172 %1402 = OpTypeArray %15 %22
173 %1401 = OpTypePointer Uniform %1402
174 %1400 = OpVariable %1401 Uniform
175
176 %1501 = OpTypePointer Uniform %1402
177 %1500 = OpVariable %1501 Uniform
178
179 %1602 = OpTypeArray %1402 %22
180 %1601 = OpTypePointer Uniform %1602
181 %1600 = OpVariable %1601 Uniform
182
183 %1704 = OpTypeStruct %16 %16 %16
184 %1703 = OpTypeArray %1704 %22
185 %1702 = OpTypeArray %1703 %22
186 %1701 = OpTypePointer Uniform %1702
187 %1700 = OpVariable %1701 Uniform
188
189 %1800 = OpVariable %1701 Uniform
190
191 %1906 = OpTypeStruct %16
192 %1905 = OpTypeStruct %1906
193 %1904 = OpTypeStruct %1905
194 %1903 = OpTypeStruct %1904
195 %1902 = OpTypeStruct %1903
196 %1901 = OpTypePointer Uniform %1902
197 %1900 = OpVariable %1901 Uniform
198
199 %4 = OpFunction %2 None %3
200 %5 = OpLabel
201 OpReturn
202 OpFunctionEnd
203 )";
204
205 const auto env = SPV_ENV_UNIVERSAL_1_3;
206 const auto consumer = nullptr;
207 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
208 spvtools::ValidatorOptions validator_options;
209 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
210 kConsoleMessageConsumer));
211
212 uint32_t buffer_int32_min[1];
213 uint32_t buffer_int64_1[2];
214 uint32_t buffer_int64_max[2];
215 uint32_t buffer_uint64_1[2];
216 uint32_t buffer_uint64_max[2];
217 uint32_t buffer_float_10[1];
218 uint32_t buffer_double_10[2];
219 uint32_t buffer_double_20[2];
220
221 {
222 int32_t temp = std::numeric_limits<int32_t>::min();
223 std::memcpy(&buffer_int32_min, &temp, sizeof(temp));
224 }
225
226 {
227 int64_t temp = 1;
228 std::memcpy(&buffer_int64_1, &temp, sizeof(temp));
229 }
230
231 {
232 int64_t temp = std::numeric_limits<int64_t>::max();
233 std::memcpy(&buffer_int64_max, &temp, sizeof(temp));
234 }
235
236 {
237 uint64_t temp = 1;
238 std::memcpy(&buffer_uint64_1, &temp, sizeof(temp));
239 }
240
241 {
242 uint64_t temp = std::numeric_limits<uint64_t>::max();
243 std::memcpy(&buffer_uint64_max, &temp, sizeof(temp));
244 }
245
246 {
247 float temp = 10.0f;
248 std::memcpy(&buffer_float_10, &temp, sizeof(float));
249 }
250
251 {
252 double temp = 10.0;
253 std::memcpy(&buffer_double_10, &temp, sizeof(temp));
254 }
255
256 {
257 double temp = 20.0;
258 std::memcpy(&buffer_double_20, &temp, sizeof(temp));
259 }
260
261 FactManager fact_manager(context.get());
262
263 uint32_t type_int32_id = 11;
264 uint32_t type_int64_id = 13;
265 uint32_t type_uint32_id = 10;
266 uint32_t type_uint64_id = 12;
267 uint32_t type_float_id = 15;
268 uint32_t type_double_id = 16;
269
270 // Initially there should be no facts about uniforms.
271 ASSERT_TRUE(
272 fact_manager.GetConstantsAvailableFromUniformsForType(type_uint32_id)
273 .empty());
274
275 // In the comments that follow we write v[...][...] to refer to uniform
276 // variable v indexed with some given indices, when in practice v is
277 // identified via a (descriptor set, binding) pair.
278
279 // 100[2][3] == int(1)
280 ASSERT_TRUE(AddFactHelper(&fact_manager, {1},
281 MakeUniformBufferElementDescriptor(0, 0, {2, 3})));
282
283 // 200[1][2][3] == int(1)
284 ASSERT_TRUE(AddFactHelper(
285 &fact_manager, {1}, MakeUniformBufferElementDescriptor(0, 1, {1, 2, 3})));
286
287 // 300[1][0][2][3] == int(1)
288 ASSERT_TRUE(
289 AddFactHelper(&fact_manager, {1},
290 MakeUniformBufferElementDescriptor(0, 2, {1, 0, 2, 3})));
291
292 // 400[2][3] = int32_min
293 ASSERT_TRUE(AddFactHelper(&fact_manager, {buffer_int32_min[0]},
294 MakeUniformBufferElementDescriptor(0, 3, {2, 3})));
295
296 // 500[1][2][3] = int32_min
297 ASSERT_TRUE(
298 AddFactHelper(&fact_manager, {buffer_int32_min[0]},
299 MakeUniformBufferElementDescriptor(0, 4, {1, 2, 3})));
300
301 // 600[1][2][3] = int64_max
302 ASSERT_TRUE(
303 AddFactHelper(&fact_manager, {buffer_int64_max[0], buffer_int64_max[1]},
304 MakeUniformBufferElementDescriptor(0, 5, {1, 2, 3})));
305
306 // 700[1][1] = int64_max
307 ASSERT_TRUE(AddFactHelper(&fact_manager,
308 {buffer_int64_max[0], buffer_int64_max[1]},
309 MakeUniformBufferElementDescriptor(0, 6, {1, 1})));
310
311 // 800[2][3] = uint(1)
312 ASSERT_TRUE(AddFactHelper(&fact_manager, {1},
313 MakeUniformBufferElementDescriptor(1, 0, {2, 3})));
314
315 // 900[1][2][3] = uint(1)
316 ASSERT_TRUE(AddFactHelper(
317 &fact_manager, {1}, MakeUniformBufferElementDescriptor(1, 1, {1, 2, 3})));
318
319 // 1000[1][0][2][3] = uint(1)
320 ASSERT_TRUE(
321 AddFactHelper(&fact_manager, {1},
322 MakeUniformBufferElementDescriptor(1, 2, {1, 0, 2, 3})));
323
324 // 1100[0] = uint64(1)
325 ASSERT_TRUE(AddFactHelper(&fact_manager,
326 {buffer_uint64_1[0], buffer_uint64_1[1]},
327 MakeUniformBufferElementDescriptor(1, 3, {0})));
328
329 // 1200[0][0] = uint64_max
330 ASSERT_TRUE(AddFactHelper(&fact_manager,
331 {buffer_uint64_max[0], buffer_uint64_max[1]},
332 MakeUniformBufferElementDescriptor(1, 4, {0, 0})));
333
334 // 1300[1][0] = uint64_max
335 ASSERT_TRUE(AddFactHelper(&fact_manager,
336 {buffer_uint64_max[0], buffer_uint64_max[1]},
337 MakeUniformBufferElementDescriptor(1, 5, {1, 0})));
338
339 // 1400[6] = float(10.0)
340 ASSERT_TRUE(AddFactHelper(&fact_manager, {buffer_float_10[0]},
341 MakeUniformBufferElementDescriptor(1, 6, {6})));
342
343 // 1500[7] = float(10.0)
344 ASSERT_TRUE(AddFactHelper(&fact_manager, {buffer_float_10[0]},
345 MakeUniformBufferElementDescriptor(2, 0, {7})));
346
347 // 1600[9][9] = float(10.0)
348 ASSERT_TRUE(AddFactHelper(&fact_manager, {buffer_float_10[0]},
349 MakeUniformBufferElementDescriptor(2, 1, {9, 9})));
350
351 // 1700[9][9][1] = double(10.0)
352 ASSERT_TRUE(
353 AddFactHelper(&fact_manager, {buffer_double_10[0], buffer_double_10[1]},
354 MakeUniformBufferElementDescriptor(2, 2, {9, 9, 1})));
355
356 // 1800[9][9][2] = double(10.0)
357 ASSERT_TRUE(
358 AddFactHelper(&fact_manager, {buffer_double_10[0], buffer_double_10[1]},
359 MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2})));
360
361 // 1900[0][0][0][0][0] = double(20.0)
362 ASSERT_TRUE(
363 AddFactHelper(&fact_manager, {buffer_double_20[0], buffer_double_20[1]},
364 MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0})));
365
366 opt::Instruction::OperandList operands = {
367 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}};
368 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
369 context.get(), SpvOpConstant, type_int32_id, 50, operands));
370 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int32_min[0]}}};
371 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
372 context.get(), SpvOpConstant, type_int32_id, 51, operands));
373 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int64_max[0]}},
374 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_int64_max[1]}}};
375 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
376 context.get(), SpvOpConstant, type_int64_id, 52, operands));
377 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}};
378 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
379 context.get(), SpvOpConstant, type_uint32_id, 53, operands));
380 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_1[0]}},
381 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_1[1]}}};
382 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
383 context.get(), SpvOpConstant, type_uint64_id, 54, operands));
384 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_max[0]}},
385 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_uint64_max[1]}}};
386 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
387 context.get(), SpvOpConstant, type_uint64_id, 55, operands));
388 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_float_10[0]}}};
389 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
390 context.get(), SpvOpConstant, type_float_id, 56, operands));
391 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_10[0]}},
392 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_10[1]}}};
393 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
394 context.get(), SpvOpConstant, type_double_id, 57, operands));
395 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_20[0]}},
396 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {buffer_double_20[1]}}};
397 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
398 context.get(), SpvOpConstant, type_double_id, 58, operands));
399
400 // A duplicate of the constant with id 59.
401 operands = {{SPV_OPERAND_TYPE_LITERAL_INTEGER, {1}}};
402 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
403 context.get(), SpvOpConstant, type_int32_id, 59, operands));
404
405 context->InvalidateAnalysesExceptFor(opt::IRContext::Analysis::kAnalysisNone);
406
407 // Constants 1 and int32_min are available.
408 ASSERT_EQ(2,
409 fact_manager.GetConstantsAvailableFromUniformsForType(type_int32_id)
410 .size());
411 // Constant int64_max is available.
412 ASSERT_EQ(1,
413 fact_manager.GetConstantsAvailableFromUniformsForType(type_int64_id)
414 .size());
415 // Constant 1u is available.
416 ASSERT_EQ(
417 1, fact_manager.GetConstantsAvailableFromUniformsForType(type_uint32_id)
418 .size());
419 // Constants 1u and uint64_max are available.
420 ASSERT_EQ(
421 2, fact_manager.GetConstantsAvailableFromUniformsForType(type_uint64_id)
422 .size());
423 // Constant 10.0 is available.
424 ASSERT_EQ(1,
425 fact_manager.GetConstantsAvailableFromUniformsForType(type_float_id)
426 .size());
427 // Constants 10.0 and 20.0 are available.
428 ASSERT_EQ(
429 2, fact_manager.GetConstantsAvailableFromUniformsForType(type_double_id)
430 .size());
431
432 ASSERT_EQ(std::numeric_limits<int64_t>::max(),
433 context->get_constant_mgr()
434 ->FindDeclaredConstant(
435 fact_manager.GetConstantsAvailableFromUniformsForType(
436 type_int64_id)[0])
437 ->AsIntConstant()
438 ->GetS64());
439 ASSERT_EQ(1, context->get_constant_mgr()
440 ->FindDeclaredConstant(
441 fact_manager.GetConstantsAvailableFromUniformsForType(
442 type_uint32_id)[0])
443 ->AsIntConstant()
444 ->GetU32());
445 ASSERT_EQ(10.0f,
446 context->get_constant_mgr()
447 ->FindDeclaredConstant(
448 fact_manager.GetConstantsAvailableFromUniformsForType(
449 type_float_id)[0])
450 ->AsFloatConstant()
451 ->GetFloat());
452 const std::vector<uint32_t>& double_constant_ids =
453 fact_manager.GetConstantsAvailableFromUniformsForType(type_double_id);
454 ASSERT_EQ(10.0, context->get_constant_mgr()
455 ->FindDeclaredConstant(double_constant_ids[0])
456 ->AsFloatConstant()
457 ->GetDouble());
458 ASSERT_EQ(20.0, context->get_constant_mgr()
459 ->FindDeclaredConstant(double_constant_ids[1])
460 ->AsFloatConstant()
461 ->GetDouble());
462
463 const std::vector<protobufs::UniformBufferElementDescriptor>
464 descriptors_for_double_10 =
465 fact_manager.GetUniformDescriptorsForConstant(double_constant_ids[0]);
466 ASSERT_EQ(2, descriptors_for_double_10.size());
467 {
468 auto temp = MakeUniformBufferElementDescriptor(2, 2, {9, 9, 1});
469 ASSERT_TRUE(UniformBufferElementDescriptorEquals()(
470 &temp, &descriptors_for_double_10[0]));
471 }
472 {
473 auto temp = MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2});
474 ASSERT_TRUE(UniformBufferElementDescriptorEquals()(
475 &temp, &descriptors_for_double_10[1]));
476 }
477 const std::vector<protobufs::UniformBufferElementDescriptor>
478 descriptors_for_double_20 =
479 fact_manager.GetUniformDescriptorsForConstant(double_constant_ids[1]);
480 ASSERT_EQ(1, descriptors_for_double_20.size());
481 {
482 auto temp = MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0});
483 ASSERT_TRUE(UniformBufferElementDescriptorEquals()(
484 &temp, &descriptors_for_double_20[0]));
485 }
486
487 auto constant_1_id = fact_manager.GetConstantFromUniformDescriptor(
488 MakeUniformBufferElementDescriptor(2, 3, {9, 9, 2}));
489 ASSERT_TRUE(constant_1_id);
490
491 auto constant_2_id = fact_manager.GetConstantFromUniformDescriptor(
492 MakeUniformBufferElementDescriptor(2, 4, {0, 0, 0, 0, 0}));
493 ASSERT_TRUE(constant_2_id);
494
495 ASSERT_EQ(double_constant_ids[0], constant_1_id);
496
497 ASSERT_EQ(double_constant_ids[1], constant_2_id);
498 }
499
TEST(ConstantUniformFactsTest,TwoConstantsWithSameValue)500 TEST(ConstantUniformFactsTest, TwoConstantsWithSameValue) {
501 std::string shader = R"(
502 OpCapability Shader
503 %1 = OpExtInstImport "GLSL.std.450"
504 OpMemoryModel Logical GLSL450
505 OpEntryPoint Fragment %4 "main"
506 OpExecutionMode %4 OriginUpperLeft
507 OpSource ESSL 310
508 OpName %4 "main"
509 OpName %8 "x"
510 OpName %10 "buf"
511 OpMemberName %10 0 "a"
512 OpName %12 ""
513 OpDecorate %8 RelaxedPrecision
514 OpMemberDecorate %10 0 RelaxedPrecision
515 OpMemberDecorate %10 0 Offset 0
516 OpDecorate %10 Block
517 OpDecorate %12 DescriptorSet 0
518 OpDecorate %12 Binding 0
519 %2 = OpTypeVoid
520 %3 = OpTypeFunction %2
521 %6 = OpTypeInt 32 1
522 %7 = OpTypePointer Function %6
523 %9 = OpConstant %6 1
524 %20 = OpConstant %6 1
525 %10 = OpTypeStruct %6
526 %11 = OpTypePointer Uniform %10
527 %12 = OpVariable %11 Uniform
528 %4 = OpFunction %2 None %3
529 %5 = OpLabel
530 %8 = OpVariable %7 Function
531 OpStore %8 %9
532 OpReturn
533 OpFunctionEnd
534 )";
535
536 const auto env = SPV_ENV_UNIVERSAL_1_3;
537 const auto consumer = nullptr;
538 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
539 spvtools::ValidatorOptions validator_options;
540 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
541 kConsoleMessageConsumer));
542
543 FactManager fact_manager(context.get());
544
545 auto uniform_buffer_element_descriptor =
546 MakeUniformBufferElementDescriptor(0, 0, {0});
547
548 // (0, 0, [0]) = int(1)
549 ASSERT_TRUE(
550 AddFactHelper(&fact_manager, {1}, uniform_buffer_element_descriptor));
551 auto constants = fact_manager.GetConstantsAvailableFromUniformsForType(6);
552 ASSERT_EQ(1, constants.size());
553 ASSERT_TRUE(constants[0] == 9 || constants[0] == 20);
554
555 auto constant = fact_manager.GetConstantFromUniformDescriptor(
556 uniform_buffer_element_descriptor);
557 ASSERT_TRUE(constant == 9 || constant == 20);
558
559 // Because the constants with ids 9 and 20 are equal, we should get the same
560 // single uniform buffer element descriptor when we look up the descriptors
561 // for either one of them.
562 for (auto constant_id : {9u, 20u}) {
563 auto descriptors =
564 fact_manager.GetUniformDescriptorsForConstant(constant_id);
565 ASSERT_EQ(1, descriptors.size());
566 ASSERT_TRUE(UniformBufferElementDescriptorEquals()(
567 &uniform_buffer_element_descriptor, &descriptors[0]));
568 }
569 }
570
TEST(ConstantUniformFactsTest,NonFiniteFactsAreNotValid)571 TEST(ConstantUniformFactsTest, NonFiniteFactsAreNotValid) {
572 std::string shader = R"(
573 OpCapability Shader
574 OpCapability Float64
575 %1 = OpExtInstImport "GLSL.std.450"
576 OpMemoryModel Logical GLSL450
577 OpEntryPoint Fragment %4 "main"
578 OpExecutionMode %4 OriginUpperLeft
579 OpSource ESSL 310
580 OpName %4 "main"
581 OpName %7 "buf"
582 OpMemberName %7 0 "f"
583 OpMemberName %7 1 "d"
584 OpName %9 ""
585 OpMemberDecorate %7 0 Offset 0
586 OpMemberDecorate %7 1 Offset 8
587 OpDecorate %7 Block
588 OpDecorate %9 DescriptorSet 0
589 OpDecorate %9 Binding 0
590 %2 = OpTypeVoid
591 %3 = OpTypeFunction %2
592 %6 = OpTypeFloat 32
593 %10 = OpTypeFloat 64
594 %7 = OpTypeStruct %6 %10
595 %8 = OpTypePointer Uniform %7
596 %9 = OpVariable %8 Uniform
597 %4 = OpFunction %2 None %3
598 %5 = OpLabel
599 OpReturn
600 OpFunctionEnd
601 )";
602
603 const auto env = SPV_ENV_UNIVERSAL_1_3;
604 const auto consumer = nullptr;
605 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
606 spvtools::ValidatorOptions validator_options;
607 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
608 kConsoleMessageConsumer));
609
610 FactManager fact_manager(context.get());
611 auto uniform_buffer_element_descriptor_f =
612 MakeUniformBufferElementDescriptor(0, 0, {0});
613
614 auto uniform_buffer_element_descriptor_d =
615 MakeUniformBufferElementDescriptor(0, 0, {1});
616
617 if (std::numeric_limits<float>::has_infinity) {
618 // f == +inf
619 float positive_infinity_float = std::numeric_limits<float>::infinity();
620 uint32_t words[1];
621 memcpy(words, &positive_infinity_float, sizeof(float));
622 ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0]},
623 uniform_buffer_element_descriptor_f));
624 // f == -inf
625 float negative_infinity_float = std::numeric_limits<float>::infinity();
626 memcpy(words, &negative_infinity_float, sizeof(float));
627 ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0]},
628 uniform_buffer_element_descriptor_f));
629 }
630
631 if (std::numeric_limits<float>::has_quiet_NaN) {
632 // f == NaN
633 float quiet_nan_float = std::numeric_limits<float>::quiet_NaN();
634 uint32_t words[1];
635 memcpy(words, &quiet_nan_float, sizeof(float));
636 ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0]},
637 uniform_buffer_element_descriptor_f));
638 }
639
640 if (std::numeric_limits<double>::has_infinity) {
641 // d == +inf
642 double positive_infinity_double = std::numeric_limits<double>::infinity();
643 uint32_t words[2];
644 memcpy(words, &positive_infinity_double, sizeof(double));
645 ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0], words[1]},
646 uniform_buffer_element_descriptor_d));
647 // d == -inf
648 double negative_infinity_double = -std::numeric_limits<double>::infinity();
649 memcpy(words, &negative_infinity_double, sizeof(double));
650 ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0], words[1]},
651 uniform_buffer_element_descriptor_d));
652 }
653
654 if (std::numeric_limits<double>::has_quiet_NaN) {
655 // d == NaN
656 double quiet_nan_double = std::numeric_limits<double>::quiet_NaN();
657 uint32_t words[2];
658 memcpy(words, &quiet_nan_double, sizeof(double));
659 ASSERT_FALSE(AddFactHelper(&fact_manager, {words[0], words[1]},
660 uniform_buffer_element_descriptor_d));
661 }
662 }
663
TEST(ConstantUniformFactsTest,AmbiguousFact)664 TEST(ConstantUniformFactsTest, AmbiguousFact) {
665 // This test came from the following GLSL:
666 //
667 // #version 310 es
668 //
669 // precision highp float;
670 //
671 // layout(set = 0, binding = 0) uniform buf {
672 // float f;
673 // };
674 //
675 // layout(set = 0, binding = 0) uniform buf2 {
676 // float g;
677 // };
678 //
679 // void main() {
680 //
681 // }
682
683 std::string shader = R"(
684 OpCapability Shader
685 %1 = OpExtInstImport "GLSL.std.450"
686 OpMemoryModel Logical GLSL450
687 OpEntryPoint Fragment %4 "main"
688 OpExecutionMode %4 OriginUpperLeft
689 OpSource ESSL 310
690 OpName %4 "main"
691 OpName %7 "buf"
692 OpMemberName %7 0 "f"
693 OpName %9 ""
694 OpName %10 "buf2"
695 OpMemberName %10 0 "g"
696 OpName %12 ""
697 OpMemberDecorate %7 0 Offset 0
698 OpDecorate %7 Block
699 OpDecorate %9 DescriptorSet 0
700 OpDecorate %9 Binding 0
701 OpMemberDecorate %10 0 Offset 0
702 OpDecorate %10 Block
703 OpDecorate %12 DescriptorSet 0
704 OpDecorate %12 Binding 0
705 %2 = OpTypeVoid
706 %3 = OpTypeFunction %2
707 %6 = OpTypeFloat 32
708 %7 = OpTypeStruct %6
709 %8 = OpTypePointer Uniform %7
710 %9 = OpVariable %8 Uniform
711 %10 = OpTypeStruct %6
712 %11 = OpTypePointer Uniform %10
713 %12 = OpVariable %11 Uniform
714 %4 = OpFunction %2 None %3
715 %5 = OpLabel
716 OpReturn
717 OpFunctionEnd
718 )";
719
720 const auto env = SPV_ENV_UNIVERSAL_1_3;
721 const auto consumer = nullptr;
722 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
723 spvtools::ValidatorOptions validator_options;
724 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
725 kConsoleMessageConsumer));
726
727 FactManager fact_manager(context.get());
728 auto uniform_buffer_element_descriptor =
729 MakeUniformBufferElementDescriptor(0, 0, {0});
730
731 // The fact cannot be added because it is ambiguous: there are two uniforms
732 // with descriptor set 0 and binding 0.
733 ASSERT_FALSE(
734 AddFactHelper(&fact_manager, {1}, uniform_buffer_element_descriptor));
735 }
736
TEST(ConstantUniformFactsTest,CheckingFactsDoesNotAddConstants)737 TEST(ConstantUniformFactsTest, CheckingFactsDoesNotAddConstants) {
738 std::string shader = R"(
739 OpCapability Shader
740 %1 = OpExtInstImport "GLSL.std.450"
741 OpMemoryModel Logical GLSL450
742 OpEntryPoint Fragment %4 "main"
743 OpExecutionMode %4 OriginUpperLeft
744 OpSource ESSL 320
745 OpMemberDecorate %9 0 Offset 0
746 OpDecorate %9 Block
747 OpDecorate %11 DescriptorSet 0
748 OpDecorate %11 Binding 0
749 %2 = OpTypeVoid
750 %3 = OpTypeFunction %2
751 %6 = OpTypeInt 32 1
752 %7 = OpTypePointer Function %6
753 %9 = OpTypeStruct %6
754 %10 = OpTypePointer Uniform %9
755 %11 = OpVariable %10 Uniform
756 %12 = OpConstant %6 0
757 %13 = OpTypePointer Uniform %6
758 %4 = OpFunction %2 None %3
759 %5 = OpLabel
760 %8 = OpVariable %7 Function
761 %14 = OpAccessChain %13 %11 %12
762 %15 = OpLoad %6 %14
763 OpStore %8 %15
764 OpReturn
765 OpFunctionEnd
766 )";
767
768 const auto env = SPV_ENV_UNIVERSAL_1_3;
769 const auto consumer = nullptr;
770 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
771 spvtools::ValidatorOptions validator_options;
772 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
773 kConsoleMessageConsumer));
774
775 FactManager fact_manager(context.get());
776
777 // 8[0] == int(1)
778 ASSERT_TRUE(AddFactHelper(&fact_manager, {1},
779 MakeUniformBufferElementDescriptor(0, 0, {0})));
780
781 // Although 8[0] has the value 1, we do not have the constant 1 in the module.
782 // We thus should not find any constants available from uniforms for int type.
783 // Furthermore, the act of looking for appropriate constants should not change
784 // which constants are known to the constant manager.
785 auto int_type = context->get_type_mgr()->GetType(6)->AsInteger();
786 opt::analysis::IntConstant constant_one(int_type, {1});
787 ASSERT_FALSE(context->get_constant_mgr()->FindConstant(&constant_one));
788 auto available_constants =
789 fact_manager.GetConstantsAvailableFromUniformsForType(6);
790 ASSERT_EQ(0, available_constants.size());
791 ASSERT_TRUE(IsEqual(env, shader, context.get()));
792 ASSERT_FALSE(context->get_constant_mgr()->FindConstant(&constant_one));
793 }
794
795 } // namespace
796 } // namespace fuzz
797 } // namespace spvtools
798