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