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
26namespace spvtools {
27namespace fuzz {
28namespace {
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
33protobufs::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
47TEST(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
375TEST(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
515TEST(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
779TEST(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