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