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/data_descriptor.h"
16 
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "source/fuzz/id_use_descriptor.h"
20 #include "source/fuzz/instruction_descriptor.h"
21 #include "source/fuzz/transformation_composite_extract.h"
22 #include "source/fuzz/transformation_replace_id_with_synonym.h"
23 #include "source/fuzz/transformation_vector_shuffle.h"
24 #include "test/fuzz/fuzz_test_util.h"
25 
26 namespace spvtools {
27 namespace fuzz {
28 namespace {
29 
30 // This file captures tests that check correctness of the collective use of a
31 // number of transformations that relate to data synonyms.
32 
MakeSynonymFact(uint32_t first_id,const std::vector<uint32_t> & first_indices,uint32_t second_id,const std::vector<uint32_t> & second_indices)33 protobufs::Fact MakeSynonymFact(uint32_t first_id,
34                                 const std::vector<uint32_t>& first_indices,
35                                 uint32_t second_id,
36                                 const std::vector<uint32_t>& second_indices) {
37   protobufs::FactDataSynonym data_synonym_fact;
38   *data_synonym_fact.mutable_data1() =
39       MakeDataDescriptor(first_id, first_indices);
40   *data_synonym_fact.mutable_data2() =
41       MakeDataDescriptor(second_id, second_indices);
42   protobufs::Fact result;
43   *result.mutable_data_synonym_fact() = data_synonym_fact;
44   return result;
45 }
46 
TEST(DataSynonymTransformationTest,ArrayCompositeSynonyms)47 TEST(DataSynonymTransformationTest, ArrayCompositeSynonyms) {
48   std::string shader = R"(
49                OpCapability Shader
50           %1 = OpExtInstImport "GLSL.std.450"
51                OpMemoryModel Logical GLSL450
52                OpEntryPoint Fragment %4 "main"
53                OpExecutionMode %4 OriginUpperLeft
54                OpSource ESSL 310
55                OpName %4 "main"
56                OpName %11 "A"
57                OpName %20 "B"
58                OpName %31 "g"
59                OpName %35 "h"
60                OpDecorate %11 RelaxedPrecision
61                OpDecorate %22 RelaxedPrecision
62                OpDecorate %27 RelaxedPrecision
63                OpDecorate %35 RelaxedPrecision
64                OpDecorate %36 RelaxedPrecision
65                OpDecorate %40 RelaxedPrecision
66                OpDecorate %41 RelaxedPrecision
67           %2 = OpTypeVoid
68           %3 = OpTypeFunction %2
69           %6 = OpTypeInt 32 1
70           %7 = OpTypeInt 32 0
71           %8 = OpConstant %7 3
72           %9 = OpTypeArray %6 %8
73          %10 = OpTypePointer Function %9
74          %12 = OpConstant %6 0
75          %13 = OpConstant %6 3
76          %14 = OpTypePointer Function %6
77          %16 = OpTypeFloat 32
78          %17 = OpConstant %7 4
79          %18 = OpTypeArray %16 %17
80          %19 = OpTypePointer Function %18
81          %24 = OpTypePointer Function %16
82          %28 = OpConstant %16 42
83          %30 = OpConstant %6 2
84          %34 = OpConstant %6 1
85          %38 = OpConstant %6 42
86           %4 = OpFunction %2 None %3
87           %5 = OpLabel
88          %11 = OpVariable %10 Function
89          %20 = OpVariable %19 Function
90          %31 = OpVariable %24 Function
91          %35 = OpVariable %14 Function
92          %15 = OpAccessChain %14 %11 %12
93          %21 = OpAccessChain %14 %11 %12
94          %22 = OpLoad %6 %21
95         %100 = OpCompositeConstruct %9 %12 %13 %22
96                OpStore %15 %13
97          %23 = OpConvertSToF %16 %22
98          %25 = OpAccessChain %24 %20 %12
99                OpStore %25 %23
100          %26 = OpAccessChain %14 %11 %12
101          %27 = OpLoad %6 %26
102          %29 = OpAccessChain %24 %20 %27
103                OpStore %29 %28
104          %32 = OpLoad %16 %31
105         %101 = OpCompositeConstruct %18 %28 %23 %32 %23
106          %50 = OpCopyObject %16 %23
107          %51 = OpCopyObject %16 %23
108          %33 = OpAccessChain %24 %20 %30
109                OpStore %33 %28
110                OpStore %33 %32
111          %36 = OpLoad %6 %35
112          %37 = OpAccessChain %14 %11 %34
113                OpStore %37 %36
114          %39 = OpAccessChain %14 %11 %12
115          %40 = OpLoad %6 %39
116          %41 = OpIAdd %6 %38 %40
117          %42 = OpAccessChain %14 %11 %30
118                OpStore %42 %41
119                OpReturn
120                OpFunctionEnd
121   )";
122 
123   const auto env = SPV_ENV_UNIVERSAL_1_3;
124   const auto consumer = nullptr;
125   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
126   spvtools::ValidatorOptions validator_options;
127   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
128                                                kConsoleMessageConsumer));
129   TransformationContext transformation_context(
130       MakeUnique<FactManager>(context.get()), validator_options);
131 
132   transformation_context.GetFactManager()->MaybeAddFact(
133       MakeSynonymFact(12, {}, 100, {0}));
134   transformation_context.GetFactManager()->MaybeAddFact(
135       MakeSynonymFact(13, {}, 100, {1}));
136   transformation_context.GetFactManager()->MaybeAddFact(
137       MakeSynonymFact(22, {}, 100, {2}));
138   transformation_context.GetFactManager()->MaybeAddFact(
139       MakeSynonymFact(28, {}, 101, {0}));
140   transformation_context.GetFactManager()->MaybeAddFact(
141       MakeSynonymFact(23, {}, 101, {1}));
142   transformation_context.GetFactManager()->MaybeAddFact(
143       MakeSynonymFact(32, {}, 101, {2}));
144   transformation_context.GetFactManager()->MaybeAddFact(
145       MakeSynonymFact(23, {}, 101, {3}));
146 
147   // Replace %12 with %100[0] in '%25 = OpAccessChain %24 %20 %12'
148   auto instruction_descriptor_1 =
149       MakeInstructionDescriptor(25, SpvOpAccessChain, 0);
150   auto good_extract_1 =
151       TransformationCompositeExtract(instruction_descriptor_1, 102, 100, {0});
152   // Bad: id already in use
153   auto bad_extract_1 = TransformationCompositeExtract(
154       MakeInstructionDescriptor(25, SpvOpAccessChain, 0), 25, 100, {0});
155   ASSERT_TRUE(
156       good_extract_1.IsApplicable(context.get(), transformation_context));
157   ASSERT_FALSE(
158       bad_extract_1.IsApplicable(context.get(), transformation_context));
159   good_extract_1.Apply(context.get(), &transformation_context);
160   auto replacement_1 = TransformationReplaceIdWithSynonym(
161       MakeIdUseDescriptor(12, instruction_descriptor_1, 1), 102);
162   ASSERT_TRUE(
163       replacement_1.IsApplicable(context.get(), transformation_context));
164   replacement_1.Apply(context.get(), &transformation_context);
165   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
166                                                kConsoleMessageConsumer));
167 
168   // Replace %13 with %100[1] in 'OpStore %15 %13'
169   auto instruction_descriptor_2 = MakeInstructionDescriptor(100, SpvOpStore, 0);
170   auto good_extract_2 =
171       TransformationCompositeExtract(instruction_descriptor_2, 103, 100, {1});
172   // No bad example provided here.
173   ASSERT_TRUE(
174       good_extract_2.IsApplicable(context.get(), transformation_context));
175   good_extract_2.Apply(context.get(), &transformation_context);
176   auto replacement_2 = TransformationReplaceIdWithSynonym(
177       MakeIdUseDescriptor(13, instruction_descriptor_2, 1), 103);
178   ASSERT_TRUE(
179       replacement_2.IsApplicable(context.get(), transformation_context));
180   replacement_2.Apply(context.get(), &transformation_context);
181   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
182                                                kConsoleMessageConsumer));
183 
184   // Replace %22 with %100[2] in '%23 = OpConvertSToF %16 %22'
185   auto instruction_descriptor_3 =
186       MakeInstructionDescriptor(23, SpvOpConvertSToF, 0);
187   auto good_extract_3 =
188       TransformationCompositeExtract(instruction_descriptor_3, 104, 100, {2});
189   ASSERT_TRUE(
190       good_extract_3.IsApplicable(context.get(), transformation_context));
191   good_extract_3.Apply(context.get(), &transformation_context);
192   auto replacement_3 = TransformationReplaceIdWithSynonym(
193       MakeIdUseDescriptor(22, instruction_descriptor_3, 0), 104);
194   // Bad: wrong input operand index
195   auto bad_replacement_3 = TransformationReplaceIdWithSynonym(
196       MakeIdUseDescriptor(22, instruction_descriptor_3, 1), 104);
197   ASSERT_TRUE(
198       replacement_3.IsApplicable(context.get(), transformation_context));
199   ASSERT_FALSE(
200       bad_replacement_3.IsApplicable(context.get(), transformation_context));
201   replacement_3.Apply(context.get(), &transformation_context);
202   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
203                                                kConsoleMessageConsumer));
204 
205   // Replace %28 with %101[0] in 'OpStore %33 %28'
206   auto instruction_descriptor_4 = MakeInstructionDescriptor(33, SpvOpStore, 0);
207   auto good_extract_4 =
208       TransformationCompositeExtract(instruction_descriptor_4, 105, 101, {0});
209   // Bad: instruction descriptor does not identify an appropriate instruction
210   auto bad_extract_4 = TransformationCompositeExtract(
211       MakeInstructionDescriptor(33, SpvOpCopyObject, 0), 105, 101, {0});
212   ASSERT_TRUE(
213       good_extract_4.IsApplicable(context.get(), transformation_context));
214   ASSERT_FALSE(
215       bad_extract_4.IsApplicable(context.get(), transformation_context));
216   good_extract_4.Apply(context.get(), &transformation_context);
217   auto replacement_4 = TransformationReplaceIdWithSynonym(
218       MakeIdUseDescriptor(28, instruction_descriptor_4, 1), 105);
219   ASSERT_TRUE(
220       replacement_4.IsApplicable(context.get(), transformation_context));
221   replacement_4.Apply(context.get(), &transformation_context);
222   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
223                                                kConsoleMessageConsumer));
224 
225   // Replace %23 with %101[1] in '%50 = OpCopyObject %16 %23'
226   auto instruction_descriptor_5 =
227       MakeInstructionDescriptor(50, SpvOpCopyObject, 0);
228   auto good_extract_5 =
229       TransformationCompositeExtract(instruction_descriptor_5, 106, 101, {1});
230   ASSERT_TRUE(
231       good_extract_5.IsApplicable(context.get(), transformation_context));
232   good_extract_5.Apply(context.get(), &transformation_context);
233   auto replacement_5 = TransformationReplaceIdWithSynonym(
234       MakeIdUseDescriptor(23, instruction_descriptor_5, 0), 106);
235   // Bad: wrong synonym fact being used
236   auto bad_replacement_5 = TransformationReplaceIdWithSynonym(
237       MakeIdUseDescriptor(23, instruction_descriptor_5, 0), 105);
238   ASSERT_TRUE(
239       replacement_5.IsApplicable(context.get(), transformation_context));
240   ASSERT_FALSE(
241       bad_replacement_5.IsApplicable(context.get(), transformation_context));
242   replacement_5.Apply(context.get(), &transformation_context);
243   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
244                                                kConsoleMessageConsumer));
245 
246   // Replace %32 with %101[2] in 'OpStore %33 %32'
247   auto instruction_descriptor_6 = MakeInstructionDescriptor(33, SpvOpStore, 1);
248   auto good_extract_6 =
249       TransformationCompositeExtract(instruction_descriptor_6, 107, 101, {2});
250   // Bad: id 1001 does not exist
251   auto bad_extract_6 =
252       TransformationCompositeExtract(instruction_descriptor_6, 107, 1001, {2});
253   ASSERT_TRUE(
254       good_extract_6.IsApplicable(context.get(), transformation_context));
255   ASSERT_FALSE(
256       bad_extract_6.IsApplicable(context.get(), transformation_context));
257   good_extract_6.Apply(context.get(), &transformation_context);
258   auto replacement_6 = TransformationReplaceIdWithSynonym(
259       MakeIdUseDescriptor(32, instruction_descriptor_6, 1), 107);
260   ASSERT_TRUE(
261       replacement_6.IsApplicable(context.get(), transformation_context));
262   replacement_6.Apply(context.get(), &transformation_context);
263   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
264                                                kConsoleMessageConsumer));
265 
266   // Replace %23 with %101[3] in '%51 = OpCopyObject %16 %23'
267   auto instruction_descriptor_7 =
268       MakeInstructionDescriptor(51, SpvOpCopyObject, 0);
269   auto good_extract_7 =
270       TransformationCompositeExtract(instruction_descriptor_7, 108, 101, {3});
271   ASSERT_TRUE(
272       good_extract_7.IsApplicable(context.get(), transformation_context));
273   good_extract_7.Apply(context.get(), &transformation_context);
274   auto replacement_7 = TransformationReplaceIdWithSynonym(
275       MakeIdUseDescriptor(23, instruction_descriptor_7, 0), 108);
276   // Bad: use id 0 is invalid
277   auto bad_replacement_7 = TransformationReplaceIdWithSynonym(
278       MakeIdUseDescriptor(0, instruction_descriptor_7, 0), 108);
279   ASSERT_TRUE(
280       replacement_7.IsApplicable(context.get(), transformation_context));
281   ASSERT_FALSE(
282       bad_replacement_7.IsApplicable(context.get(), transformation_context));
283   replacement_7.Apply(context.get(), &transformation_context);
284   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
285                                                kConsoleMessageConsumer));
286 
287   const std::string after_transformation = R"(
288                OpCapability Shader
289           %1 = OpExtInstImport "GLSL.std.450"
290                OpMemoryModel Logical GLSL450
291                OpEntryPoint Fragment %4 "main"
292                OpExecutionMode %4 OriginUpperLeft
293                OpSource ESSL 310
294                OpName %4 "main"
295                OpName %11 "A"
296                OpName %20 "B"
297                OpName %31 "g"
298                OpName %35 "h"
299                OpDecorate %11 RelaxedPrecision
300                OpDecorate %22 RelaxedPrecision
301                OpDecorate %27 RelaxedPrecision
302                OpDecorate %35 RelaxedPrecision
303                OpDecorate %36 RelaxedPrecision
304                OpDecorate %40 RelaxedPrecision
305                OpDecorate %41 RelaxedPrecision
306           %2 = OpTypeVoid
307           %3 = OpTypeFunction %2
308           %6 = OpTypeInt 32 1
309           %7 = OpTypeInt 32 0
310           %8 = OpConstant %7 3
311           %9 = OpTypeArray %6 %8
312          %10 = OpTypePointer Function %9
313          %12 = OpConstant %6 0
314          %13 = OpConstant %6 3
315          %14 = OpTypePointer Function %6
316          %16 = OpTypeFloat 32
317          %17 = OpConstant %7 4
318          %18 = OpTypeArray %16 %17
319          %19 = OpTypePointer Function %18
320          %24 = OpTypePointer Function %16
321          %28 = OpConstant %16 42
322          %30 = OpConstant %6 2
323          %34 = OpConstant %6 1
324          %38 = OpConstant %6 42
325           %4 = OpFunction %2 None %3
326           %5 = OpLabel
327          %11 = OpVariable %10 Function
328          %20 = OpVariable %19 Function
329          %31 = OpVariable %24 Function
330          %35 = OpVariable %14 Function
331          %15 = OpAccessChain %14 %11 %12
332          %21 = OpAccessChain %14 %11 %12
333          %22 = OpLoad %6 %21
334         %100 = OpCompositeConstruct %9 %12 %13 %22
335         %103 = OpCompositeExtract %6 %100 1
336                OpStore %15 %103
337         %104 = OpCompositeExtract %6 %100 2
338          %23 = OpConvertSToF %16 %104
339         %102 = OpCompositeExtract %6 %100 0
340          %25 = OpAccessChain %24 %20 %102
341                OpStore %25 %23
342          %26 = OpAccessChain %14 %11 %12
343          %27 = OpLoad %6 %26
344          %29 = OpAccessChain %24 %20 %27
345                OpStore %29 %28
346          %32 = OpLoad %16 %31
347         %101 = OpCompositeConstruct %18 %28 %23 %32 %23
348         %106 = OpCompositeExtract %16 %101 1
349          %50 = OpCopyObject %16 %106
350         %108 = OpCompositeExtract %16 %101 3
351          %51 = OpCopyObject %16 %108
352          %33 = OpAccessChain %24 %20 %30
353         %105 = OpCompositeExtract %16 %101 0
354                OpStore %33 %105
355         %107 = OpCompositeExtract %16 %101 2
356                OpStore %33 %107
357          %36 = OpLoad %6 %35
358          %37 = OpAccessChain %14 %11 %34
359                OpStore %37 %36
360          %39 = OpAccessChain %14 %11 %12
361          %40 = OpLoad %6 %39
362          %41 = OpIAdd %6 %38 %40
363          %42 = OpAccessChain %14 %11 %30
364                OpStore %42 %41
365                OpReturn
366                OpFunctionEnd
367   )";
368 
369   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
370 }
371 
TEST(DataSynonymTransformationTest,MatrixCompositeSynonyms)372 TEST(DataSynonymTransformationTest, MatrixCompositeSynonyms) {
373   std::string shader = R"(
374                OpCapability Shader
375           %1 = OpExtInstImport "GLSL.std.450"
376                OpMemoryModel Logical GLSL450
377                OpEntryPoint Fragment %4 "main"
378                OpExecutionMode %4 OriginUpperLeft
379                OpSource ESSL 310
380                OpName %4 "main"
381                OpName %10 "m"
382           %2 = OpTypeVoid
383           %3 = OpTypeFunction %2
384           %6 = OpTypeFloat 32
385           %7 = OpTypeVector %6 4
386          %50 = OpUndef %7
387           %8 = OpTypeMatrix %7 3
388           %9 = OpTypePointer Function %8
389          %11 = OpTypeInt 32 1
390          %12 = OpConstant %11 0
391          %13 = OpConstant %6 1
392          %14 = OpConstantComposite %7 %13 %13 %13 %13
393          %15 = OpTypePointer Function %7
394          %17 = OpConstant %11 1
395          %18 = OpConstant %6 2
396          %19 = OpConstantComposite %7 %18 %18 %18 %18
397          %21 = OpConstant %11 2
398           %4 = OpFunction %2 None %3
399           %5 = OpLabel
400          %10 = OpVariable %9 Function
401          %16 = OpAccessChain %15 %10 %12
402                OpStore %16 %14
403          %20 = OpAccessChain %15 %10 %17
404                OpStore %20 %19
405          %22 = OpAccessChain %15 %10 %12
406          %23 = OpLoad %7 %22
407          %24 = OpAccessChain %15 %10 %17
408          %25 = OpLoad %7 %24
409         %100 = OpCompositeConstruct %8 %23 %25 %50
410          %26 = OpFAdd %7 %23 %25
411          %27 = OpAccessChain %15 %10 %21
412                OpStore %27 %26
413                OpReturn
414                OpFunctionEnd
415   )";
416 
417   const auto env = SPV_ENV_UNIVERSAL_1_3;
418   const auto consumer = nullptr;
419   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
420   spvtools::ValidatorOptions validator_options;
421   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
422                                                kConsoleMessageConsumer));
423   TransformationContext transformation_context(
424       MakeUnique<FactManager>(context.get()), validator_options);
425 
426   transformation_context.GetFactManager()->MaybeAddFact(
427       MakeSynonymFact(23, {}, 100, {0}));
428   transformation_context.GetFactManager()->MaybeAddFact(
429       MakeSynonymFact(25, {}, 100, {1}));
430   transformation_context.GetFactManager()->MaybeAddFact(
431       MakeSynonymFact(50, {}, 100, {2}));
432 
433   // Replace %23 with %100[0] in '%26 = OpFAdd %7 %23 %25'
434   auto instruction_descriptor_1 = MakeInstructionDescriptor(26, SpvOpFAdd, 0);
435   auto extract_1 =
436       TransformationCompositeExtract(instruction_descriptor_1, 101, 100, {0});
437   ASSERT_TRUE(extract_1.IsApplicable(context.get(), transformation_context));
438   extract_1.Apply(context.get(), &transformation_context);
439   auto replacement_1 = TransformationReplaceIdWithSynonym(
440       MakeIdUseDescriptor(23, instruction_descriptor_1, 0), 101);
441   ASSERT_TRUE(
442       replacement_1.IsApplicable(context.get(), transformation_context));
443   replacement_1.Apply(context.get(), &transformation_context);
444   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
445                                                kConsoleMessageConsumer));
446 
447   // Replace %25 with %100[1] in '%26 = OpFAdd %7 %23 %25'
448   auto instruction_descriptor_2 = MakeInstructionDescriptor(26, SpvOpFAdd, 0);
449   auto extract_2 =
450       TransformationCompositeExtract(instruction_descriptor_2, 102, 100, {1});
451   ASSERT_TRUE(extract_2.IsApplicable(context.get(), transformation_context));
452   extract_2.Apply(context.get(), &transformation_context);
453   auto replacement_2 = TransformationReplaceIdWithSynonym(
454       MakeIdUseDescriptor(25, instruction_descriptor_2, 1), 102);
455   ASSERT_TRUE(
456       replacement_2.IsApplicable(context.get(), transformation_context));
457   replacement_2.Apply(context.get(), &transformation_context);
458   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
459                                                kConsoleMessageConsumer));
460 
461   const std::string after_transformation = R"(
462                OpCapability Shader
463           %1 = OpExtInstImport "GLSL.std.450"
464                OpMemoryModel Logical GLSL450
465                OpEntryPoint Fragment %4 "main"
466                OpExecutionMode %4 OriginUpperLeft
467                OpSource ESSL 310
468                OpName %4 "main"
469                OpName %10 "m"
470           %2 = OpTypeVoid
471           %3 = OpTypeFunction %2
472           %6 = OpTypeFloat 32
473           %7 = OpTypeVector %6 4
474          %50 = OpUndef %7
475           %8 = OpTypeMatrix %7 3
476           %9 = OpTypePointer Function %8
477          %11 = OpTypeInt 32 1
478          %12 = OpConstant %11 0
479          %13 = OpConstant %6 1
480          %14 = OpConstantComposite %7 %13 %13 %13 %13
481          %15 = OpTypePointer Function %7
482          %17 = OpConstant %11 1
483          %18 = OpConstant %6 2
484          %19 = OpConstantComposite %7 %18 %18 %18 %18
485          %21 = OpConstant %11 2
486           %4 = OpFunction %2 None %3
487           %5 = OpLabel
488          %10 = OpVariable %9 Function
489          %16 = OpAccessChain %15 %10 %12
490                OpStore %16 %14
491          %20 = OpAccessChain %15 %10 %17
492                OpStore %20 %19
493          %22 = OpAccessChain %15 %10 %12
494          %23 = OpLoad %7 %22
495          %24 = OpAccessChain %15 %10 %17
496          %25 = OpLoad %7 %24
497         %100 = OpCompositeConstruct %8 %23 %25 %50
498         %101 = OpCompositeExtract %7 %100 0
499         %102 = OpCompositeExtract %7 %100 1
500          %26 = OpFAdd %7 %101 %102
501          %27 = OpAccessChain %15 %10 %21
502                OpStore %27 %26
503                OpReturn
504                OpFunctionEnd
505   )";
506 
507   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
508 }
509 
TEST(DataSynonymTransformationTest,StructCompositeSynonyms)510 TEST(DataSynonymTransformationTest, StructCompositeSynonyms) {
511   std::string shader = R"(
512                OpCapability Shader
513           %1 = OpExtInstImport "GLSL.std.450"
514                OpMemoryModel Logical GLSL450
515                OpEntryPoint Fragment %4 "main"
516                OpExecutionMode %4 OriginUpperLeft
517                OpSource ESSL 310
518                OpName %4 "main"
519                OpName %9 "Inner"
520                OpMemberName %9 0 "a"
521                OpMemberName %9 1 "b"
522                OpName %11 "i1"
523                OpName %17 "i2"
524                OpName %31 "Point"
525                OpMemberName %31 0 "x"
526                OpMemberName %31 1 "y"
527                OpMemberName %31 2 "z"
528                OpName %32 "Outer"
529                OpMemberName %32 0 "c"
530                OpMemberName %32 1 "d"
531                OpName %34 "o1"
532           %2 = OpTypeVoid
533           %3 = OpTypeFunction %2
534           %6 = OpTypeInt 32 1
535           %7 = OpTypeFloat 32
536           %8 = OpTypeVector %7 2
537           %9 = OpTypeStruct %6 %8
538          %10 = OpTypePointer Function %9
539          %12 = OpConstant %6 1
540          %13 = OpConstant %7 2
541          %14 = OpConstant %7 3
542          %15 = OpConstantComposite %8 %13 %14
543          %16 = OpConstantComposite %9 %12 %15
544          %18 = OpConstant %6 0
545          %19 = OpTypePointer Function %6
546          %24 = OpTypePointer Function %8
547          %27 = OpConstant %7 4
548          %31 = OpTypeStruct %7 %7 %7
549          %32 = OpTypeStruct %9 %31
550          %33 = OpTypePointer Function %32
551          %36 = OpConstant %7 10
552          %37 = OpTypeInt 32 0
553          %38 = OpConstant %37 0
554          %39 = OpTypePointer Function %7
555          %42 = OpConstant %37 1
556           %4 = OpFunction %2 None %3
557           %5 = OpLabel
558          %11 = OpVariable %10 Function
559          %17 = OpVariable %10 Function
560          %34 = OpVariable %33 Function
561         %101 = OpCompositeConstruct %31 %27 %36 %27
562                OpStore %11 %16
563          %20 = OpAccessChain %19 %11 %18
564          %21 = OpLoad %6 %20
565          %22 = OpIAdd %6 %21 %12
566         %102 = OpCompositeConstruct %9 %22 %15
567          %23 = OpAccessChain %19 %17 %18
568                OpStore %23 %22
569          %25 = OpAccessChain %24 %17 %12
570          %26 = OpLoad %8 %25
571          %28 = OpCompositeConstruct %8 %27 %27
572          %29 = OpFAdd %8 %26 %28
573          %30 = OpAccessChain %24 %17 %12
574                OpStore %30 %29
575          %35 = OpLoad %9 %11
576          %40 = OpAccessChain %39 %11 %12 %38
577          %41 = OpLoad %7 %40
578          %43 = OpAccessChain %39 %11 %12 %42
579          %44 = OpLoad %7 %43
580          %45 = OpCompositeConstruct %31 %36 %41 %44
581         %100 = OpCompositeConstruct %32 %16 %45
582          %46 = OpCompositeConstruct %32 %35 %45
583                OpStore %34 %46
584                OpReturn
585                OpFunctionEnd
586   )";
587 
588   const auto env = SPV_ENV_UNIVERSAL_1_3;
589   const auto consumer = nullptr;
590   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
591   spvtools::ValidatorOptions validator_options;
592   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
593                                                kConsoleMessageConsumer));
594   TransformationContext transformation_context(
595       MakeUnique<FactManager>(context.get()), validator_options);
596 
597   transformation_context.GetFactManager()->MaybeAddFact(
598       MakeSynonymFact(16, {}, 100, {0}));
599   transformation_context.GetFactManager()->MaybeAddFact(
600       MakeSynonymFact(45, {}, 100, {1}));
601   transformation_context.GetFactManager()->MaybeAddFact(
602       MakeSynonymFact(27, {}, 101, {0}));
603   transformation_context.GetFactManager()->MaybeAddFact(
604       MakeSynonymFact(36, {}, 101, {1}));
605   transformation_context.GetFactManager()->MaybeAddFact(
606       MakeSynonymFact(27, {}, 101, {2}));
607   transformation_context.GetFactManager()->MaybeAddFact(
608       MakeSynonymFact(22, {}, 102, {0}));
609   transformation_context.GetFactManager()->MaybeAddFact(
610       MakeSynonymFact(15, {}, 102, {1}));
611 
612   // Replace %45 with %100[1] in '%46 = OpCompositeConstruct %32 %35 %45'
613   auto instruction_descriptor_1 =
614       MakeInstructionDescriptor(46, SpvOpCompositeConstruct, 0);
615   auto extract_1 =
616       TransformationCompositeExtract(instruction_descriptor_1, 201, 100, {1});
617   ASSERT_TRUE(extract_1.IsApplicable(context.get(), transformation_context));
618   extract_1.Apply(context.get(), &transformation_context);
619   auto replacement_1 = TransformationReplaceIdWithSynonym(
620       MakeIdUseDescriptor(45, instruction_descriptor_1, 1), 201);
621   ASSERT_TRUE(
622       replacement_1.IsApplicable(context.get(), transformation_context));
623   replacement_1.Apply(context.get(), &transformation_context);
624   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
625                                                kConsoleMessageConsumer));
626 
627   // Replace second occurrence of %27 with %101[0] in '%28 =
628   // OpCompositeConstruct %8 %27 %27'
629   auto instruction_descriptor_2 =
630       MakeInstructionDescriptor(28, SpvOpCompositeConstruct, 0);
631   auto extract_2 =
632       TransformationCompositeExtract(instruction_descriptor_2, 202, 101, {0});
633   ASSERT_TRUE(extract_2.IsApplicable(context.get(), transformation_context));
634   extract_2.Apply(context.get(), &transformation_context);
635   auto replacement_2 = TransformationReplaceIdWithSynonym(
636       MakeIdUseDescriptor(27, instruction_descriptor_2, 1), 202);
637   ASSERT_TRUE(
638       replacement_2.IsApplicable(context.get(), transformation_context));
639   replacement_2.Apply(context.get(), &transformation_context);
640   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
641                                                kConsoleMessageConsumer));
642 
643   // Replace %36 with %101[1] in '%45 = OpCompositeConstruct %31 %36 %41 %44'
644   auto instruction_descriptor_3 =
645       MakeInstructionDescriptor(45, SpvOpCompositeConstruct, 0);
646   auto extract_3 =
647       TransformationCompositeExtract(instruction_descriptor_3, 203, 101, {1});
648   ASSERT_TRUE(extract_3.IsApplicable(context.get(), transformation_context));
649   extract_3.Apply(context.get(), &transformation_context);
650   auto replacement_3 = TransformationReplaceIdWithSynonym(
651       MakeIdUseDescriptor(36, instruction_descriptor_3, 0), 203);
652   ASSERT_TRUE(
653       replacement_3.IsApplicable(context.get(), transformation_context));
654   replacement_3.Apply(context.get(), &transformation_context);
655   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
656                                                kConsoleMessageConsumer));
657 
658   // Replace first occurrence of %27 with %101[2] in '%28 = OpCompositeConstruct
659   // %8 %27 %27'
660   auto instruction_descriptor_4 =
661       MakeInstructionDescriptor(28, SpvOpCompositeConstruct, 0);
662   auto extract_4 =
663       TransformationCompositeExtract(instruction_descriptor_4, 204, 101, {2});
664   ASSERT_TRUE(extract_4.IsApplicable(context.get(), transformation_context));
665   extract_4.Apply(context.get(), &transformation_context);
666   auto replacement_4 = TransformationReplaceIdWithSynonym(
667       MakeIdUseDescriptor(27, instruction_descriptor_4, 0), 204);
668   ASSERT_TRUE(
669       replacement_4.IsApplicable(context.get(), transformation_context));
670   replacement_4.Apply(context.get(), &transformation_context);
671   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
672                                                kConsoleMessageConsumer));
673 
674   // Replace %22 with %102[0] in 'OpStore %23 %22'
675   auto instruction_descriptor_5 = MakeInstructionDescriptor(23, SpvOpStore, 0);
676   auto extract_5 =
677       TransformationCompositeExtract(instruction_descriptor_5, 205, 102, {0});
678   ASSERT_TRUE(extract_5.IsApplicable(context.get(), transformation_context));
679   extract_5.Apply(context.get(), &transformation_context);
680   auto replacement_5 = TransformationReplaceIdWithSynonym(
681       MakeIdUseDescriptor(22, instruction_descriptor_5, 1), 205);
682   ASSERT_TRUE(
683       replacement_5.IsApplicable(context.get(), transformation_context));
684   replacement_5.Apply(context.get(), &transformation_context);
685   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
686                                                kConsoleMessageConsumer));
687 
688   const std::string after_transformation = R"(
689                OpCapability Shader
690           %1 = OpExtInstImport "GLSL.std.450"
691                OpMemoryModel Logical GLSL450
692                OpEntryPoint Fragment %4 "main"
693                OpExecutionMode %4 OriginUpperLeft
694                OpSource ESSL 310
695                OpName %4 "main"
696                OpName %9 "Inner"
697                OpMemberName %9 0 "a"
698                OpMemberName %9 1 "b"
699                OpName %11 "i1"
700                OpName %17 "i2"
701                OpName %31 "Point"
702                OpMemberName %31 0 "x"
703                OpMemberName %31 1 "y"
704                OpMemberName %31 2 "z"
705                OpName %32 "Outer"
706                OpMemberName %32 0 "c"
707                OpMemberName %32 1 "d"
708                OpName %34 "o1"
709           %2 = OpTypeVoid
710           %3 = OpTypeFunction %2
711           %6 = OpTypeInt 32 1
712           %7 = OpTypeFloat 32
713           %8 = OpTypeVector %7 2
714           %9 = OpTypeStruct %6 %8
715          %10 = OpTypePointer Function %9
716          %12 = OpConstant %6 1
717          %13 = OpConstant %7 2
718          %14 = OpConstant %7 3
719          %15 = OpConstantComposite %8 %13 %14
720          %16 = OpConstantComposite %9 %12 %15
721          %18 = OpConstant %6 0
722          %19 = OpTypePointer Function %6
723          %24 = OpTypePointer Function %8
724          %27 = OpConstant %7 4
725          %31 = OpTypeStruct %7 %7 %7
726          %32 = OpTypeStruct %9 %31
727          %33 = OpTypePointer Function %32
728          %36 = OpConstant %7 10
729          %37 = OpTypeInt 32 0
730          %38 = OpConstant %37 0
731          %39 = OpTypePointer Function %7
732          %42 = OpConstant %37 1
733           %4 = OpFunction %2 None %3
734           %5 = OpLabel
735          %11 = OpVariable %10 Function
736          %17 = OpVariable %10 Function
737          %34 = OpVariable %33 Function
738         %101 = OpCompositeConstruct %31 %27 %36 %27
739                OpStore %11 %16
740          %20 = OpAccessChain %19 %11 %18
741          %21 = OpLoad %6 %20
742          %22 = OpIAdd %6 %21 %12
743         %102 = OpCompositeConstruct %9 %22 %15
744          %23 = OpAccessChain %19 %17 %18
745         %205 = OpCompositeExtract %6 %102 0
746                OpStore %23 %205
747          %25 = OpAccessChain %24 %17 %12
748          %26 = OpLoad %8 %25
749         %202 = OpCompositeExtract %7 %101 0
750         %204 = OpCompositeExtract %7 %101 2
751          %28 = OpCompositeConstruct %8 %204 %202
752          %29 = OpFAdd %8 %26 %28
753          %30 = OpAccessChain %24 %17 %12
754                OpStore %30 %29
755          %35 = OpLoad %9 %11
756          %40 = OpAccessChain %39 %11 %12 %38
757          %41 = OpLoad %7 %40
758          %43 = OpAccessChain %39 %11 %12 %42
759          %44 = OpLoad %7 %43
760         %203 = OpCompositeExtract %7 %101 1
761          %45 = OpCompositeConstruct %31 %203 %41 %44
762         %100 = OpCompositeConstruct %32 %16 %45
763         %201 = OpCompositeExtract %31 %100 1
764          %46 = OpCompositeConstruct %32 %35 %201
765                OpStore %34 %46
766                OpReturn
767                OpFunctionEnd
768   )";
769 
770   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
771 }
772 
TEST(DataSynonymTransformationTest,VectorCompositeSynonyms)773 TEST(DataSynonymTransformationTest, VectorCompositeSynonyms) {
774   std::string shader = R"(
775                OpCapability Shader
776           %1 = OpExtInstImport "GLSL.std.450"
777                OpMemoryModel Logical GLSL450
778                OpEntryPoint Fragment %4 "main"
779                OpExecutionMode %4 OriginUpperLeft
780                OpSource ESSL 310
781                OpName %4 "main"
782                OpName %8 "f"
783                OpName %12 "v2"
784                OpName %18 "v3"
785                OpName %23 "v4"
786                OpName %32 "b"
787                OpName %36 "bv2"
788                OpName %41 "bv3"
789                OpName %50 "bv4"
790           %2 = OpTypeVoid
791           %3 = OpTypeFunction %2
792           %6 = OpTypeFloat 32
793           %7 = OpTypePointer Function %6
794           %9 = OpConstant %6 42
795          %10 = OpTypeVector %6 2
796          %11 = OpTypePointer Function %10
797          %16 = OpTypeVector %6 3
798          %17 = OpTypePointer Function %16
799          %21 = OpTypeVector %6 4
800          %22 = OpTypePointer Function %21
801          %30 = OpTypeBool
802          %31 = OpTypePointer Function %30
803          %33 = OpConstantFalse %30
804          %34 = OpTypeVector %30 2
805          %35 = OpTypePointer Function %34
806          %37 = OpConstantTrue %30
807          %38 = OpConstantComposite %34 %37 %37
808          %39 = OpTypeVector %30 3
809          %40 = OpTypePointer Function %39
810          %48 = OpTypeVector %30 4
811          %49 = OpTypePointer Function %48
812          %51 = OpTypeInt 32 0
813          %52 = OpConstant %51 2
814          %55 = OpConstant %6 0
815          %57 = OpConstant %51 1
816           %4 = OpFunction %2 None %3
817           %5 = OpLabel
818           %8 = OpVariable %7 Function
819          %12 = OpVariable %11 Function
820          %18 = OpVariable %17 Function
821          %23 = OpVariable %22 Function
822          %32 = OpVariable %31 Function
823          %36 = OpVariable %35 Function
824          %41 = OpVariable %40 Function
825          %50 = OpVariable %49 Function
826                OpStore %8 %9
827          %13 = OpLoad %6 %8
828          %14 = OpLoad %6 %8
829          %15 = OpCompositeConstruct %10 %13 %14
830                OpStore %12 %15
831          %19 = OpLoad %10 %12
832          %20 = OpVectorShuffle %16 %19 %19 0 0 1
833                OpStore %18 %20
834          %24 = OpLoad %16 %18
835          %25 = OpLoad %6 %8
836          %26 = OpCompositeExtract %6 %24 0
837          %27 = OpCompositeExtract %6 %24 1
838          %28 = OpCompositeExtract %6 %24 2
839          %29 = OpCompositeConstruct %21 %26 %27 %28 %25
840                OpStore %23 %29
841                OpStore %32 %33
842                OpStore %36 %38
843          %42 = OpLoad %30 %32
844          %43 = OpLoad %34 %36
845          %44 = OpVectorShuffle %34 %43 %43 0 0
846          %45 = OpCompositeExtract %30 %44 0
847          %46 = OpCompositeExtract %30 %44 1
848          %47 = OpCompositeConstruct %39 %42 %45 %46
849                OpStore %41 %47
850          %53 = OpAccessChain %7 %23 %52
851          %54 = OpLoad %6 %53
852 
853         %100 = OpCompositeConstruct %21 %20 %54
854         %101 = OpCompositeConstruct %21 %15 %19
855         %102 = OpCompositeConstruct %16 %27 %15
856         %103 = OpCompositeConstruct %48 %33 %47
857         %104 = OpCompositeConstruct %34 %42 %45
858         %105 = OpCompositeConstruct %39 %38 %46
859 
860          %86 = OpCopyObject %30 %33
861          %56 = OpFOrdNotEqual %30 %54 %55
862          %80 = OpCopyObject %16 %20
863          %58 = OpAccessChain %7 %18 %57
864          %59 = OpLoad %6 %58
865          %60 = OpFOrdNotEqual %30 %59 %55
866          %61 = OpLoad %34 %36
867          %62 = OpLogicalAnd %30 %45 %46
868          %63 = OpLogicalOr %30 %45 %46
869          %64 = OpCompositeConstruct %48 %56 %60 %62 %63
870                OpStore %12 %15
871          %81 = OpVectorShuffle %16 %19 %19 0 0 1
872          %82 = OpCompositeConstruct %21 %26 %27 %28 %25
873          %83 = OpCopyObject %10 %15
874          %84 = OpCopyObject %39 %47
875                OpStore %50 %64
876          %85 = OpCopyObject %30 %42
877                OpStore %36 %38
878                OpReturn
879                OpFunctionEnd
880   )";
881 
882   const auto env = SPV_ENV_UNIVERSAL_1_3;
883   const auto consumer = nullptr;
884   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
885   spvtools::ValidatorOptions validator_options;
886   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
887                                                kConsoleMessageConsumer));
888   TransformationContext transformation_context(
889       MakeUnique<FactManager>(context.get()), validator_options);
890 
891   transformation_context.GetFactManager()->MaybeAddFact(
892       MakeSynonymFact(20, {0}, 100, {0}));
893   transformation_context.GetFactManager()->MaybeAddFact(
894       MakeSynonymFact(20, {1}, 100, {1}));
895   transformation_context.GetFactManager()->MaybeAddFact(
896       MakeSynonymFact(20, {2}, 100, {2}));
897   transformation_context.GetFactManager()->MaybeAddFact(
898       MakeSynonymFact(54, {}, 100, {3}));
899   transformation_context.GetFactManager()->MaybeAddFact(
900       MakeSynonymFact(15, {0}, 101, {0}));
901   transformation_context.GetFactManager()->MaybeAddFact(
902       MakeSynonymFact(15, {1}, 101, {1}));
903   transformation_context.GetFactManager()->MaybeAddFact(
904       MakeSynonymFact(19, {0}, 101, {2}));
905   transformation_context.GetFactManager()->MaybeAddFact(
906       MakeSynonymFact(19, {1}, 101, {3}));
907   transformation_context.GetFactManager()->MaybeAddFact(
908       MakeSynonymFact(27, {}, 102, {0}));
909   transformation_context.GetFactManager()->MaybeAddFact(
910       MakeSynonymFact(15, {0}, 102, {1}));
911   transformation_context.GetFactManager()->MaybeAddFact(
912       MakeSynonymFact(15, {1}, 102, {2}));
913   transformation_context.GetFactManager()->MaybeAddFact(
914       MakeSynonymFact(33, {}, 103, {0}));
915   transformation_context.GetFactManager()->MaybeAddFact(
916       MakeSynonymFact(47, {0}, 103, {1}));
917   transformation_context.GetFactManager()->MaybeAddFact(
918       MakeSynonymFact(47, {1}, 103, {2}));
919   transformation_context.GetFactManager()->MaybeAddFact(
920       MakeSynonymFact(47, {2}, 103, {3}));
921   transformation_context.GetFactManager()->MaybeAddFact(
922       MakeSynonymFact(42, {}, 104, {0}));
923   transformation_context.GetFactManager()->MaybeAddFact(
924       MakeSynonymFact(45, {}, 104, {1}));
925   transformation_context.GetFactManager()->MaybeAddFact(
926       MakeSynonymFact(38, {0}, 105, {0}));
927   transformation_context.GetFactManager()->MaybeAddFact(
928       MakeSynonymFact(38, {1}, 105, {1}));
929   transformation_context.GetFactManager()->MaybeAddFact(
930       MakeSynonymFact(46, {}, 105, {2}));
931 
932   // Replace %20 with %100[0:2] in '%80 = OpCopyObject %16 %20'
933   auto instruction_descriptor_1 =
934       MakeInstructionDescriptor(80, SpvOpCopyObject, 0);
935   auto shuffle_1 = TransformationVectorShuffle(instruction_descriptor_1, 200,
936                                                100, 100, {0, 1, 2});
937   ASSERT_TRUE(shuffle_1.IsApplicable(context.get(), transformation_context));
938   shuffle_1.Apply(context.get(), &transformation_context);
939   transformation_context.GetFactManager()->ComputeClosureOfFacts(100);
940 
941   auto replacement_1 = TransformationReplaceIdWithSynonym(
942       MakeIdUseDescriptor(20, instruction_descriptor_1, 0), 200);
943   ASSERT_TRUE(
944       replacement_1.IsApplicable(context.get(), transformation_context));
945   replacement_1.Apply(context.get(), &transformation_context);
946   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
947                                                kConsoleMessageConsumer));
948 
949   // Replace %54 with %100[3] in '%56 = OpFOrdNotEqual %30 %54 %55'
950   auto instruction_descriptor_2 =
951       MakeInstructionDescriptor(56, SpvOpFOrdNotEqual, 0);
952   auto extract_2 =
953       TransformationCompositeExtract(instruction_descriptor_2, 201, 100, {3});
954 
955   ASSERT_TRUE(extract_2.IsApplicable(context.get(), transformation_context));
956   extract_2.Apply(context.get(), &transformation_context);
957   auto replacement_2 = TransformationReplaceIdWithSynonym(
958       MakeIdUseDescriptor(54, instruction_descriptor_2, 0), 201);
959   ASSERT_TRUE(
960       replacement_2.IsApplicable(context.get(), transformation_context));
961   replacement_2.Apply(context.get(), &transformation_context);
962   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
963                                                kConsoleMessageConsumer));
964 
965   // Replace %15 with %101[0:1] in 'OpStore %12 %15'
966   auto instruction_descriptor_3 = MakeInstructionDescriptor(64, SpvOpStore, 0);
967   auto shuffle_3 = TransformationVectorShuffle(instruction_descriptor_3, 202,
968                                                101, 101, {0, 1});
969   ASSERT_TRUE(shuffle_3.IsApplicable(context.get(), transformation_context));
970   shuffle_3.Apply(context.get(), &transformation_context);
971   transformation_context.GetFactManager()->ComputeClosureOfFacts(100);
972 
973   auto replacement_3 = TransformationReplaceIdWithSynonym(
974       MakeIdUseDescriptor(15, instruction_descriptor_3, 1), 202);
975   ASSERT_TRUE(
976       replacement_3.IsApplicable(context.get(), transformation_context));
977   replacement_3.Apply(context.get(), &transformation_context);
978   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
979                                                kConsoleMessageConsumer));
980 
981   // Replace %19 with %101[2:3] in '%81 = OpVectorShuffle %16 %19 %19 0 0 1'
982   auto instruction_descriptor_4 =
983       MakeInstructionDescriptor(81, SpvOpVectorShuffle, 0);
984   auto shuffle_4 = TransformationVectorShuffle(instruction_descriptor_4, 203,
985                                                101, 101, {2, 3});
986   ASSERT_TRUE(shuffle_4.IsApplicable(context.get(), transformation_context));
987   shuffle_4.Apply(context.get(), &transformation_context);
988   transformation_context.GetFactManager()->ComputeClosureOfFacts(100);
989 
990   auto replacement_4 = TransformationReplaceIdWithSynonym(
991       MakeIdUseDescriptor(19, instruction_descriptor_4, 0), 203);
992   ASSERT_TRUE(
993       replacement_4.IsApplicable(context.get(), transformation_context));
994   replacement_4.Apply(context.get(), &transformation_context);
995   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
996                                                kConsoleMessageConsumer));
997 
998   // Replace %27 with %102[0] in '%82 = OpCompositeConstruct %21 %26 %27 %28
999   // %25'
1000   auto instruction_descriptor_5 =
1001       MakeInstructionDescriptor(82, SpvOpCompositeConstruct, 0);
1002   auto extract_5 =
1003       TransformationCompositeExtract(instruction_descriptor_5, 204, 102, {0});
1004 
1005   ASSERT_TRUE(extract_5.IsApplicable(context.get(), transformation_context));
1006   extract_5.Apply(context.get(), &transformation_context);
1007   auto replacement_5 = TransformationReplaceIdWithSynonym(
1008       MakeIdUseDescriptor(27, instruction_descriptor_5, 1), 204);
1009   ASSERT_TRUE(
1010       replacement_5.IsApplicable(context.get(), transformation_context));
1011   replacement_5.Apply(context.get(), &transformation_context);
1012   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1013                                                kConsoleMessageConsumer));
1014 
1015   // Replace %15 with %102[1:2] in '%83 = OpCopyObject %10 %15'
1016   auto instruction_descriptor_6 =
1017       MakeInstructionDescriptor(83, SpvOpCopyObject, 0);
1018   auto shuffle_6 = TransformationVectorShuffle(instruction_descriptor_6, 205,
1019                                                102, 102, {1, 2});
1020   ASSERT_TRUE(shuffle_6.IsApplicable(context.get(), transformation_context));
1021   shuffle_6.Apply(context.get(), &transformation_context);
1022   transformation_context.GetFactManager()->ComputeClosureOfFacts(100);
1023 
1024   auto replacement_6 = TransformationReplaceIdWithSynonym(
1025       MakeIdUseDescriptor(15, instruction_descriptor_6, 0), 205);
1026   ASSERT_TRUE(
1027       replacement_6.IsApplicable(context.get(), transformation_context));
1028   replacement_6.Apply(context.get(), &transformation_context);
1029   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1030                                                kConsoleMessageConsumer));
1031 
1032   // Replace %33 with %103[0] in '%86 = OpCopyObject %30 %33'
1033   auto instruction_descriptor_7 =
1034       MakeInstructionDescriptor(86, SpvOpCopyObject, 0);
1035   auto extract_7 =
1036       TransformationCompositeExtract(instruction_descriptor_7, 206, 103, {0});
1037   ASSERT_TRUE(extract_7.IsApplicable(context.get(), transformation_context));
1038   extract_7.Apply(context.get(), &transformation_context);
1039   auto replacement_7 = TransformationReplaceIdWithSynonym(
1040       MakeIdUseDescriptor(33, instruction_descriptor_7, 0), 206);
1041   ASSERT_TRUE(
1042       replacement_7.IsApplicable(context.get(), transformation_context));
1043   replacement_7.Apply(context.get(), &transformation_context);
1044   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1045                                                kConsoleMessageConsumer));
1046 
1047   // Replace %47 with %103[1:3] in '%84 = OpCopyObject %39 %47'
1048   auto instruction_descriptor_8 =
1049       MakeInstructionDescriptor(84, SpvOpCopyObject, 0);
1050   auto shuffle_8 = TransformationVectorShuffle(instruction_descriptor_8, 207,
1051                                                103, 103, {1, 2, 3});
1052   ASSERT_TRUE(shuffle_8.IsApplicable(context.get(), transformation_context));
1053   shuffle_8.Apply(context.get(), &transformation_context);
1054   transformation_context.GetFactManager()->ComputeClosureOfFacts(100);
1055 
1056   auto replacement_8 = TransformationReplaceIdWithSynonym(
1057       MakeIdUseDescriptor(47, instruction_descriptor_8, 0), 207);
1058   ASSERT_TRUE(
1059       replacement_8.IsApplicable(context.get(), transformation_context));
1060   replacement_8.Apply(context.get(), &transformation_context);
1061   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1062                                                kConsoleMessageConsumer));
1063 
1064   // Replace %42 with %104[0] in '%85 = OpCopyObject %30 %42'
1065   auto instruction_descriptor_9 =
1066       MakeInstructionDescriptor(85, SpvOpCopyObject, 0);
1067   auto extract_9 =
1068       TransformationCompositeExtract(instruction_descriptor_9, 208, 104, {0});
1069   ASSERT_TRUE(extract_9.IsApplicable(context.get(), transformation_context));
1070   extract_9.Apply(context.get(), &transformation_context);
1071   auto replacement_9 = TransformationReplaceIdWithSynonym(
1072       MakeIdUseDescriptor(42, instruction_descriptor_9, 0), 208);
1073   ASSERT_TRUE(
1074       replacement_9.IsApplicable(context.get(), transformation_context));
1075   replacement_9.Apply(context.get(), &transformation_context);
1076   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1077                                                kConsoleMessageConsumer));
1078 
1079   // Replace %45 with %104[1] in '%63 = OpLogicalOr %30 %45 %46'
1080   auto instruction_descriptor_10 =
1081       MakeInstructionDescriptor(63, SpvOpLogicalOr, 0);
1082   auto extract_10 =
1083       TransformationCompositeExtract(instruction_descriptor_10, 209, 104, {1});
1084   ASSERT_TRUE(extract_10.IsApplicable(context.get(), transformation_context));
1085   extract_10.Apply(context.get(), &transformation_context);
1086   auto replacement_10 = TransformationReplaceIdWithSynonym(
1087       MakeIdUseDescriptor(45, instruction_descriptor_10, 0), 209);
1088   ASSERT_TRUE(
1089       replacement_10.IsApplicable(context.get(), transformation_context));
1090   replacement_10.Apply(context.get(), &transformation_context);
1091   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1092                                                kConsoleMessageConsumer));
1093 
1094   // Replace %38 with %105[0:1] in 'OpStore %36 %38'
1095   auto instruction_descriptor_11 = MakeInstructionDescriptor(85, SpvOpStore, 0);
1096   auto shuffle_11 = TransformationVectorShuffle(instruction_descriptor_11, 210,
1097                                                 105, 105, {0, 1});
1098   ASSERT_TRUE(shuffle_11.IsApplicable(context.get(), transformation_context));
1099   shuffle_11.Apply(context.get(), &transformation_context);
1100   transformation_context.GetFactManager()->ComputeClosureOfFacts(100);
1101 
1102   auto replacement_11 = TransformationReplaceIdWithSynonym(
1103       MakeIdUseDescriptor(38, instruction_descriptor_11, 1), 210);
1104   ASSERT_TRUE(
1105       replacement_11.IsApplicable(context.get(), transformation_context));
1106   replacement_11.Apply(context.get(), &transformation_context);
1107   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1108                                                kConsoleMessageConsumer));
1109 
1110   // Replace %46 with %105[2] in '%62 = OpLogicalAnd %30 %45 %46'
1111   auto instruction_descriptor_12 =
1112       MakeInstructionDescriptor(62, SpvOpLogicalAnd, 0);
1113   auto extract_12 =
1114       TransformationCompositeExtract(instruction_descriptor_12, 211, 105, {2});
1115   ASSERT_TRUE(extract_12.IsApplicable(context.get(), transformation_context));
1116   extract_12.Apply(context.get(), &transformation_context);
1117   auto replacement_12 = TransformationReplaceIdWithSynonym(
1118       MakeIdUseDescriptor(46, instruction_descriptor_12, 1), 211);
1119   ASSERT_TRUE(
1120       replacement_12.IsApplicable(context.get(), transformation_context));
1121   replacement_12.Apply(context.get(), &transformation_context);
1122   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1123                                                kConsoleMessageConsumer));
1124 
1125   const std::string after_transformation = R"(
1126                OpCapability Shader
1127           %1 = OpExtInstImport "GLSL.std.450"
1128                OpMemoryModel Logical GLSL450
1129                OpEntryPoint Fragment %4 "main"
1130                OpExecutionMode %4 OriginUpperLeft
1131                OpSource ESSL 310
1132                OpName %4 "main"
1133                OpName %8 "f"
1134                OpName %12 "v2"
1135                OpName %18 "v3"
1136                OpName %23 "v4"
1137                OpName %32 "b"
1138                OpName %36 "bv2"
1139                OpName %41 "bv3"
1140                OpName %50 "bv4"
1141           %2 = OpTypeVoid
1142           %3 = OpTypeFunction %2
1143           %6 = OpTypeFloat 32
1144           %7 = OpTypePointer Function %6
1145           %9 = OpConstant %6 42
1146          %10 = OpTypeVector %6 2
1147          %11 = OpTypePointer Function %10
1148          %16 = OpTypeVector %6 3
1149          %17 = OpTypePointer Function %16
1150          %21 = OpTypeVector %6 4
1151          %22 = OpTypePointer Function %21
1152          %30 = OpTypeBool
1153          %31 = OpTypePointer Function %30
1154          %33 = OpConstantFalse %30
1155          %34 = OpTypeVector %30 2
1156          %35 = OpTypePointer Function %34
1157          %37 = OpConstantTrue %30
1158          %38 = OpConstantComposite %34 %37 %37
1159          %39 = OpTypeVector %30 3
1160          %40 = OpTypePointer Function %39
1161          %48 = OpTypeVector %30 4
1162          %49 = OpTypePointer Function %48
1163          %51 = OpTypeInt 32 0
1164          %52 = OpConstant %51 2
1165          %55 = OpConstant %6 0
1166          %57 = OpConstant %51 1
1167           %4 = OpFunction %2 None %3
1168           %5 = OpLabel
1169           %8 = OpVariable %7 Function
1170          %12 = OpVariable %11 Function
1171          %18 = OpVariable %17 Function
1172          %23 = OpVariable %22 Function
1173          %32 = OpVariable %31 Function
1174          %36 = OpVariable %35 Function
1175          %41 = OpVariable %40 Function
1176          %50 = OpVariable %49 Function
1177                OpStore %8 %9
1178          %13 = OpLoad %6 %8
1179          %14 = OpLoad %6 %8
1180          %15 = OpCompositeConstruct %10 %13 %14
1181                OpStore %12 %15
1182          %19 = OpLoad %10 %12
1183          %20 = OpVectorShuffle %16 %19 %19 0 0 1
1184                OpStore %18 %20
1185          %24 = OpLoad %16 %18
1186          %25 = OpLoad %6 %8
1187          %26 = OpCompositeExtract %6 %24 0
1188          %27 = OpCompositeExtract %6 %24 1
1189          %28 = OpCompositeExtract %6 %24 2
1190          %29 = OpCompositeConstruct %21 %26 %27 %28 %25
1191                OpStore %23 %29
1192                OpStore %32 %33
1193                OpStore %36 %38
1194          %42 = OpLoad %30 %32
1195          %43 = OpLoad %34 %36
1196          %44 = OpVectorShuffle %34 %43 %43 0 0
1197          %45 = OpCompositeExtract %30 %44 0
1198          %46 = OpCompositeExtract %30 %44 1
1199          %47 = OpCompositeConstruct %39 %42 %45 %46
1200                OpStore %41 %47
1201          %53 = OpAccessChain %7 %23 %52
1202          %54 = OpLoad %6 %53
1203 
1204         %100 = OpCompositeConstruct %21 %20 %54
1205         %101 = OpCompositeConstruct %21 %15 %19
1206         %102 = OpCompositeConstruct %16 %27 %15
1207         %103 = OpCompositeConstruct %48 %33 %47
1208         %104 = OpCompositeConstruct %34 %42 %45
1209         %105 = OpCompositeConstruct %39 %38 %46
1210 
1211         %206 = OpCompositeExtract %30 %103 0
1212          %86 = OpCopyObject %30 %206
1213         %201 = OpCompositeExtract %6 %100 3
1214          %56 = OpFOrdNotEqual %30 %201 %55
1215         %200 = OpVectorShuffle %16 %100 %100 0 1 2
1216          %80 = OpCopyObject %16 %200
1217          %58 = OpAccessChain %7 %18 %57
1218          %59 = OpLoad %6 %58
1219          %60 = OpFOrdNotEqual %30 %59 %55
1220          %61 = OpLoad %34 %36
1221         %211 = OpCompositeExtract %30 %105 2
1222          %62 = OpLogicalAnd %30 %45 %211
1223         %209 = OpCompositeExtract %30 %104 1
1224          %63 = OpLogicalOr %30 %209 %46
1225          %64 = OpCompositeConstruct %48 %56 %60 %62 %63
1226         %202 = OpVectorShuffle %10 %101 %101 0 1
1227                OpStore %12 %202
1228         %203 = OpVectorShuffle %10 %101 %101 2 3
1229          %81 = OpVectorShuffle %16 %203 %19 0 0 1
1230         %204 = OpCompositeExtract %6 %102 0
1231          %82 = OpCompositeConstruct %21 %26 %204 %28 %25
1232         %205 = OpVectorShuffle %10 %102 %102 1 2
1233          %83 = OpCopyObject %10 %205
1234         %207 = OpVectorShuffle %39 %103 %103 1 2 3
1235          %84 = OpCopyObject %39 %207
1236                OpStore %50 %64
1237         %208 = OpCompositeExtract %30 %104 0
1238          %85 = OpCopyObject %30 %208
1239         %210 = OpVectorShuffle %34 %105 %105 0 1
1240                OpStore %36 %210
1241                OpReturn
1242                OpFunctionEnd
1243   )";
1244 
1245   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
1246 }
1247 
1248 }  // namespace
1249 }  // namespace fuzz
1250 }  // namespace spvtools
1251