• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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