• 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 "source/fuzz/transformation_composite_construct.h"
16 
17 #include "gtest/gtest.h"
18 #include "source/fuzz/data_descriptor.h"
19 #include "source/fuzz/fuzzer_util.h"
20 #include "source/fuzz/instruction_descriptor.h"
21 #include "test/fuzz/fuzz_test_util.h"
22 
23 namespace spvtools {
24 namespace fuzz {
25 namespace {
26 
TEST(TransformationCompositeConstructTest,ConstructArrays)27 TEST(TransformationCompositeConstructTest, ConstructArrays) {
28   std::string shader = R"(
29                OpCapability Shader
30           %1 = OpExtInstImport "GLSL.std.450"
31                OpMemoryModel Logical GLSL450
32                OpEntryPoint Fragment %4 "main"
33                OpExecutionMode %4 OriginUpperLeft
34                OpSource ESSL 310
35                OpName %4 "main"
36                OpName %11 "floats"
37                OpName %22 "x"
38                OpName %39 "vecs"
39                OpName %49 "bools"
40                OpName %60 "many_uvec3s"
41                OpDecorate %60 RelaxedPrecision
42           %2 = OpTypeVoid
43           %3 = OpTypeFunction %2
44           %6 = OpTypeFloat 32
45           %7 = OpTypeInt 32 0
46           %8 = OpConstant %7 2
47           %9 = OpTypeArray %6 %8
48          %10 = OpTypePointer Function %9
49          %12 = OpTypeInt 32 1
50          %13 = OpConstant %12 0
51          %14 = OpConstant %6 1
52          %15 = OpTypePointer Function %6
53          %17 = OpConstant %12 1
54          %18 = OpConstant %6 2
55          %20 = OpTypeVector %6 2
56          %21 = OpTypePointer Function %20
57          %32 = OpTypeBool
58          %36 = OpConstant %7 3
59          %37 = OpTypeArray %20 %36
60          %38 = OpTypePointer Private %37
61          %39 = OpVariable %38 Private
62          %40 = OpConstant %6 3
63          %41 = OpConstantComposite %20 %40 %40
64          %42 = OpTypePointer Private %20
65          %44 = OpConstant %12 2
66          %47 = OpTypeArray %32 %36
67          %48 = OpTypePointer Function %47
68          %50 = OpConstantTrue %32
69          %51 = OpTypePointer Function %32
70          %56 = OpTypeVector %7 3
71          %57 = OpTypeArray %56 %8
72          %58 = OpTypeArray %57 %8
73          %59 = OpTypePointer Function %58
74          %61 = OpConstant %7 4
75          %62 = OpConstantComposite %56 %61 %61 %61
76          %63 = OpTypePointer Function %56
77          %65 = OpConstant %7 5
78          %66 = OpConstantComposite %56 %65 %65 %65
79          %67 = OpConstant %7 6
80          %68 = OpConstantComposite %56 %67 %67 %67
81          %69 = OpConstantComposite %57 %66 %68
82         %100 = OpUndef %57
83          %70 = OpTypePointer Function %57
84           %4 = OpFunction %2 None %3
85           %5 = OpLabel
86          %11 = OpVariable %10 Function
87          %22 = OpVariable %21 Function
88          %49 = OpVariable %48 Function
89          %60 = OpVariable %59 Function
90          %16 = OpAccessChain %15 %11 %13
91                OpStore %16 %14
92          %19 = OpAccessChain %15 %11 %17
93                OpStore %19 %18
94          %23 = OpAccessChain %15 %11 %13
95          %24 = OpLoad %6 %23
96          %25 = OpAccessChain %15 %11 %17
97          %26 = OpLoad %6 %25
98          %27 = OpCompositeConstruct %20 %24 %26
99                OpStore %22 %27
100          %28 = OpAccessChain %15 %11 %13
101          %29 = OpLoad %6 %28
102          %30 = OpAccessChain %15 %11 %17
103          %31 = OpLoad %6 %30
104          %33 = OpFOrdGreaterThan %32 %29 %31
105                OpSelectionMerge %35 None
106                OpBranchConditional %33 %34 %35
107          %34 = OpLabel
108          %43 = OpAccessChain %42 %39 %17
109                OpStore %43 %41
110          %45 = OpLoad %20 %22
111          %46 = OpAccessChain %42 %39 %44
112                OpStore %46 %45
113                OpBranch %35
114          %35 = OpLabel
115          %52 = OpAccessChain %51 %49 %13
116                OpStore %52 %50
117          %53 = OpAccessChain %51 %49 %13
118          %54 = OpLoad %32 %53
119          %55 = OpAccessChain %51 %49 %17
120                OpStore %55 %54
121          %64 = OpAccessChain %63 %60 %13 %13
122                OpStore %64 %62
123          %71 = OpAccessChain %70 %60 %17
124                OpStore %71 %69
125                OpReturn
126                OpFunctionEnd
127   )";
128 
129   const auto env = SPV_ENV_UNIVERSAL_1_3;
130   const auto consumer = nullptr;
131   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
132   spvtools::ValidatorOptions validator_options;
133   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
134                                                kConsoleMessageConsumer));
135   TransformationContext transformation_context(
136       MakeUnique<FactManager>(context.get()), validator_options);
137   // Make a vec2[3]
138   TransformationCompositeConstruct make_vec2_array_length_3(
139       37, {41, 45, 27}, MakeInstructionDescriptor(46, SpvOpAccessChain, 0),
140       200);
141   // Bad: there are too many components
142   TransformationCompositeConstruct make_vec2_array_length_3_bad(
143       37, {41, 45, 27, 27}, MakeInstructionDescriptor(46, SpvOpAccessChain, 0),
144       200);
145   ASSERT_TRUE(make_vec2_array_length_3.IsApplicable(context.get(),
146                                                     transformation_context));
147   ASSERT_FALSE(make_vec2_array_length_3_bad.IsApplicable(
148       context.get(), transformation_context));
149   ASSERT_EQ(nullptr, context->get_def_use_mgr()->GetDef(200));
150   ASSERT_EQ(nullptr, context->get_instr_block(200));
151   uint32_t num_uses_of_41_before = context->get_def_use_mgr()->NumUses(41);
152   uint32_t num_uses_of_45_before = context->get_def_use_mgr()->NumUses(45);
153   uint32_t num_uses_of_27_before = context->get_def_use_mgr()->NumUses(27);
154   ApplyAndCheckFreshIds(make_vec2_array_length_3, context.get(),
155                         &transformation_context);
156   ASSERT_EQ(SpvOpCompositeConstruct,
157             context->get_def_use_mgr()->GetDef(200)->opcode());
158   ASSERT_EQ(34, context->get_instr_block(200)->id());
159   ASSERT_EQ(num_uses_of_41_before + 1, context->get_def_use_mgr()->NumUses(41));
160   ASSERT_EQ(num_uses_of_45_before + 1, context->get_def_use_mgr()->NumUses(45));
161   ASSERT_EQ(num_uses_of_27_before + 1, context->get_def_use_mgr()->NumUses(27));
162   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
163                                                kConsoleMessageConsumer));
164   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
165       MakeDataDescriptor(41, {}), MakeDataDescriptor(200, {0})));
166   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
167       MakeDataDescriptor(45, {}), MakeDataDescriptor(200, {1})));
168   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
169       MakeDataDescriptor(27, {}), MakeDataDescriptor(200, {2})));
170 
171   // Make a float[2]
172   TransformationCompositeConstruct make_float_array_length_2(
173       9, {24, 40}, MakeInstructionDescriptor(71, SpvOpStore, 0), 201);
174   // Bad: %41 does not have type float
175   TransformationCompositeConstruct make_float_array_length_2_bad(
176       9, {41, 40}, MakeInstructionDescriptor(71, SpvOpStore, 0), 201);
177   ASSERT_TRUE(make_float_array_length_2.IsApplicable(context.get(),
178                                                      transformation_context));
179   ASSERT_FALSE(make_float_array_length_2_bad.IsApplicable(
180       context.get(), transformation_context));
181   ApplyAndCheckFreshIds(make_float_array_length_2, context.get(),
182                         &transformation_context);
183   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
184                                                kConsoleMessageConsumer));
185   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
186       MakeDataDescriptor(24, {}), MakeDataDescriptor(201, {0})));
187   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
188       MakeDataDescriptor(40, {}), MakeDataDescriptor(201, {1})));
189 
190   // Make a bool[3]
191   TransformationCompositeConstruct make_bool_array_length_3(
192       47, {33, 50, 50}, MakeInstructionDescriptor(33, SpvOpSelectionMerge, 0),
193       202);
194   // Bad: %54 is not available at the desired program point.
195   TransformationCompositeConstruct make_bool_array_length_3_bad(
196       47, {33, 54, 50}, MakeInstructionDescriptor(33, SpvOpSelectionMerge, 0),
197       202);
198   ASSERT_TRUE(make_bool_array_length_3.IsApplicable(context.get(),
199                                                     transformation_context));
200   ASSERT_FALSE(make_bool_array_length_3_bad.IsApplicable(
201       context.get(), transformation_context));
202   ApplyAndCheckFreshIds(make_bool_array_length_3, context.get(),
203                         &transformation_context);
204   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
205                                                kConsoleMessageConsumer));
206   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
207       MakeDataDescriptor(33, {}), MakeDataDescriptor(202, {0})));
208   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
209       MakeDataDescriptor(50, {}), MakeDataDescriptor(202, {1})));
210   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
211       MakeDataDescriptor(50, {}), MakeDataDescriptor(202, {2})));
212 
213   // make a uvec3[2][2]
214   TransformationCompositeConstruct make_uvec3_array_length_2_2(
215       58, {69, 100}, MakeInstructionDescriptor(64, SpvOpStore, 0), 203);
216   // Bad: Skip count 100 is too large.
217   TransformationCompositeConstruct make_uvec3_array_length_2_2_bad(
218       58, {33, 54}, MakeInstructionDescriptor(64, SpvOpStore, 100), 203);
219   ASSERT_TRUE(make_uvec3_array_length_2_2.IsApplicable(context.get(),
220                                                        transformation_context));
221   ASSERT_FALSE(make_uvec3_array_length_2_2_bad.IsApplicable(
222       context.get(), transformation_context));
223   ApplyAndCheckFreshIds(make_uvec3_array_length_2_2, context.get(),
224                         &transformation_context);
225   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
226                                                kConsoleMessageConsumer));
227   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
228       MakeDataDescriptor(69, {}), MakeDataDescriptor(203, {0})));
229   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
230       MakeDataDescriptor(100, {}), MakeDataDescriptor(203, {1})));
231 
232   std::string after_transformation = R"(
233                OpCapability Shader
234           %1 = OpExtInstImport "GLSL.std.450"
235                OpMemoryModel Logical GLSL450
236                OpEntryPoint Fragment %4 "main"
237                OpExecutionMode %4 OriginUpperLeft
238                OpSource ESSL 310
239                OpName %4 "main"
240                OpName %11 "floats"
241                OpName %22 "x"
242                OpName %39 "vecs"
243                OpName %49 "bools"
244                OpName %60 "many_uvec3s"
245                OpDecorate %60 RelaxedPrecision
246           %2 = OpTypeVoid
247           %3 = OpTypeFunction %2
248           %6 = OpTypeFloat 32
249           %7 = OpTypeInt 32 0
250           %8 = OpConstant %7 2
251           %9 = OpTypeArray %6 %8
252          %10 = OpTypePointer Function %9
253          %12 = OpTypeInt 32 1
254          %13 = OpConstant %12 0
255          %14 = OpConstant %6 1
256          %15 = OpTypePointer Function %6
257          %17 = OpConstant %12 1
258          %18 = OpConstant %6 2
259          %20 = OpTypeVector %6 2
260          %21 = OpTypePointer Function %20
261          %32 = OpTypeBool
262          %36 = OpConstant %7 3
263          %37 = OpTypeArray %20 %36
264          %38 = OpTypePointer Private %37
265          %39 = OpVariable %38 Private
266          %40 = OpConstant %6 3
267          %41 = OpConstantComposite %20 %40 %40
268          %42 = OpTypePointer Private %20
269          %44 = OpConstant %12 2
270          %47 = OpTypeArray %32 %36
271          %48 = OpTypePointer Function %47
272          %50 = OpConstantTrue %32
273          %51 = OpTypePointer Function %32
274          %56 = OpTypeVector %7 3
275          %57 = OpTypeArray %56 %8
276          %58 = OpTypeArray %57 %8
277          %59 = OpTypePointer Function %58
278          %61 = OpConstant %7 4
279          %62 = OpConstantComposite %56 %61 %61 %61
280          %63 = OpTypePointer Function %56
281          %65 = OpConstant %7 5
282          %66 = OpConstantComposite %56 %65 %65 %65
283          %67 = OpConstant %7 6
284          %68 = OpConstantComposite %56 %67 %67 %67
285          %69 = OpConstantComposite %57 %66 %68
286         %100 = OpUndef %57
287          %70 = OpTypePointer Function %57
288           %4 = OpFunction %2 None %3
289           %5 = OpLabel
290          %11 = OpVariable %10 Function
291          %22 = OpVariable %21 Function
292          %49 = OpVariable %48 Function
293          %60 = OpVariable %59 Function
294          %16 = OpAccessChain %15 %11 %13
295                OpStore %16 %14
296          %19 = OpAccessChain %15 %11 %17
297                OpStore %19 %18
298          %23 = OpAccessChain %15 %11 %13
299          %24 = OpLoad %6 %23
300          %25 = OpAccessChain %15 %11 %17
301          %26 = OpLoad %6 %25
302          %27 = OpCompositeConstruct %20 %24 %26
303                OpStore %22 %27
304          %28 = OpAccessChain %15 %11 %13
305          %29 = OpLoad %6 %28
306          %30 = OpAccessChain %15 %11 %17
307          %31 = OpLoad %6 %30
308          %33 = OpFOrdGreaterThan %32 %29 %31
309         %202 = OpCompositeConstruct %47 %33 %50 %50
310                OpSelectionMerge %35 None
311                OpBranchConditional %33 %34 %35
312          %34 = OpLabel
313          %43 = OpAccessChain %42 %39 %17
314                OpStore %43 %41
315          %45 = OpLoad %20 %22
316         %200 = OpCompositeConstruct %37 %41 %45 %27
317          %46 = OpAccessChain %42 %39 %44
318                OpStore %46 %45
319                OpBranch %35
320          %35 = OpLabel
321          %52 = OpAccessChain %51 %49 %13
322                OpStore %52 %50
323          %53 = OpAccessChain %51 %49 %13
324          %54 = OpLoad %32 %53
325          %55 = OpAccessChain %51 %49 %17
326                OpStore %55 %54
327          %64 = OpAccessChain %63 %60 %13 %13
328         %203 = OpCompositeConstruct %58 %69 %100
329                OpStore %64 %62
330          %71 = OpAccessChain %70 %60 %17
331         %201 = OpCompositeConstruct %9 %24 %40
332                OpStore %71 %69
333                OpReturn
334                OpFunctionEnd
335   )";
336 
337   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
338 }
339 
TEST(TransformationCompositeConstructTest,ConstructMatrices)340 TEST(TransformationCompositeConstructTest, ConstructMatrices) {
341   std::string shader = R"(
342                OpCapability Shader
343           %1 = OpExtInstImport "GLSL.std.450"
344                OpMemoryModel Logical GLSL450
345                OpEntryPoint Fragment %4 "main"
346                OpExecutionMode %4 OriginUpperLeft
347                OpSource ESSL 310
348                OpName %4 "main"
349                OpName %9 "v1"
350                OpName %12 "v2"
351                OpName %14 "v3"
352                OpName %19 "v4"
353                OpName %26 "v5"
354                OpName %29 "v6"
355                OpName %34 "m34"
356                OpName %37 "m43"
357                OpName %43 "vecs"
358           %2 = OpTypeVoid
359           %3 = OpTypeFunction %2
360           %6 = OpTypeFloat 32
361           %7 = OpTypeVector %6 3
362           %8 = OpTypePointer Function %7
363          %10 = OpConstant %6 1
364          %11 = OpConstantComposite %7 %10 %10 %10
365          %17 = OpTypeVector %6 4
366          %18 = OpTypePointer Function %17
367          %21 = OpConstant %6 2
368          %32 = OpTypeMatrix %17 3
369          %33 = OpTypePointer Private %32
370          %34 = OpVariable %33 Private
371          %35 = OpTypeMatrix %7 4
372          %36 = OpTypePointer Private %35
373          %37 = OpVariable %36 Private
374          %38 = OpTypeVector %6 2
375          %39 = OpTypeInt 32 0
376          %40 = OpConstant %39 3
377          %41 = OpTypeArray %38 %40
378          %42 = OpTypePointer Private %41
379          %43 = OpVariable %42 Private
380         %100 = OpUndef %7
381         %101 = OpUndef %17
382           %4 = OpFunction %2 None %3
383           %5 = OpLabel
384           %9 = OpVariable %8 Function
385          %12 = OpVariable %8 Function
386          %14 = OpVariable %8 Function
387          %19 = OpVariable %18 Function
388          %26 = OpVariable %18 Function
389          %29 = OpVariable %18 Function
390                OpStore %9 %11
391          %13 = OpLoad %7 %9
392                OpStore %12 %13
393          %15 = OpLoad %7 %12
394          %16 = OpVectorShuffle %7 %15 %15 2 1 0
395                OpStore %14 %16
396          %20 = OpLoad %7 %14
397          %22 = OpCompositeExtract %6 %20 0
398          %23 = OpCompositeExtract %6 %20 1
399          %24 = OpCompositeExtract %6 %20 2
400          %25 = OpCompositeConstruct %17 %22 %23 %24 %21
401                OpStore %19 %25
402          %27 = OpLoad %17 %19
403          %28 = OpVectorShuffle %17 %27 %27 3 2 1 0
404                OpStore %26 %28
405          %30 = OpLoad %7 %9
406          %31 = OpVectorShuffle %17 %30 %30 0 0 1 1
407                OpStore %29 %31
408                OpReturn
409                OpFunctionEnd
410   )";
411 
412   const auto env = SPV_ENV_UNIVERSAL_1_3;
413   const auto consumer = nullptr;
414   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
415   spvtools::ValidatorOptions validator_options;
416   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
417                                                kConsoleMessageConsumer));
418   TransformationContext transformation_context(
419       MakeUnique<FactManager>(context.get()), validator_options);
420   // make a mat3x4
421   TransformationCompositeConstruct make_mat34(
422       32, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200);
423   // Bad: %35 is mat4x3, not mat3x4.
424   TransformationCompositeConstruct make_mat34_bad(
425       35, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200);
426   ASSERT_TRUE(make_mat34.IsApplicable(context.get(), transformation_context));
427   ASSERT_FALSE(
428       make_mat34_bad.IsApplicable(context.get(), transformation_context));
429   ApplyAndCheckFreshIds(make_mat34, context.get(), &transformation_context);
430   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
431                                                kConsoleMessageConsumer));
432   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
433       MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0})));
434   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
435       MakeDataDescriptor(28, {}), MakeDataDescriptor(200, {1})));
436   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
437       MakeDataDescriptor(31, {}), MakeDataDescriptor(200, {2})));
438 
439   // make a mat4x3
440   TransformationCompositeConstruct make_mat43(
441       35, {11, 13, 16, 100}, MakeInstructionDescriptor(31, SpvOpStore, 0), 201);
442   // Bad: %25 does not match the matrix's column type.
443   TransformationCompositeConstruct make_mat43_bad(
444       35, {25, 13, 16, 100}, MakeInstructionDescriptor(31, SpvOpStore, 0), 201);
445   ASSERT_TRUE(make_mat43.IsApplicable(context.get(), transformation_context));
446   ASSERT_FALSE(
447       make_mat43_bad.IsApplicable(context.get(), transformation_context));
448   ApplyAndCheckFreshIds(make_mat43, context.get(), &transformation_context);
449   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
450                                                kConsoleMessageConsumer));
451   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
452       MakeDataDescriptor(11, {}), MakeDataDescriptor(201, {0})));
453   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
454       MakeDataDescriptor(13, {}), MakeDataDescriptor(201, {1})));
455   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
456       MakeDataDescriptor(16, {}), MakeDataDescriptor(201, {2})));
457   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
458       MakeDataDescriptor(100, {}), MakeDataDescriptor(201, {3})));
459 
460   std::string after_transformation = R"(
461                OpCapability Shader
462           %1 = OpExtInstImport "GLSL.std.450"
463                OpMemoryModel Logical GLSL450
464                OpEntryPoint Fragment %4 "main"
465                OpExecutionMode %4 OriginUpperLeft
466                OpSource ESSL 310
467                OpName %4 "main"
468                OpName %9 "v1"
469                OpName %12 "v2"
470                OpName %14 "v3"
471                OpName %19 "v4"
472                OpName %26 "v5"
473                OpName %29 "v6"
474                OpName %34 "m34"
475                OpName %37 "m43"
476                OpName %43 "vecs"
477           %2 = OpTypeVoid
478           %3 = OpTypeFunction %2
479           %6 = OpTypeFloat 32
480           %7 = OpTypeVector %6 3
481           %8 = OpTypePointer Function %7
482          %10 = OpConstant %6 1
483          %11 = OpConstantComposite %7 %10 %10 %10
484          %17 = OpTypeVector %6 4
485          %18 = OpTypePointer Function %17
486          %21 = OpConstant %6 2
487          %32 = OpTypeMatrix %17 3
488          %33 = OpTypePointer Private %32
489          %34 = OpVariable %33 Private
490          %35 = OpTypeMatrix %7 4
491          %36 = OpTypePointer Private %35
492          %37 = OpVariable %36 Private
493          %38 = OpTypeVector %6 2
494          %39 = OpTypeInt 32 0
495          %40 = OpConstant %39 3
496          %41 = OpTypeArray %38 %40
497          %42 = OpTypePointer Private %41
498          %43 = OpVariable %42 Private
499         %100 = OpUndef %7
500         %101 = OpUndef %17
501           %4 = OpFunction %2 None %3
502           %5 = OpLabel
503           %9 = OpVariable %8 Function
504          %12 = OpVariable %8 Function
505          %14 = OpVariable %8 Function
506          %19 = OpVariable %18 Function
507          %26 = OpVariable %18 Function
508          %29 = OpVariable %18 Function
509                OpStore %9 %11
510          %13 = OpLoad %7 %9
511                OpStore %12 %13
512          %15 = OpLoad %7 %12
513          %16 = OpVectorShuffle %7 %15 %15 2 1 0
514                OpStore %14 %16
515          %20 = OpLoad %7 %14
516          %22 = OpCompositeExtract %6 %20 0
517          %23 = OpCompositeExtract %6 %20 1
518          %24 = OpCompositeExtract %6 %20 2
519          %25 = OpCompositeConstruct %17 %22 %23 %24 %21
520                OpStore %19 %25
521          %27 = OpLoad %17 %19
522          %28 = OpVectorShuffle %17 %27 %27 3 2 1 0
523                OpStore %26 %28
524          %30 = OpLoad %7 %9
525          %31 = OpVectorShuffle %17 %30 %30 0 0 1 1
526         %201 = OpCompositeConstruct %35 %11 %13 %16 %100
527                OpStore %29 %31
528         %200 = OpCompositeConstruct %32 %25 %28 %31
529                OpReturn
530                OpFunctionEnd
531   )";
532 
533   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
534 }
535 
TEST(TransformationCompositeConstructTest,ConstructStructs)536 TEST(TransformationCompositeConstructTest, ConstructStructs) {
537   std::string shader = R"(
538                OpCapability Shader
539           %1 = OpExtInstImport "GLSL.std.450"
540                OpMemoryModel Logical GLSL450
541                OpEntryPoint Fragment %4 "main"
542                OpExecutionMode %4 OriginUpperLeft
543                OpSource ESSL 310
544                OpName %4 "main"
545                OpName %9 "Inner"
546                OpMemberName %9 0 "a"
547                OpMemberName %9 1 "b"
548                OpName %11 "i1"
549                OpName %22 "i2"
550                OpName %33 "Outer"
551                OpMemberName %33 0 "c"
552                OpMemberName %33 1 "d"
553                OpMemberName %33 2 "e"
554                OpName %35 "o"
555           %2 = OpTypeVoid
556           %3 = OpTypeFunction %2
557           %6 = OpTypeFloat 32
558           %7 = OpTypeVector %6 2
559           %8 = OpTypeInt 32 1
560           %9 = OpTypeStruct %7 %8
561          %10 = OpTypePointer Function %9
562          %12 = OpConstant %8 0
563          %13 = OpConstant %6 2
564          %14 = OpTypeInt 32 0
565          %15 = OpConstant %14 0
566          %16 = OpTypePointer Function %6
567          %18 = OpConstant %8 1
568          %19 = OpConstant %8 3
569          %20 = OpTypePointer Function %8
570          %23 = OpTypePointer Function %7
571          %31 = OpConstant %14 2
572          %32 = OpTypeArray %9 %31
573          %33 = OpTypeStruct %32 %9 %6
574          %34 = OpTypePointer Function %33
575          %36 = OpConstant %6 1
576          %37 = OpConstantComposite %7 %36 %13
577          %38 = OpConstant %8 2
578          %39 = OpConstantComposite %9 %37 %38
579          %40 = OpConstant %6 3
580          %41 = OpConstant %6 4
581          %42 = OpConstantComposite %7 %40 %41
582          %56 = OpConstant %6 5
583         %100 = OpUndef %9
584           %4 = OpFunction %2 None %3
585           %5 = OpLabel
586          %11 = OpVariable %10 Function
587          %22 = OpVariable %10 Function
588          %35 = OpVariable %34 Function
589          %17 = OpAccessChain %16 %11 %12 %15
590                OpStore %17 %13
591          %21 = OpAccessChain %20 %11 %18
592                OpStore %21 %19
593          %24 = OpAccessChain %23 %11 %12
594          %25 = OpLoad %7 %24
595          %26 = OpAccessChain %23 %22 %12
596                OpStore %26 %25
597          %27 = OpAccessChain %20 %11 %18
598          %28 = OpLoad %8 %27
599          %29 = OpIAdd %8 %28 %18
600          %30 = OpAccessChain %20 %22 %18
601                OpStore %30 %29
602          %43 = OpAccessChain %20 %11 %18
603          %44 = OpLoad %8 %43
604          %45 = OpCompositeConstruct %9 %42 %44
605          %46 = OpCompositeConstruct %32 %39 %45
606          %47 = OpLoad %9 %22
607          %48 = OpCompositeConstruct %33 %46 %47 %40
608                OpStore %35 %48
609          %49 = OpLoad %9 %11
610          %50 = OpAccessChain %10 %35 %12 %12
611                OpStore %50 %49
612          %51 = OpLoad %9 %22
613          %52 = OpAccessChain %10 %35 %12 %18
614                OpStore %52 %51
615          %53 = OpAccessChain %10 %35 %12 %12
616          %54 = OpLoad %9 %53
617          %55 = OpAccessChain %10 %35 %18
618                OpStore %55 %54
619          %57 = OpAccessChain %16 %35 %38
620                OpStore %57 %56
621                OpReturn
622                OpFunctionEnd
623   )";
624 
625   const auto env = SPV_ENV_UNIVERSAL_1_3;
626   const auto consumer = nullptr;
627   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
628   spvtools::ValidatorOptions validator_options;
629   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
630                                                kConsoleMessageConsumer));
631   TransformationContext transformation_context(
632       MakeUnique<FactManager>(context.get()), validator_options);
633   // make an Inner
634   TransformationCompositeConstruct make_inner(
635       9, {25, 19}, MakeInstructionDescriptor(57, SpvOpAccessChain, 0), 200);
636   // Bad: Too few fields to make the struct.
637   TransformationCompositeConstruct make_inner_bad(
638       9, {25}, MakeInstructionDescriptor(57, SpvOpAccessChain, 0), 200);
639   ASSERT_TRUE(make_inner.IsApplicable(context.get(), transformation_context));
640   ASSERT_FALSE(
641       make_inner_bad.IsApplicable(context.get(), transformation_context));
642   ApplyAndCheckFreshIds(make_inner, context.get(), &transformation_context);
643   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
644                                                kConsoleMessageConsumer));
645   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
646       MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0})));
647   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
648       MakeDataDescriptor(19, {}), MakeDataDescriptor(200, {1})));
649 
650   // make an Outer
651   TransformationCompositeConstruct make_outer(
652       33, {46, 200, 56}, MakeInstructionDescriptor(200, SpvOpAccessChain, 0),
653       201);
654   // Bad: %200 is not available at the desired program point.
655   TransformationCompositeConstruct make_outer_bad(
656       33, {46, 200, 56},
657       MakeInstructionDescriptor(200, SpvOpCompositeConstruct, 0), 201);
658   ASSERT_TRUE(make_outer.IsApplicable(context.get(), transformation_context));
659   ASSERT_FALSE(
660       make_outer_bad.IsApplicable(context.get(), transformation_context));
661   ApplyAndCheckFreshIds(make_outer, context.get(), &transformation_context);
662   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
663                                                kConsoleMessageConsumer));
664   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
665       MakeDataDescriptor(46, {}), MakeDataDescriptor(201, {0})));
666   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
667       MakeDataDescriptor(200, {}), MakeDataDescriptor(201, {1})));
668   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
669       MakeDataDescriptor(56, {}), MakeDataDescriptor(201, {2})));
670 
671   std::string after_transformation = R"(
672                OpCapability Shader
673           %1 = OpExtInstImport "GLSL.std.450"
674                OpMemoryModel Logical GLSL450
675                OpEntryPoint Fragment %4 "main"
676                OpExecutionMode %4 OriginUpperLeft
677                OpSource ESSL 310
678                OpName %4 "main"
679                OpName %9 "Inner"
680                OpMemberName %9 0 "a"
681                OpMemberName %9 1 "b"
682                OpName %11 "i1"
683                OpName %22 "i2"
684                OpName %33 "Outer"
685                OpMemberName %33 0 "c"
686                OpMemberName %33 1 "d"
687                OpMemberName %33 2 "e"
688                OpName %35 "o"
689           %2 = OpTypeVoid
690           %3 = OpTypeFunction %2
691           %6 = OpTypeFloat 32
692           %7 = OpTypeVector %6 2
693           %8 = OpTypeInt 32 1
694           %9 = OpTypeStruct %7 %8
695          %10 = OpTypePointer Function %9
696          %12 = OpConstant %8 0
697          %13 = OpConstant %6 2
698          %14 = OpTypeInt 32 0
699          %15 = OpConstant %14 0
700          %16 = OpTypePointer Function %6
701          %18 = OpConstant %8 1
702          %19 = OpConstant %8 3
703          %20 = OpTypePointer Function %8
704          %23 = OpTypePointer Function %7
705          %31 = OpConstant %14 2
706          %32 = OpTypeArray %9 %31
707          %33 = OpTypeStruct %32 %9 %6
708          %34 = OpTypePointer Function %33
709          %36 = OpConstant %6 1
710          %37 = OpConstantComposite %7 %36 %13
711          %38 = OpConstant %8 2
712          %39 = OpConstantComposite %9 %37 %38
713          %40 = OpConstant %6 3
714          %41 = OpConstant %6 4
715          %42 = OpConstantComposite %7 %40 %41
716          %56 = OpConstant %6 5
717         %100 = OpUndef %9
718           %4 = OpFunction %2 None %3
719           %5 = OpLabel
720          %11 = OpVariable %10 Function
721          %22 = OpVariable %10 Function
722          %35 = OpVariable %34 Function
723          %17 = OpAccessChain %16 %11 %12 %15
724                OpStore %17 %13
725          %21 = OpAccessChain %20 %11 %18
726                OpStore %21 %19
727          %24 = OpAccessChain %23 %11 %12
728          %25 = OpLoad %7 %24
729          %26 = OpAccessChain %23 %22 %12
730                OpStore %26 %25
731          %27 = OpAccessChain %20 %11 %18
732          %28 = OpLoad %8 %27
733          %29 = OpIAdd %8 %28 %18
734          %30 = OpAccessChain %20 %22 %18
735                OpStore %30 %29
736          %43 = OpAccessChain %20 %11 %18
737          %44 = OpLoad %8 %43
738          %45 = OpCompositeConstruct %9 %42 %44
739          %46 = OpCompositeConstruct %32 %39 %45
740          %47 = OpLoad %9 %22
741          %48 = OpCompositeConstruct %33 %46 %47 %40
742                OpStore %35 %48
743          %49 = OpLoad %9 %11
744          %50 = OpAccessChain %10 %35 %12 %12
745                OpStore %50 %49
746          %51 = OpLoad %9 %22
747          %52 = OpAccessChain %10 %35 %12 %18
748                OpStore %52 %51
749          %53 = OpAccessChain %10 %35 %12 %12
750          %54 = OpLoad %9 %53
751          %55 = OpAccessChain %10 %35 %18
752                OpStore %55 %54
753         %200 = OpCompositeConstruct %9 %25 %19
754         %201 = OpCompositeConstruct %33 %46 %200 %56
755          %57 = OpAccessChain %16 %35 %38
756                OpStore %57 %56
757                OpReturn
758                OpFunctionEnd
759   )";
760 
761   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
762 }
763 
TEST(TransformationCompositeConstructTest,ConstructVectors)764 TEST(TransformationCompositeConstructTest, ConstructVectors) {
765   std::string shader = R"(
766                OpCapability Shader
767           %1 = OpExtInstImport "GLSL.std.450"
768                OpMemoryModel Logical GLSL450
769                OpEntryPoint Fragment %4 "main"
770                OpExecutionMode %4 OriginUpperLeft
771                OpSource ESSL 310
772                OpName %4 "main"
773                OpName %9 "v2"
774                OpName %27 "v3"
775                OpName %46 "v4"
776                OpName %53 "iv2"
777                OpName %61 "uv3"
778                OpName %72 "bv4"
779                OpName %88 "uv2"
780                OpName %95 "bv3"
781                OpName %104 "bv2"
782                OpName %116 "iv3"
783                OpName %124 "iv4"
784                OpName %133 "uv4"
785           %2 = OpTypeVoid
786           %3 = OpTypeFunction %2
787           %6 = OpTypeFloat 32
788           %7 = OpTypeVector %6 2
789           %8 = OpTypePointer Function %7
790          %10 = OpConstant %6 1
791          %11 = OpConstant %6 2
792          %12 = OpConstantComposite %7 %10 %11
793          %13 = OpTypeInt 32 0
794          %14 = OpConstant %13 0
795          %15 = OpTypePointer Function %6
796          %18 = OpConstant %13 1
797          %21 = OpTypeBool
798          %25 = OpTypeVector %6 3
799          %26 = OpTypePointer Function %25
800          %33 = OpConstant %6 3
801          %34 = OpConstant %6 -0.756802499
802          %38 = OpConstant %13 2
803          %44 = OpTypeVector %6 4
804          %45 = OpTypePointer Function %44
805          %50 = OpTypeInt 32 1
806          %51 = OpTypeVector %50 2
807          %52 = OpTypePointer Function %51
808          %57 = OpTypePointer Function %50
809          %59 = OpTypeVector %13 3
810          %60 = OpTypePointer Function %59
811          %65 = OpConstant %13 3
812          %67 = OpTypePointer Function %13
813          %70 = OpTypeVector %21 4
814          %71 = OpTypePointer Function %70
815          %73 = OpConstantTrue %21
816          %74 = OpTypePointer Function %21
817          %86 = OpTypeVector %13 2
818          %87 = OpTypePointer Function %86
819          %93 = OpTypeVector %21 3
820          %94 = OpTypePointer Function %93
821         %102 = OpTypeVector %21 2
822         %103 = OpTypePointer Function %102
823         %111 = OpConstantFalse %21
824         %114 = OpTypeVector %50 3
825         %115 = OpTypePointer Function %114
826         %117 = OpConstant %50 3
827         %122 = OpTypeVector %50 4
828         %123 = OpTypePointer Function %122
829         %131 = OpTypeVector %13 4
830         %132 = OpTypePointer Function %131
831           %4 = OpFunction %2 None %3
832           %5 = OpLabel
833           %9 = OpVariable %8 Function
834          %27 = OpVariable %26 Function
835          %46 = OpVariable %45 Function
836          %53 = OpVariable %52 Function
837          %61 = OpVariable %60 Function
838          %72 = OpVariable %71 Function
839          %88 = OpVariable %87 Function
840          %95 = OpVariable %94 Function
841         %104 = OpVariable %103 Function
842         %116 = OpVariable %115 Function
843         %124 = OpVariable %123 Function
844         %133 = OpVariable %132 Function
845                OpStore %9 %12
846          %16 = OpAccessChain %15 %9 %14
847          %17 = OpLoad %6 %16
848          %19 = OpAccessChain %15 %9 %18
849          %20 = OpLoad %6 %19
850          %22 = OpFOrdGreaterThan %21 %17 %20
851                OpSelectionMerge %24 None
852                OpBranchConditional %22 %23 %101
853          %23 = OpLabel
854          %28 = OpAccessChain %15 %9 %14
855          %29 = OpLoad %6 %28
856          %30 = OpAccessChain %15 %9 %18
857          %31 = OpLoad %6 %30
858          %32 = OpFAdd %6 %29 %31
859          %35 = OpCompositeConstruct %25 %32 %33 %34
860                OpStore %27 %35
861          %36 = OpAccessChain %15 %27 %14
862          %37 = OpLoad %6 %36
863          %39 = OpAccessChain %15 %27 %38
864          %40 = OpLoad %6 %39
865          %41 = OpFOrdLessThan %21 %37 %40
866                OpSelectionMerge %43 None
867                OpBranchConditional %41 %42 %69
868          %42 = OpLabel
869          %47 = OpAccessChain %15 %9 %18
870          %48 = OpLoad %6 %47
871          %49 = OpAccessChain %15 %46 %14
872                OpStore %49 %48
873          %54 = OpAccessChain %15 %27 %38
874          %55 = OpLoad %6 %54
875          %56 = OpConvertFToS %50 %55
876          %58 = OpAccessChain %57 %53 %14
877                OpStore %58 %56
878          %62 = OpAccessChain %15 %46 %14
879          %63 = OpLoad %6 %62
880          %64 = OpConvertFToU %13 %63
881          %66 = OpIAdd %13 %64 %65
882          %68 = OpAccessChain %67 %61 %14
883                OpStore %68 %66
884                OpBranch %43
885          %69 = OpLabel
886          %75 = OpAccessChain %74 %72 %14
887                OpStore %75 %73
888          %76 = OpAccessChain %74 %72 %14
889          %77 = OpLoad %21 %76
890          %78 = OpLogicalNot %21 %77
891          %79 = OpAccessChain %74 %72 %18
892                OpStore %79 %78
893          %80 = OpAccessChain %74 %72 %14
894          %81 = OpLoad %21 %80
895          %82 = OpAccessChain %74 %72 %18
896          %83 = OpLoad %21 %82
897          %84 = OpLogicalAnd %21 %81 %83
898          %85 = OpAccessChain %74 %72 %38
899                OpStore %85 %84
900          %89 = OpAccessChain %67 %88 %14
901          %90 = OpLoad %13 %89
902          %91 = OpINotEqual %21 %90 %14
903          %92 = OpAccessChain %74 %72 %65
904                OpStore %92 %91
905                OpBranch %43
906          %43 = OpLabel
907          %96 = OpLoad %70 %72
908          %97 = OpCompositeExtract %21 %96 0
909          %98 = OpCompositeExtract %21 %96 1
910          %99 = OpCompositeExtract %21 %96 2
911         %100 = OpCompositeConstruct %93 %97 %98 %99
912                OpStore %95 %100
913                OpBranch %24
914         %101 = OpLabel
915         %105 = OpAccessChain %67 %88 %14
916         %106 = OpLoad %13 %105
917         %107 = OpINotEqual %21 %106 %14
918         %108 = OpCompositeConstruct %102 %107 %107
919                OpStore %104 %108
920                OpBranch %24
921          %24 = OpLabel
922         %109 = OpAccessChain %74 %104 %18
923         %110 = OpLoad %21 %109
924         %112 = OpLogicalOr %21 %110 %111
925         %113 = OpAccessChain %74 %104 %14
926                OpStore %113 %112
927         %118 = OpAccessChain %57 %116 %14
928                OpStore %118 %117
929         %119 = OpAccessChain %57 %116 %14
930         %120 = OpLoad %50 %119
931         %121 = OpAccessChain %57 %53 %18
932                OpStore %121 %120
933         %125 = OpAccessChain %57 %116 %14
934         %126 = OpLoad %50 %125
935         %127 = OpAccessChain %57 %53 %18
936         %128 = OpLoad %50 %127
937         %129 = OpIAdd %50 %126 %128
938         %130 = OpAccessChain %57 %124 %65
939                OpStore %130 %129
940         %134 = OpAccessChain %57 %116 %14
941         %135 = OpLoad %50 %134
942         %136 = OpBitcast %13 %135
943         %137 = OpAccessChain %67 %133 %14
944                OpStore %137 %136
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   spvtools::ValidatorOptions validator_options;
953   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
954                                                kConsoleMessageConsumer));
955   TransformationContext transformation_context(
956       MakeUnique<FactManager>(context.get()), validator_options);
957   TransformationCompositeConstruct make_vec2(
958       7, {17, 11}, MakeInstructionDescriptor(100, SpvOpStore, 0), 200);
959   // Bad: not enough data for a vec2
960   TransformationCompositeConstruct make_vec2_bad(
961       7, {11}, MakeInstructionDescriptor(100, SpvOpStore, 0), 200);
962   ASSERT_TRUE(make_vec2.IsApplicable(context.get(), transformation_context));
963   ASSERT_FALSE(
964       make_vec2_bad.IsApplicable(context.get(), transformation_context));
965   ApplyAndCheckFreshIds(make_vec2, context.get(), &transformation_context);
966   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
967                                                kConsoleMessageConsumer));
968   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
969       MakeDataDescriptor(17, {}), MakeDataDescriptor(200, {0})));
970   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
971       MakeDataDescriptor(11, {}), MakeDataDescriptor(200, {1})));
972 
973   TransformationCompositeConstruct make_vec3(
974       25, {12, 32}, MakeInstructionDescriptor(35, SpvOpCompositeConstruct, 0),
975       201);
976   // Bad: too much data for a vec3
977   TransformationCompositeConstruct make_vec3_bad(
978       25, {12, 32, 32},
979       MakeInstructionDescriptor(35, SpvOpCompositeConstruct, 0), 201);
980   ASSERT_TRUE(make_vec3.IsApplicable(context.get(), transformation_context));
981   ASSERT_FALSE(
982       make_vec3_bad.IsApplicable(context.get(), transformation_context));
983   ApplyAndCheckFreshIds(make_vec3, context.get(), &transformation_context);
984   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
985                                                kConsoleMessageConsumer));
986   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
987       MakeDataDescriptor(12, {0}), MakeDataDescriptor(201, {0})));
988   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
989       MakeDataDescriptor(12, {1}), MakeDataDescriptor(201, {1})));
990   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
991       MakeDataDescriptor(32, {}), MakeDataDescriptor(201, {2})));
992 
993   TransformationCompositeConstruct make_vec4(
994       44, {32, 32, 10, 11}, MakeInstructionDescriptor(75, SpvOpAccessChain, 0),
995       202);
996   // Bad: id 48 is not available at the insertion points
997   TransformationCompositeConstruct make_vec4_bad(
998       44, {48, 32, 10, 11}, MakeInstructionDescriptor(75, SpvOpAccessChain, 0),
999       202);
1000   ASSERT_TRUE(make_vec4.IsApplicable(context.get(), transformation_context));
1001   ASSERT_FALSE(
1002       make_vec4_bad.IsApplicable(context.get(), transformation_context));
1003   ApplyAndCheckFreshIds(make_vec4, context.get(), &transformation_context);
1004   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1005                                                kConsoleMessageConsumer));
1006   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1007       MakeDataDescriptor(32, {}), MakeDataDescriptor(202, {0})));
1008   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1009       MakeDataDescriptor(32, {}), MakeDataDescriptor(202, {1})));
1010   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1011       MakeDataDescriptor(10, {}), MakeDataDescriptor(202, {2})));
1012   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1013       MakeDataDescriptor(11, {}), MakeDataDescriptor(202, {3})));
1014 
1015   TransformationCompositeConstruct make_ivec2(
1016       51, {126, 120}, MakeInstructionDescriptor(128, SpvOpLoad, 0), 203);
1017   // Bad: if 128 is not available at the instruction that defines 128
1018   TransformationCompositeConstruct make_ivec2_bad(
1019       51, {128, 120}, MakeInstructionDescriptor(128, SpvOpLoad, 0), 203);
1020   ASSERT_TRUE(make_ivec2.IsApplicable(context.get(), transformation_context));
1021   ASSERT_FALSE(
1022       make_ivec2_bad.IsApplicable(context.get(), transformation_context));
1023   ApplyAndCheckFreshIds(make_ivec2, context.get(), &transformation_context);
1024   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1025                                                kConsoleMessageConsumer));
1026   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1027       MakeDataDescriptor(126, {}), MakeDataDescriptor(203, {0})));
1028   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1029       MakeDataDescriptor(120, {}), MakeDataDescriptor(203, {1})));
1030 
1031   TransformationCompositeConstruct make_ivec3(
1032       114, {56, 117, 56}, MakeInstructionDescriptor(66, SpvOpAccessChain, 0),
1033       204);
1034   // Bad because 1300 is not an id
1035   TransformationCompositeConstruct make_ivec3_bad(
1036       114, {56, 117, 1300}, MakeInstructionDescriptor(66, SpvOpAccessChain, 0),
1037       204);
1038   ASSERT_TRUE(make_ivec3.IsApplicable(context.get(), transformation_context));
1039   ASSERT_FALSE(
1040       make_ivec3_bad.IsApplicable(context.get(), transformation_context));
1041   ApplyAndCheckFreshIds(make_ivec3, context.get(), &transformation_context);
1042   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1043                                                kConsoleMessageConsumer));
1044   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1045       MakeDataDescriptor(56, {}), MakeDataDescriptor(204, {0})));
1046   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1047       MakeDataDescriptor(117, {}), MakeDataDescriptor(204, {1})));
1048   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1049       MakeDataDescriptor(56, {}), MakeDataDescriptor(204, {2})));
1050 
1051   TransformationCompositeConstruct make_ivec4(
1052       122, {56, 117, 117, 117}, MakeInstructionDescriptor(66, SpvOpIAdd, 0),
1053       205);
1054   // Bad because 86 is the wrong type.
1055   TransformationCompositeConstruct make_ivec4_bad(
1056       86, {56, 117, 117, 117}, MakeInstructionDescriptor(66, SpvOpIAdd, 0),
1057       205);
1058   ASSERT_TRUE(make_ivec4.IsApplicable(context.get(), transformation_context));
1059   ASSERT_FALSE(
1060       make_ivec4_bad.IsApplicable(context.get(), transformation_context));
1061   ApplyAndCheckFreshIds(make_ivec4, context.get(), &transformation_context);
1062   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1063                                                kConsoleMessageConsumer));
1064   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1065       MakeDataDescriptor(56, {}), MakeDataDescriptor(205, {0})));
1066   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1067       MakeDataDescriptor(117, {}), MakeDataDescriptor(205, {1})));
1068   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1069       MakeDataDescriptor(117, {}), MakeDataDescriptor(205, {2})));
1070   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1071       MakeDataDescriptor(117, {}), MakeDataDescriptor(205, {3})));
1072 
1073   TransformationCompositeConstruct make_uvec2(
1074       86, {18, 38}, MakeInstructionDescriptor(133, SpvOpAccessChain, 0), 206);
1075   TransformationCompositeConstruct make_uvec2_bad(
1076       86, {18, 38}, MakeInstructionDescriptor(133, SpvOpAccessChain, 200), 206);
1077   ASSERT_TRUE(make_uvec2.IsApplicable(context.get(), transformation_context));
1078   ASSERT_FALSE(
1079       make_uvec2_bad.IsApplicable(context.get(), transformation_context));
1080   ApplyAndCheckFreshIds(make_uvec2, context.get(), &transformation_context);
1081   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1082                                                kConsoleMessageConsumer));
1083   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1084       MakeDataDescriptor(18, {}), MakeDataDescriptor(206, {0})));
1085   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1086       MakeDataDescriptor(38, {}), MakeDataDescriptor(206, {1})));
1087 
1088   TransformationCompositeConstruct make_uvec3(
1089       59, {14, 18, 136}, MakeInstructionDescriptor(137, SpvOpReturn, 0), 207);
1090   // Bad because 1300 is not an id
1091   TransformationCompositeConstruct make_uvec3_bad(
1092       59, {14, 18, 1300}, MakeInstructionDescriptor(137, SpvOpReturn, 0), 207);
1093   ASSERT_TRUE(make_uvec3.IsApplicable(context.get(), transformation_context));
1094   ASSERT_FALSE(
1095       make_uvec3_bad.IsApplicable(context.get(), transformation_context));
1096   ApplyAndCheckFreshIds(make_uvec3, context.get(), &transformation_context);
1097   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1098                                                kConsoleMessageConsumer));
1099   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1100       MakeDataDescriptor(14, {}), MakeDataDescriptor(207, {0})));
1101   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1102       MakeDataDescriptor(18, {}), MakeDataDescriptor(207, {1})));
1103   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1104       MakeDataDescriptor(136, {}), MakeDataDescriptor(207, {2})));
1105 
1106   TransformationCompositeConstruct make_uvec4(
1107       131, {14, 18, 136, 136},
1108       MakeInstructionDescriptor(137, SpvOpAccessChain, 0), 208);
1109   // Bad because 86 is the wrong type.
1110   TransformationCompositeConstruct make_uvec4_bad(
1111       86, {14, 18, 136, 136},
1112       MakeInstructionDescriptor(137, SpvOpAccessChain, 0), 208);
1113   ASSERT_TRUE(make_uvec4.IsApplicable(context.get(), transformation_context));
1114   ASSERT_FALSE(
1115       make_uvec4_bad.IsApplicable(context.get(), transformation_context));
1116   ApplyAndCheckFreshIds(make_uvec4, context.get(), &transformation_context);
1117   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1118                                                kConsoleMessageConsumer));
1119   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1120       MakeDataDescriptor(14, {}), MakeDataDescriptor(208, {0})));
1121   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1122       MakeDataDescriptor(18, {}), MakeDataDescriptor(208, {1})));
1123   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1124       MakeDataDescriptor(136, {}), MakeDataDescriptor(208, {2})));
1125   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1126       MakeDataDescriptor(136, {}), MakeDataDescriptor(208, {3})));
1127 
1128   TransformationCompositeConstruct make_bvec2(
1129       102,
1130       {
1131           111,
1132           41,
1133       },
1134       MakeInstructionDescriptor(75, SpvOpAccessChain, 0), 209);
1135   // Bad because 0 is not a valid base instruction id
1136   TransformationCompositeConstruct make_bvec2_bad(
1137       102,
1138       {
1139           111,
1140           41,
1141       },
1142       MakeInstructionDescriptor(0, SpvOpExtInstImport, 0), 209);
1143   ASSERT_TRUE(make_bvec2.IsApplicable(context.get(), transformation_context));
1144   ASSERT_FALSE(
1145       make_bvec2_bad.IsApplicable(context.get(), transformation_context));
1146   ApplyAndCheckFreshIds(make_bvec2, context.get(), &transformation_context);
1147   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1148                                                kConsoleMessageConsumer));
1149   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1150       MakeDataDescriptor(111, {}), MakeDataDescriptor(209, {0})));
1151   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1152       MakeDataDescriptor(41, {}), MakeDataDescriptor(209, {1})));
1153 
1154   TransformationCompositeConstruct make_bvec3(
1155       93, {108, 73}, MakeInstructionDescriptor(108, SpvOpStore, 0), 210);
1156   // Bad because there are too many components for a bvec3
1157   TransformationCompositeConstruct make_bvec3_bad(
1158       93, {108, 108}, MakeInstructionDescriptor(108, SpvOpStore, 0), 210);
1159   ASSERT_TRUE(make_bvec3.IsApplicable(context.get(), transformation_context));
1160   ASSERT_FALSE(
1161       make_bvec3_bad.IsApplicable(context.get(), transformation_context));
1162   ApplyAndCheckFreshIds(make_bvec3, context.get(), &transformation_context);
1163   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1164                                                kConsoleMessageConsumer));
1165   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1166       MakeDataDescriptor(108, {0}), MakeDataDescriptor(210, {0})));
1167   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1168       MakeDataDescriptor(108, {1}), MakeDataDescriptor(210, {1})));
1169   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1170       MakeDataDescriptor(73, {}), MakeDataDescriptor(210, {2})));
1171 
1172   TransformationCompositeConstruct make_bvec4(
1173       70, {108, 108}, MakeInstructionDescriptor(108, SpvOpBranch, 0), 211);
1174   // Bad because 21 is a type, not a result id
1175   TransformationCompositeConstruct make_bvec4_bad(
1176       70, {21, 108}, MakeInstructionDescriptor(108, SpvOpBranch, 0), 211);
1177   ASSERT_TRUE(make_bvec4.IsApplicable(context.get(), transformation_context));
1178   ASSERT_FALSE(
1179       make_bvec4_bad.IsApplicable(context.get(), transformation_context));
1180   ApplyAndCheckFreshIds(make_bvec4, context.get(), &transformation_context);
1181   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1182                                                kConsoleMessageConsumer));
1183   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1184       MakeDataDescriptor(108, {0}), MakeDataDescriptor(211, {0})));
1185   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1186       MakeDataDescriptor(108, {1}), MakeDataDescriptor(211, {1})));
1187   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1188       MakeDataDescriptor(108, {0}), MakeDataDescriptor(211, {2})));
1189   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1190       MakeDataDescriptor(108, {1}), MakeDataDescriptor(211, {3})));
1191 
1192   std::string after_transformation = R"(
1193                OpCapability Shader
1194           %1 = OpExtInstImport "GLSL.std.450"
1195                OpMemoryModel Logical GLSL450
1196                OpEntryPoint Fragment %4 "main"
1197                OpExecutionMode %4 OriginUpperLeft
1198                OpSource ESSL 310
1199                OpName %4 "main"
1200                OpName %9 "v2"
1201                OpName %27 "v3"
1202                OpName %46 "v4"
1203                OpName %53 "iv2"
1204                OpName %61 "uv3"
1205                OpName %72 "bv4"
1206                OpName %88 "uv2"
1207                OpName %95 "bv3"
1208                OpName %104 "bv2"
1209                OpName %116 "iv3"
1210                OpName %124 "iv4"
1211                OpName %133 "uv4"
1212           %2 = OpTypeVoid
1213           %3 = OpTypeFunction %2
1214           %6 = OpTypeFloat 32
1215           %7 = OpTypeVector %6 2
1216           %8 = OpTypePointer Function %7
1217          %10 = OpConstant %6 1
1218          %11 = OpConstant %6 2
1219          %12 = OpConstantComposite %7 %10 %11
1220          %13 = OpTypeInt 32 0
1221          %14 = OpConstant %13 0
1222          %15 = OpTypePointer Function %6
1223          %18 = OpConstant %13 1
1224          %21 = OpTypeBool
1225          %25 = OpTypeVector %6 3
1226          %26 = OpTypePointer Function %25
1227          %33 = OpConstant %6 3
1228          %34 = OpConstant %6 -0.756802499
1229          %38 = OpConstant %13 2
1230          %44 = OpTypeVector %6 4
1231          %45 = OpTypePointer Function %44
1232          %50 = OpTypeInt 32 1
1233          %51 = OpTypeVector %50 2
1234          %52 = OpTypePointer Function %51
1235          %57 = OpTypePointer Function %50
1236          %59 = OpTypeVector %13 3
1237          %60 = OpTypePointer Function %59
1238          %65 = OpConstant %13 3
1239          %67 = OpTypePointer Function %13
1240          %70 = OpTypeVector %21 4
1241          %71 = OpTypePointer Function %70
1242          %73 = OpConstantTrue %21
1243          %74 = OpTypePointer Function %21
1244          %86 = OpTypeVector %13 2
1245          %87 = OpTypePointer Function %86
1246          %93 = OpTypeVector %21 3
1247          %94 = OpTypePointer Function %93
1248         %102 = OpTypeVector %21 2
1249         %103 = OpTypePointer Function %102
1250         %111 = OpConstantFalse %21
1251         %114 = OpTypeVector %50 3
1252         %115 = OpTypePointer Function %114
1253         %117 = OpConstant %50 3
1254         %122 = OpTypeVector %50 4
1255         %123 = OpTypePointer Function %122
1256         %131 = OpTypeVector %13 4
1257         %132 = OpTypePointer Function %131
1258           %4 = OpFunction %2 None %3
1259           %5 = OpLabel
1260           %9 = OpVariable %8 Function
1261          %27 = OpVariable %26 Function
1262          %46 = OpVariable %45 Function
1263          %53 = OpVariable %52 Function
1264          %61 = OpVariable %60 Function
1265          %72 = OpVariable %71 Function
1266          %88 = OpVariable %87 Function
1267          %95 = OpVariable %94 Function
1268         %104 = OpVariable %103 Function
1269         %116 = OpVariable %115 Function
1270         %124 = OpVariable %123 Function
1271         %133 = OpVariable %132 Function
1272                OpStore %9 %12
1273         %206 = OpCompositeConstruct %86 %18 %38
1274          %16 = OpAccessChain %15 %9 %14
1275          %17 = OpLoad %6 %16
1276          %19 = OpAccessChain %15 %9 %18
1277          %20 = OpLoad %6 %19
1278          %22 = OpFOrdGreaterThan %21 %17 %20
1279                OpSelectionMerge %24 None
1280                OpBranchConditional %22 %23 %101
1281          %23 = OpLabel
1282          %28 = OpAccessChain %15 %9 %14
1283          %29 = OpLoad %6 %28
1284          %30 = OpAccessChain %15 %9 %18
1285          %31 = OpLoad %6 %30
1286          %32 = OpFAdd %6 %29 %31
1287         %201 = OpCompositeConstruct %25 %12 %32
1288          %35 = OpCompositeConstruct %25 %32 %33 %34
1289                OpStore %27 %35
1290          %36 = OpAccessChain %15 %27 %14
1291          %37 = OpLoad %6 %36
1292          %39 = OpAccessChain %15 %27 %38
1293          %40 = OpLoad %6 %39
1294          %41 = OpFOrdLessThan %21 %37 %40
1295                OpSelectionMerge %43 None
1296                OpBranchConditional %41 %42 %69
1297          %42 = OpLabel
1298          %47 = OpAccessChain %15 %9 %18
1299          %48 = OpLoad %6 %47
1300          %49 = OpAccessChain %15 %46 %14
1301                OpStore %49 %48
1302          %54 = OpAccessChain %15 %27 %38
1303          %55 = OpLoad %6 %54
1304          %56 = OpConvertFToS %50 %55
1305          %58 = OpAccessChain %57 %53 %14
1306                OpStore %58 %56
1307          %62 = OpAccessChain %15 %46 %14
1308          %63 = OpLoad %6 %62
1309          %64 = OpConvertFToU %13 %63
1310         %205 = OpCompositeConstruct %122 %56 %117 %117 %117
1311          %66 = OpIAdd %13 %64 %65
1312         %204 = OpCompositeConstruct %114 %56 %117 %56
1313          %68 = OpAccessChain %67 %61 %14
1314                OpStore %68 %66
1315                OpBranch %43
1316          %69 = OpLabel
1317         %202 = OpCompositeConstruct %44 %32 %32 %10 %11
1318         %209 = OpCompositeConstruct %102 %111 %41
1319          %75 = OpAccessChain %74 %72 %14
1320                OpStore %75 %73
1321          %76 = OpAccessChain %74 %72 %14
1322          %77 = OpLoad %21 %76
1323          %78 = OpLogicalNot %21 %77
1324          %79 = OpAccessChain %74 %72 %18
1325                OpStore %79 %78
1326          %80 = OpAccessChain %74 %72 %14
1327          %81 = OpLoad %21 %80
1328          %82 = OpAccessChain %74 %72 %18
1329          %83 = OpLoad %21 %82
1330          %84 = OpLogicalAnd %21 %81 %83
1331          %85 = OpAccessChain %74 %72 %38
1332                OpStore %85 %84
1333          %89 = OpAccessChain %67 %88 %14
1334          %90 = OpLoad %13 %89
1335          %91 = OpINotEqual %21 %90 %14
1336          %92 = OpAccessChain %74 %72 %65
1337                OpStore %92 %91
1338                OpBranch %43
1339          %43 = OpLabel
1340          %96 = OpLoad %70 %72
1341          %97 = OpCompositeExtract %21 %96 0
1342          %98 = OpCompositeExtract %21 %96 1
1343          %99 = OpCompositeExtract %21 %96 2
1344         %100 = OpCompositeConstruct %93 %97 %98 %99
1345         %200 = OpCompositeConstruct %7 %17 %11
1346                OpStore %95 %100
1347                OpBranch %24
1348         %101 = OpLabel
1349         %105 = OpAccessChain %67 %88 %14
1350         %106 = OpLoad %13 %105
1351         %107 = OpINotEqual %21 %106 %14
1352         %108 = OpCompositeConstruct %102 %107 %107
1353         %210 = OpCompositeConstruct %93 %108 %73
1354                OpStore %104 %108
1355         %211 = OpCompositeConstruct %70 %108 %108
1356                OpBranch %24
1357          %24 = OpLabel
1358         %109 = OpAccessChain %74 %104 %18
1359         %110 = OpLoad %21 %109
1360         %112 = OpLogicalOr %21 %110 %111
1361         %113 = OpAccessChain %74 %104 %14
1362                OpStore %113 %112
1363         %118 = OpAccessChain %57 %116 %14
1364                OpStore %118 %117
1365         %119 = OpAccessChain %57 %116 %14
1366         %120 = OpLoad %50 %119
1367         %121 = OpAccessChain %57 %53 %18
1368                OpStore %121 %120
1369         %125 = OpAccessChain %57 %116 %14
1370         %126 = OpLoad %50 %125
1371         %127 = OpAccessChain %57 %53 %18
1372         %203 = OpCompositeConstruct %51 %126 %120
1373         %128 = OpLoad %50 %127
1374         %129 = OpIAdd %50 %126 %128
1375         %130 = OpAccessChain %57 %124 %65
1376                OpStore %130 %129
1377         %134 = OpAccessChain %57 %116 %14
1378         %135 = OpLoad %50 %134
1379         %136 = OpBitcast %13 %135
1380         %208 = OpCompositeConstruct %131 %14 %18 %136 %136
1381         %137 = OpAccessChain %67 %133 %14
1382                OpStore %137 %136
1383         %207 = OpCompositeConstruct %59 %14 %18 %136
1384                OpReturn
1385                OpFunctionEnd
1386   )";
1387 
1388   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
1389 }
1390 
TEST(TransformationCompositeConstructTest,AddSynonymsForRelevantIds)1391 TEST(TransformationCompositeConstructTest, AddSynonymsForRelevantIds) {
1392   std::string shader = R"(
1393                OpCapability Shader
1394           %1 = OpExtInstImport "GLSL.std.450"
1395                OpMemoryModel Logical GLSL450
1396                OpEntryPoint Fragment %4 "main"
1397                OpExecutionMode %4 OriginUpperLeft
1398                OpSource ESSL 310
1399           %2 = OpTypeVoid
1400           %3 = OpTypeFunction %2
1401           %6 = OpTypeFloat 32
1402           %7 = OpTypeVector %6 3
1403           %8 = OpTypePointer Function %7
1404          %10 = OpConstant %6 1
1405          %11 = OpConstantComposite %7 %10 %10 %10
1406          %17 = OpTypeVector %6 4
1407          %18 = OpTypePointer Function %17
1408          %21 = OpConstant %6 2
1409          %32 = OpTypeMatrix %17 3
1410          %33 = OpTypePointer Private %32
1411          %34 = OpVariable %33 Private
1412          %35 = OpTypeMatrix %7 4
1413          %36 = OpTypePointer Private %35
1414          %37 = OpVariable %36 Private
1415          %38 = OpTypeVector %6 2
1416          %39 = OpTypeInt 32 0
1417          %40 = OpConstant %39 3
1418          %41 = OpTypeArray %38 %40
1419          %42 = OpTypePointer Private %41
1420          %43 = OpVariable %42 Private
1421         %100 = OpUndef %7
1422         %101 = OpUndef %17
1423           %4 = OpFunction %2 None %3
1424           %5 = OpLabel
1425           %9 = OpVariable %8 Function
1426          %12 = OpVariable %8 Function
1427          %14 = OpVariable %8 Function
1428          %19 = OpVariable %18 Function
1429          %26 = OpVariable %18 Function
1430          %29 = OpVariable %18 Function
1431                OpStore %9 %11
1432          %13 = OpLoad %7 %9
1433                OpStore %12 %13
1434          %15 = OpLoad %7 %12
1435          %16 = OpVectorShuffle %7 %15 %15 2 1 0
1436                OpStore %14 %16
1437          %20 = OpLoad %7 %14
1438          %22 = OpCompositeExtract %6 %20 0
1439          %23 = OpCompositeExtract %6 %20 1
1440          %24 = OpCompositeExtract %6 %20 2
1441          %25 = OpCompositeConstruct %17 %22 %23 %24 %21
1442                OpStore %19 %25
1443          %27 = OpLoad %17 %19
1444          %28 = OpVectorShuffle %17 %27 %27 3 2 1 0
1445                OpStore %26 %28
1446          %30 = OpLoad %7 %9
1447          %31 = OpVectorShuffle %17 %30 %30 0 0 1 1
1448                OpStore %29 %31
1449                OpReturn
1450                OpFunctionEnd
1451   )";
1452 
1453   const auto env = SPV_ENV_UNIVERSAL_1_3;
1454   const auto consumer = nullptr;
1455   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1456   spvtools::ValidatorOptions validator_options;
1457   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1458                                                kConsoleMessageConsumer));
1459   TransformationContext transformation_context(
1460       MakeUnique<FactManager>(context.get()), validator_options);
1461   TransformationCompositeConstruct transformation(
1462       32, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200);
1463   ASSERT_TRUE(
1464       transformation.IsApplicable(context.get(), transformation_context));
1465   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1466   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1467                                                kConsoleMessageConsumer));
1468   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1469       MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0})));
1470   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1471       MakeDataDescriptor(28, {}), MakeDataDescriptor(200, {1})));
1472 }
1473 
TEST(TransformationCompositeConstructTest,DontAddSynonymsForIrrelevantIds)1474 TEST(TransformationCompositeConstructTest, DontAddSynonymsForIrrelevantIds) {
1475   std::string shader = R"(
1476                OpCapability Shader
1477           %1 = OpExtInstImport "GLSL.std.450"
1478                OpMemoryModel Logical GLSL450
1479                OpEntryPoint Fragment %4 "main"
1480                OpExecutionMode %4 OriginUpperLeft
1481                OpSource ESSL 310
1482           %2 = OpTypeVoid
1483           %3 = OpTypeFunction %2
1484           %6 = OpTypeFloat 32
1485           %7 = OpTypeVector %6 3
1486           %8 = OpTypePointer Function %7
1487          %10 = OpConstant %6 1
1488          %11 = OpConstantComposite %7 %10 %10 %10
1489          %17 = OpTypeVector %6 4
1490          %18 = OpTypePointer Function %17
1491          %21 = OpConstant %6 2
1492          %32 = OpTypeMatrix %17 3
1493          %33 = OpTypePointer Private %32
1494          %34 = OpVariable %33 Private
1495          %35 = OpTypeMatrix %7 4
1496          %36 = OpTypePointer Private %35
1497          %37 = OpVariable %36 Private
1498          %38 = OpTypeVector %6 2
1499          %39 = OpTypeInt 32 0
1500          %40 = OpConstant %39 3
1501          %41 = OpTypeArray %38 %40
1502          %42 = OpTypePointer Private %41
1503          %43 = OpVariable %42 Private
1504         %100 = OpUndef %7
1505         %101 = OpUndef %17
1506           %4 = OpFunction %2 None %3
1507           %5 = OpLabel
1508           %9 = OpVariable %8 Function
1509          %12 = OpVariable %8 Function
1510          %14 = OpVariable %8 Function
1511          %19 = OpVariable %18 Function
1512          %26 = OpVariable %18 Function
1513          %29 = OpVariable %18 Function
1514                OpStore %9 %11
1515          %13 = OpLoad %7 %9
1516                OpStore %12 %13
1517          %15 = OpLoad %7 %12
1518          %16 = OpVectorShuffle %7 %15 %15 2 1 0
1519                OpStore %14 %16
1520          %20 = OpLoad %7 %14
1521          %22 = OpCompositeExtract %6 %20 0
1522          %23 = OpCompositeExtract %6 %20 1
1523          %24 = OpCompositeExtract %6 %20 2
1524          %25 = OpCompositeConstruct %17 %22 %23 %24 %21
1525                OpStore %19 %25
1526          %27 = OpLoad %17 %19
1527          %28 = OpVectorShuffle %17 %27 %27 3 2 1 0
1528                OpStore %26 %28
1529          %30 = OpLoad %7 %9
1530          %31 = OpVectorShuffle %17 %30 %30 0 0 1 1
1531                OpStore %29 %31
1532                OpReturn
1533                OpFunctionEnd
1534   )";
1535 
1536   const auto env = SPV_ENV_UNIVERSAL_1_3;
1537   const auto consumer = nullptr;
1538   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1539   spvtools::ValidatorOptions validator_options;
1540   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1541                                                kConsoleMessageConsumer));
1542   TransformationContext transformation_context(
1543       MakeUnique<FactManager>(context.get()), validator_options);
1544   transformation_context.GetFactManager()->AddFactIdIsIrrelevant(25);
1545 
1546   TransformationCompositeConstruct transformation(
1547       32, {25, 28, 31}, MakeInstructionDescriptor(31, SpvOpReturn, 0), 200);
1548   ASSERT_TRUE(
1549       transformation.IsApplicable(context.get(), transformation_context));
1550   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1551   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1552                                                kConsoleMessageConsumer));
1553   ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
1554       MakeDataDescriptor(25, {}), MakeDataDescriptor(200, {0})));
1555   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1556       MakeDataDescriptor(28, {}), MakeDataDescriptor(200, {1})));
1557   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1558       MakeDataDescriptor(31, {}), MakeDataDescriptor(200, {2})));
1559 }
1560 
TEST(TransformationCompositeConstructTest,DontAddSynonymsInDeadBlock)1561 TEST(TransformationCompositeConstructTest, DontAddSynonymsInDeadBlock) {
1562   std::string shader = R"(
1563                OpCapability Shader
1564           %1 = OpExtInstImport "GLSL.std.450"
1565                OpMemoryModel Logical GLSL450
1566                OpEntryPoint Fragment %4 "main"
1567                OpExecutionMode %4 OriginUpperLeft
1568                OpSource ESSL 320
1569           %2 = OpTypeVoid
1570           %3 = OpTypeFunction %2
1571           %6 = OpTypeInt 32 1
1572           %7 = OpTypeVector %6 2
1573           %8 = OpTypePointer Function %7
1574          %10 = OpConstant %6 0
1575          %11 = OpConstant %6 1
1576          %12 = OpConstantComposite %7 %10 %11
1577          %13 = OpTypeBool
1578          %14 = OpConstantFalse %13
1579           %4 = OpFunction %2 None %3
1580           %5 = OpLabel
1581           %9 = OpVariable %8 Function
1582                OpStore %9 %12
1583                OpSelectionMerge %16 None
1584                OpBranchConditional %14 %15 %16
1585          %15 = OpLabel
1586                OpBranch %16
1587          %16 = OpLabel
1588                OpReturn
1589                OpFunctionEnd
1590   )";
1591 
1592   const auto env = SPV_ENV_UNIVERSAL_1_3;
1593   const auto consumer = nullptr;
1594   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1595   spvtools::ValidatorOptions validator_options;
1596   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1597                                                kConsoleMessageConsumer));
1598   TransformationContext transformation_context(
1599       MakeUnique<FactManager>(context.get()), validator_options);
1600   transformation_context.GetFactManager()->AddFactBlockIsDead(15);
1601 
1602   TransformationCompositeConstruct transformation(
1603       7, {10, 11}, MakeInstructionDescriptor(15, SpvOpBranch, 0), 100);
1604   ASSERT_TRUE(
1605       transformation.IsApplicable(context.get(), transformation_context));
1606   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1607   ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
1608       MakeDataDescriptor(100, {0}), MakeDataDescriptor(10, {})));
1609   ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
1610       MakeDataDescriptor(100, {1}), MakeDataDescriptor(11, {})));
1611 }
1612 
TEST(TransformationCompositeConstructTest,OneIrrelevantComponent)1613 TEST(TransformationCompositeConstructTest, OneIrrelevantComponent) {
1614   std::string shader = R"(
1615                OpCapability Shader
1616           %1 = OpExtInstImport "GLSL.std.450"
1617                OpMemoryModel Logical GLSL450
1618                OpEntryPoint Fragment %4 "main"
1619                OpExecutionMode %4 OriginUpperLeft
1620                OpSource ESSL 320
1621           %2 = OpTypeVoid
1622           %3 = OpTypeFunction %2
1623           %6 = OpTypeInt 32 1
1624           %7 = OpTypeStruct %6 %6 %6
1625           %8 = OpConstant %6 42
1626           %9 = OpConstant %6 50
1627          %10 = OpConstant %6 51
1628           %4 = OpFunction %2 None %3
1629           %5 = OpLabel
1630                OpReturn
1631                OpFunctionEnd
1632   )";
1633 
1634   const auto env = SPV_ENV_UNIVERSAL_1_3;
1635   const auto consumer = nullptr;
1636   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1637   spvtools::ValidatorOptions validator_options;
1638   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1639                                                kConsoleMessageConsumer));
1640   TransformationContext transformation_context(
1641       MakeUnique<FactManager>(context.get()), validator_options);
1642   transformation_context.GetFactManager()->AddFactIdIsIrrelevant(8);
1643 
1644   TransformationCompositeConstruct transformation(
1645       7, {8, 9, 10}, MakeInstructionDescriptor(5, SpvOpReturn, 0), 100);
1646   ASSERT_TRUE(
1647       transformation.IsApplicable(context.get(), transformation_context));
1648   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1649   ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
1650       MakeDataDescriptor(100, {0}), MakeDataDescriptor(8, {})));
1651   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1652       MakeDataDescriptor(100, {1}), MakeDataDescriptor(9, {})));
1653   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1654       MakeDataDescriptor(100, {2}), MakeDataDescriptor(10, {})));
1655 }
1656 
TEST(TransformationCompositeConstructTest,IrrelevantVec2ThenFloat)1657 TEST(TransformationCompositeConstructTest, IrrelevantVec2ThenFloat) {
1658   std::string shader = R"(
1659                OpCapability Shader
1660           %1 = OpExtInstImport "GLSL.std.450"
1661                OpMemoryModel Logical GLSL450
1662                OpEntryPoint Fragment %4 "main"
1663                OpExecutionMode %4 OriginUpperLeft
1664                OpSource ESSL 320
1665           %2 = OpTypeVoid
1666           %3 = OpTypeFunction %2
1667           %6 = OpTypeFloat 32
1668           %7 = OpTypeVector %6 2
1669           %8 = OpTypeVector %6 3
1670           %9 = OpConstant %6 0
1671          %11 = OpConstant %6 1
1672          %12 = OpConstant %6 2
1673          %10 = OpConstantComposite %7 %11 %12
1674           %4 = OpFunction %2 None %3
1675           %5 = OpLabel
1676                OpReturn
1677                OpFunctionEnd
1678   )";
1679 
1680   const auto env = SPV_ENV_UNIVERSAL_1_3;
1681   const auto consumer = nullptr;
1682   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1683   spvtools::ValidatorOptions validator_options;
1684   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1685                                                kConsoleMessageConsumer));
1686   TransformationContext transformation_context(
1687       MakeUnique<FactManager>(context.get()), validator_options);
1688 
1689   transformation_context.GetFactManager()->AddFactIdIsIrrelevant(10);
1690 
1691   TransformationCompositeConstruct transformation(
1692       8, {10, 9}, MakeInstructionDescriptor(5, SpvOpReturn, 0), 100);
1693   ASSERT_TRUE(
1694       transformation.IsApplicable(context.get(), transformation_context));
1695   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
1696   ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
1697       MakeDataDescriptor(100, {0}), MakeDataDescriptor(10, {0})));
1698   ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
1699       MakeDataDescriptor(100, {1}), MakeDataDescriptor(10, {1})));
1700   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1701       MakeDataDescriptor(100, {2}), MakeDataDescriptor(9, {})));
1702   ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
1703       MakeDataDescriptor(100, {1}), MakeDataDescriptor(9, {})));
1704 }
1705 
1706 }  // namespace
1707 }  // namespace fuzz
1708 }  // namespace spvtools
1709