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
23namespace spvtools {
24namespace fuzz {
25namespace {
26
27TEST(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
347TEST(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
554TEST(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
790TEST(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
1422TEST(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
1506TEST(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
1594TEST(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
1646TEST(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
1690TEST(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