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