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