1 // Copyright (c) 2021 Shiyu Liu
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_wrap_vector_synonym.h"
16 
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "source/fuzz/instruction_descriptor.h"
20 #include "test/fuzz/fuzz_test_util.h"
21 
22 namespace spvtools {
23 namespace fuzz {
24 namespace {
25 
TEST(TransformationWrapVectorSynonym, BasicTest)26 TEST(TransformationWrapVectorSynonym, BasicTest) {
27   std::string shader = R"(
28                OpCapability Shader
29           %1 = OpExtInstImport "GLSL.std.450"
30                OpMemoryModel Logical GLSL450
31                OpEntryPoint Fragment %4 "main" %97
32                OpExecutionMode %4 OriginUpperLeft
33                OpSource ESSL 310
34                OpName %4 "main"
35           %2 = OpTypeVoid
36           %3 = OpTypeFunction %2
37           %6 = OpTypeInt 32 1
38           %7 = OpTypePointer Function %6
39           %9 = OpConstant %6 10
40          %11 = OpConstant %6 -5
41          %12 = OpTypeVector %6 2
42          %13 = OpTypePointer Function %12
43          %18 = OpTypeInt 32 0
44          %19 = OpTypePointer Function %18
45          %21 = OpConstant %18 8
46          %23 = OpConstant %18 2
47          %24 = OpTypeVector %18 3
48          %25 = OpTypePointer Function %24
49          %31 = OpTypeFloat 32
50          %32 = OpTypePointer Function %31
51          %34 = OpConstant %31 3.29999995
52          %36 = OpConstant %31 1.10000002
53          %37 = OpTypeVector %31 4
54          %38 = OpTypePointer Function %37
55          %96 = OpTypePointer Input %31
56          %97 = OpVariable %96 Input
57           %4 = OpFunction %2 None %3
58           %5 = OpLabel
59           %8 = OpVariable %7 Function
60          %10 = OpVariable %7 Function
61          %14 = OpVariable %13 Function
62          %20 = OpVariable %19 Function
63          %22 = OpVariable %19 Function
64          %26 = OpVariable %25 Function
65          %33 = OpVariable %32 Function
66          %35 = OpVariable %32 Function
67          %39 = OpVariable %38 Function
68          %47 = OpVariable %7 Function
69          %51 = OpVariable %7 Function
70          %55 = OpVariable %7 Function
71          %59 = OpVariable %7 Function
72          %63 = OpVariable %19 Function
73          %67 = OpVariable %19 Function
74          %71 = OpVariable %19 Function
75          %75 = OpVariable %19 Function
76          %79 = OpVariable %32 Function
77          %83 = OpVariable %32 Function
78          %87 = OpVariable %32 Function
79          %91 = OpVariable %32 Function
80                OpStore %8 %9
81                OpStore %10 %11
82          %15 = OpLoad %6 %8
83          %16 = OpLoad %6 %10
84          %17 = OpCompositeConstruct %12 %15 %16
85                OpStore %14 %17
86                OpStore %20 %21
87                OpStore %22 %23
88          %27 = OpLoad %18 %20
89          %28 = OpLoad %18 %20
90          %29 = OpLoad %18 %22
91          %30 = OpCompositeConstruct %24 %27 %28 %29
92                OpStore %26 %30
93                OpStore %33 %34
94                OpStore %35 %36
95          %40 = OpLoad %31 %33
96          %41 = OpLoad %31 %33
97          %42 = OpLoad %31 %35
98          %43 = OpLoad %31 %35
99          %44 = OpCompositeConstruct %37 %40 %41 %42 %43
100          %45 = OpLoad %37 %39
101          %46 = OpVectorShuffle %37 %45 %44 5 6 7 4
102                OpStore %39 %46
103          %48 = OpLoad %6 %8
104          %49 = OpLoad %6 %10
105         %100 = OpCompositeConstruct %12 %48 %48
106         %101 = OpCompositeConstruct %12 %49 %49
107          %50 = OpIAdd %6 %48 %49
108                OpStore %47 %50
109          %52 = OpLoad %6 %8
110          %53 = OpLoad %6 %10
111          %54 = OpISub %6 %52 %53
112                OpStore %51 %54
113          %56 = OpLoad %6 %8
114          %57 = OpLoad %6 %10
115          %58 = OpIMul %6 %56 %57
116                OpStore %55 %58
117          %60 = OpLoad %6 %8
118          %61 = OpLoad %6 %10
119          %62 = OpSDiv %6 %60 %61
120                OpStore %59 %62
121          %64 = OpLoad %18 %20
122          %65 = OpLoad %18 %22
123          %66 = OpIAdd %18 %64 %65
124                OpStore %63 %66
125          %68 = OpLoad %18 %20
126          %69 = OpLoad %18 %22
127          %70 = OpISub %18 %68 %69
128                OpStore %67 %70
129          %72 = OpLoad %18 %20
130          %73 = OpLoad %18 %22
131          %74 = OpIMul %18 %72 %73
132                OpStore %71 %74
133          %76 = OpLoad %18 %20
134          %77 = OpLoad %18 %22
135          %78 = OpUDiv %18 %76 %77
136                OpStore %75 %78
137          %80 = OpLoad %31 %33
138          %81 = OpLoad %31 %35
139          %82 = OpFAdd %31 %80 %81
140                OpStore %79 %82
141          %84 = OpLoad %31 %33
142          %85 = OpLoad %31 %35
143          %86 = OpFSub %31 %84 %85
144                OpStore %83 %86
145          %88 = OpLoad %31 %33
146          %89 = OpLoad %31 %35
147          %90 = OpFMul %31 %88 %89
148                OpStore %87 %90
149          %92 = OpLoad %31 %33
150          %93 = OpLoad %31 %35
151          %94 = OpFDiv %31 %92 %93
152                OpStore %91 %94
153                OpReturn
154                OpFunctionEnd
155   )";
156   const auto env = SPV_ENV_UNIVERSAL_1_3;
157   const auto consumer = nullptr;
158   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
159   spvtools::ValidatorOptions validator_options;
160 
161   // Check context validity.
162   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
163                                                kConsoleMessageConsumer));
164 
165   TransformationContext transformation_context(
166       MakeUnique<FactManager>(context.get()), validator_options);
167 
168   // Vec Type Id |   Vector Type  |  Element Type id |   Element Type  |
169   // ------------+----------------+------------------+-----------------+
170   //     12      |      vec2      |         6        |      int32      |
171   //     24      |      vec3      |        18        |     uint32      |
172   //     37      |      vec4      |        31        |      float      |
173 
174   // Instruction Id | Opcode  | Type Id | constant id 1 | constant id 2 |
175   // ---------------+---------+---------+---------------+---------------+
176   //       50       | OpIAdd  |    6    |      48       |      49       |
177   //       54       | OpISub  |    6    |      52       |      53       |
178   //       58       | OpIMul  |    6    |      56       |      57       |
179   //       62       | OpSDiv  |    6    |      60       |      61       |
180   //       66       | OpIAdd  |    18   |      64       |      65       |
181   //       70       | OpISub  |    18   |      68       |      69       |
182   //       74       | OpIMul  |    18   |      72       |      73       |
183   //       78       | OpUDiv  |    18   |      76       |      77       |
184   //       82       | OpFAdd  |    31   |      80       |      81       |
185   //       86       | OpFSub  |    31   |      84       |      85       |
186   //       90       | OpFMul  |    31   |      88       |      89       |
187   //       94       | OpFDiv  |    31   |      92       |      93       |
188 
189   // Assert that the target scalar instruction result id is relevant.
190   ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(50));
191   transformation_context.GetFactManager()->AddFactDataSynonym(
192       MakeDataDescriptor(100, {1}), MakeDataDescriptor(48, {}));
193   transformation_context.GetFactManager()->AddFactDataSynonym(
194       MakeDataDescriptor(101, {1}), MakeDataDescriptor(49, {}));
195 
196   // The following are all invalid use.
197   {
198     // Bad: Instruction id does not exist.
199     TransformationWrapVectorSynonym wrap_add_int_bad1(103, 100, 101, 102, 1);
200     ASSERT_FALSE(
201         wrap_add_int_bad1.IsApplicable(context.get(), transformation_context));
202 
203     // Bad: Instruction id given is not of a valid arithmetic operation typed
204     // instruction.
205     TransformationWrapVectorSynonym wrap_add_int_bad2(80, 100, 101, 102, 1);
206     ASSERT_FALSE(
207         wrap_add_int_bad1.IsApplicable(context.get(), transformation_context));
208 
209     // Bad: the id for the first vector does not exist.
210     TransformationWrapVectorSynonym wrap_add_int_bad3(50, 105, 101, 102, 1);
211     ASSERT_FALSE(
212         wrap_add_int_bad3.IsApplicable(context.get(), transformation_context));
213 
214     // Bad: the id for the second vector does not exist.
215     TransformationWrapVectorSynonym wrap_add_int_bad4(50, 100, 105, 102, 1);
216     ASSERT_FALSE(
217         wrap_add_int_bad4.IsApplicable(context.get(), transformation_context));
218 
219     // Bad: vector id is not fresh.
220     TransformationWrapVectorSynonym wrap_add_int_bad6(50, 100, 101, 94, 1);
221     ASSERT_FALSE(
222         wrap_add_int_bad6.IsApplicable(context.get(), transformation_context));
223 
224     // Bad: The position goes out of bound for the given vector type.
225     TransformationWrapVectorSynonym wrap_add_int_bad8(50, 100, 101, 102, 2);
226     ASSERT_FALSE(
227         wrap_add_int_bad8.IsApplicable(context.get(), transformation_context));
228 
229     // Bad: The original instruction is not a valid scalar operation
230     // instruction.
231     TransformationWrapVectorSynonym wrap_add_int(27, 100, 101, 102, 1);
232     ASSERT_FALSE(
233         wrap_add_int.IsApplicable(context.get(), transformation_context));
234   }
235 
236   // Good: The following transformation should be applicable.
237   TransformationWrapVectorSynonym wrap_add_int(50, 100, 101, 102, 1);
238   ASSERT_TRUE(wrap_add_int.IsApplicable(context.get(), transformation_context));
239   // Insert an arithmetic instruction of the same type to add two vectors.
240   ApplyAndCheckFreshIds(wrap_add_int, context.get(), &transformation_context);
241 
242   // |instruction_id| and id at |scalar_position of the result vector should be
243   // synonyms.
244   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
245       MakeDataDescriptor(102, {1}), MakeDataDescriptor(50, {})));
246 
247   // After applying transformations, the instruction:
248   //
249   // %102 = OpIAdd %12 %100 %101
250   //
251   // should be added before:
252   //
253   // %50 = OpIAdd %6 %48 %49
254   std::string after_transformation = R"(
255                OpCapability Shader
256           %1 = OpExtInstImport "GLSL.std.450"
257                OpMemoryModel Logical GLSL450
258                OpEntryPoint Fragment %4 "main" %97
259                OpExecutionMode %4 OriginUpperLeft
260                OpSource ESSL 310
261                OpName %4 "main"
262           %2 = OpTypeVoid
263           %3 = OpTypeFunction %2
264           %6 = OpTypeInt 32 1
265           %7 = OpTypePointer Function %6
266           %9 = OpConstant %6 10
267          %11 = OpConstant %6 -5
268          %12 = OpTypeVector %6 2
269          %13 = OpTypePointer Function %12
270          %18 = OpTypeInt 32 0
271          %19 = OpTypePointer Function %18
272          %21 = OpConstant %18 8
273          %23 = OpConstant %18 2
274          %24 = OpTypeVector %18 3
275          %25 = OpTypePointer Function %24
276          %31 = OpTypeFloat 32
277          %32 = OpTypePointer Function %31
278          %34 = OpConstant %31 3.29999995
279          %36 = OpConstant %31 1.10000002
280          %37 = OpTypeVector %31 4
281          %38 = OpTypePointer Function %37
282          %96 = OpTypePointer Input %31
283          %97 = OpVariable %96 Input
284           %4 = OpFunction %2 None %3
285           %5 = OpLabel
286           %8 = OpVariable %7 Function
287          %10 = OpVariable %7 Function
288          %14 = OpVariable %13 Function
289          %20 = OpVariable %19 Function
290          %22 = OpVariable %19 Function
291          %26 = OpVariable %25 Function
292          %33 = OpVariable %32 Function
293          %35 = OpVariable %32 Function
294          %39 = OpVariable %38 Function
295          %47 = OpVariable %7 Function
296          %51 = OpVariable %7 Function
297          %55 = OpVariable %7 Function
298          %59 = OpVariable %7 Function
299          %63 = OpVariable %19 Function
300          %67 = OpVariable %19 Function
301          %71 = OpVariable %19 Function
302          %75 = OpVariable %19 Function
303          %79 = OpVariable %32 Function
304          %83 = OpVariable %32 Function
305          %87 = OpVariable %32 Function
306          %91 = OpVariable %32 Function
307                OpStore %8 %9
308                OpStore %10 %11
309          %15 = OpLoad %6 %8
310          %16 = OpLoad %6 %10
311          %17 = OpCompositeConstruct %12 %15 %16
312                OpStore %14 %17
313                OpStore %20 %21
314                OpStore %22 %23
315          %27 = OpLoad %18 %20
316          %28 = OpLoad %18 %20
317          %29 = OpLoad %18 %22
318          %30 = OpCompositeConstruct %24 %27 %28 %29
319                OpStore %26 %30
320                OpStore %33 %34
321                OpStore %35 %36
322          %40 = OpLoad %31 %33
323          %41 = OpLoad %31 %33
324          %42 = OpLoad %31 %35
325          %43 = OpLoad %31 %35
326          %44 = OpCompositeConstruct %37 %40 %41 %42 %43
327          %45 = OpLoad %37 %39
328          %46 = OpVectorShuffle %37 %45 %44 5 6 7 4
329                OpStore %39 %46
330          %48 = OpLoad %6 %8
331          %49 = OpLoad %6 %10
332         %100 = OpCompositeConstruct %12 %48 %48
333         %101 = OpCompositeConstruct %12 %49 %49
334         %102 = OpIAdd %12 %100 %101
335          %50 = OpIAdd %6 %48 %49
336                OpStore %47 %50
337          %52 = OpLoad %6 %8
338          %53 = OpLoad %6 %10
339          %54 = OpISub %6 %52 %53
340                OpStore %51 %54
341          %56 = OpLoad %6 %8
342          %57 = OpLoad %6 %10
343          %58 = OpIMul %6 %56 %57
344                OpStore %55 %58
345          %60 = OpLoad %6 %8
346          %61 = OpLoad %6 %10
347          %62 = OpSDiv %6 %60 %61
348                OpStore %59 %62
349          %64 = OpLoad %18 %20
350          %65 = OpLoad %18 %22
351          %66 = OpIAdd %18 %64 %65
352                OpStore %63 %66
353          %68 = OpLoad %18 %20
354          %69 = OpLoad %18 %22
355          %70 = OpISub %18 %68 %69
356                OpStore %67 %70
357          %72 = OpLoad %18 %20
358          %73 = OpLoad %18 %22
359          %74 = OpIMul %18 %72 %73
360                OpStore %71 %74
361          %76 = OpLoad %18 %20
362          %77 = OpLoad %18 %22
363          %78 = OpUDiv %18 %76 %77
364                OpStore %75 %78
365          %80 = OpLoad %31 %33
366          %81 = OpLoad %31 %35
367          %82 = OpFAdd %31 %80 %81
368                OpStore %79 %82
369          %84 = OpLoad %31 %33
370          %85 = OpLoad %31 %35
371          %86 = OpFSub %31 %84 %85
372                OpStore %83 %86
373          %88 = OpLoad %31 %33
374          %89 = OpLoad %31 %35
375          %90 = OpFMul %31 %88 %89
376                OpStore %87 %90
377          %92 = OpLoad %31 %33
378          %93 = OpLoad %31 %35
379          %94 = OpFDiv %31 %92 %93
380                OpStore %91 %94
381                OpReturn
382                OpFunctionEnd
383   )";
384   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
385 }
386 
TEST(TransformationWrapVectorSynonym, OperationSupportTest)387 TEST(TransformationWrapVectorSynonym, OperationSupportTest) {
388   std::string shader = R"(
389                OpCapability Shader
390           %1 = OpExtInstImport "GLSL.std.450"
391                OpMemoryModel Logical GLSL450
392                OpEntryPoint Fragment %4 "main" %97
393                OpExecutionMode %4 OriginUpperLeft
394                OpSource ESSL 310
395                OpName %4 "main"
396           %2 = OpTypeVoid
397           %3 = OpTypeFunction %2
398           %6 = OpTypeInt 32 1
399           %7 = OpTypePointer Function %6
400           %9 = OpConstant %6 10
401          %11 = OpConstant %6 -5
402          %12 = OpTypeVector %6 2
403          %13 = OpTypePointer Function %12
404          %18 = OpTypeInt 32 0
405          %19 = OpTypePointer Function %18
406          %21 = OpConstant %18 8
407          %23 = OpConstant %18 2
408          %24 = OpTypeVector %18 3
409          %25 = OpTypePointer Function %24
410          %31 = OpTypeFloat 32
411          %32 = OpTypePointer Function %31
412          %34 = OpConstant %31 3.29999995
413          %36 = OpConstant %31 1.10000002
414          %37 = OpTypeVector %31 4
415          %38 = OpTypePointer Function %37
416          %96 = OpTypePointer Input %31
417          %97 = OpVariable %96 Input
418           %4 = OpFunction %2 None %3
419           %5 = OpLabel
420           %8 = OpVariable %7 Function
421          %10 = OpVariable %7 Function
422          %14 = OpVariable %13 Function
423          %20 = OpVariable %19 Function
424          %22 = OpVariable %19 Function
425          %26 = OpVariable %25 Function
426          %33 = OpVariable %32 Function
427          %35 = OpVariable %32 Function
428          %39 = OpVariable %38 Function
429          %47 = OpVariable %7 Function
430          %51 = OpVariable %7 Function
431          %55 = OpVariable %7 Function
432          %59 = OpVariable %7 Function
433          %63 = OpVariable %19 Function
434          %67 = OpVariable %19 Function
435          %71 = OpVariable %19 Function
436          %75 = OpVariable %19 Function
437          %79 = OpVariable %32 Function
438          %83 = OpVariable %32 Function
439          %87 = OpVariable %32 Function
440          %91 = OpVariable %32 Function
441                OpStore %8 %9
442                OpStore %10 %11
443          %15 = OpLoad %6 %8
444          %16 = OpLoad %6 %10
445          %17 = OpCompositeConstruct %12 %15 %16
446                OpStore %14 %17
447                OpStore %20 %21
448                OpStore %22 %23
449          %27 = OpLoad %18 %20
450          %28 = OpLoad %18 %20
451          %29 = OpLoad %18 %22
452          %30 = OpCompositeConstruct %24 %27 %28 %29
453                OpStore %26 %30
454                OpStore %33 %34
455                OpStore %35 %36
456          %40 = OpLoad %31 %33
457          %41 = OpLoad %31 %33
458          %42 = OpLoad %31 %35
459          %43 = OpLoad %31 %35
460          %44 = OpCompositeConstruct %37 %40 %41 %42 %43
461          %45 = OpLoad %37 %39
462          %46 = OpVectorShuffle %37 %45 %44 5 6 7 4
463                OpStore %39 %46
464          %48 = OpLoad %6 %8
465          %49 = OpLoad %6 %10
466          %50 = OpIAdd %6 %48 %49
467                OpStore %47 %50
468          %52 = OpLoad %6 %8
469          %53 = OpLoad %6 %10
470         %100 = OpCompositeConstruct %12 %52 %52
471         %101 = OpCompositeConstruct %12 %53 %53
472          %54 = OpISub %6 %52 %53
473                OpStore %51 %54
474          %56 = OpLoad %6 %8
475          %57 = OpLoad %6 %10
476         %103 = OpCompositeConstruct %12 %56 %56
477         %104 = OpCompositeConstruct %12 %57 %57
478          %58 = OpIMul %6 %56 %57
479                OpStore %55 %58
480          %60 = OpLoad %6 %8
481          %61 = OpLoad %6 %10
482          %62 = OpSDiv %6 %60 %61
483                OpStore %59 %62
484          %64 = OpLoad %18 %20
485          %65 = OpLoad %18 %22
486         %106 = OpCompositeConstruct %24 %64 %64 %64
487         %107 = OpCompositeConstruct %24 %65 %65 %65
488          %66 = OpIAdd %18 %64 %65
489                OpStore %63 %66
490          %68 = OpLoad %18 %20
491          %69 = OpLoad %18 %22
492         %109 = OpCompositeConstruct %24 %68 %68 %68
493         %110 = OpCompositeConstruct %24 %69 %69 %69
494          %70 = OpISub %18 %68 %69
495                OpStore %67 %70
496          %72 = OpLoad %18 %20
497          %73 = OpLoad %18 %22
498         %112 = OpCompositeConstruct %24 %72 %72 %72
499         %113 = OpCompositeConstruct %24 %73 %73 %73
500          %74 = OpIMul %18 %72 %73
501                OpStore %71 %74
502          %76 = OpLoad %18 %20
503          %77 = OpLoad %18 %22
504          %78 = OpUDiv %18 %76 %77
505                OpStore %75 %78
506          %80 = OpLoad %31 %33
507          %81 = OpLoad %31 %35
508         %115 = OpCompositeConstruct %37 %80 %80 %80 %80
509         %116 = OpCompositeConstruct %37 %81 %81 %81 %81
510          %82 = OpFAdd %31 %80 %81
511                OpStore %79 %82
512          %84 = OpLoad %31 %33
513          %85 = OpLoad %31 %35
514         %118 = OpCompositeConstruct %37 %84 %84 %84 %84
515         %119 = OpCompositeConstruct %37 %85 %85 %85 %85
516          %86 = OpFSub %31 %84 %85
517                OpStore %83 %86
518          %88 = OpLoad %31 %33
519          %89 = OpLoad %31 %35
520         %121 = OpCompositeConstruct %37 %88 %88 %88 %88
521         %122 = OpCompositeConstruct %37 %89 %89 %89 %89
522          %90 = OpFMul %31 %88 %89
523                OpStore %87 %90
524          %92 = OpLoad %31 %33
525          %93 = OpLoad %31 %35
526          %94 = OpFDiv %31 %92 %93
527                OpStore %91 %94
528                OpReturn
529                OpFunctionEnd
530   )";
531   const auto env = SPV_ENV_UNIVERSAL_1_3;
532   const auto consumer = nullptr;
533   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
534   spvtools::ValidatorOptions validator_options;
535 
536   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
537                                                kConsoleMessageConsumer));
538 
539   TransformationContext transformation_context(
540       MakeUnique<FactManager>(context.get()), validator_options);
541 
542   {
543     // Add synonym facts between the vector operands at pos and the operands to
544     // the scalar instruction.
545     transformation_context.GetFactManager()->AddFactDataSynonym(
546         MakeDataDescriptor(100, {1}), MakeDataDescriptor(52, {}));
547     transformation_context.GetFactManager()->AddFactDataSynonym(
548         MakeDataDescriptor(101, {1}), MakeDataDescriptor(53, {}));
549 
550     transformation_context.GetFactManager()->AddFactDataSynonym(
551         MakeDataDescriptor(103, {0}), MakeDataDescriptor(56, {}));
552     transformation_context.GetFactManager()->AddFactDataSynonym(
553         MakeDataDescriptor(104, {0}), MakeDataDescriptor(57, {}));
554 
555     transformation_context.GetFactManager()->AddFactDataSynonym(
556         MakeDataDescriptor(106, {2}), MakeDataDescriptor(64, {}));
557     transformation_context.GetFactManager()->AddFactDataSynonym(
558         MakeDataDescriptor(107, {2}), MakeDataDescriptor(65, {}));
559 
560     transformation_context.GetFactManager()->AddFactDataSynonym(
561         MakeDataDescriptor(109, {2}), MakeDataDescriptor(68, {}));
562     transformation_context.GetFactManager()->AddFactDataSynonym(
563         MakeDataDescriptor(110, {2}), MakeDataDescriptor(69, {}));
564 
565     transformation_context.GetFactManager()->AddFactDataSynonym(
566         MakeDataDescriptor(112, {1}), MakeDataDescriptor(72, {}));
567     transformation_context.GetFactManager()->AddFactDataSynonym(
568         MakeDataDescriptor(113, {1}), MakeDataDescriptor(73, {}));
569 
570     transformation_context.GetFactManager()->AddFactDataSynonym(
571         MakeDataDescriptor(115, {2}), MakeDataDescriptor(80, {}));
572     transformation_context.GetFactManager()->AddFactDataSynonym(
573         MakeDataDescriptor(116, {2}), MakeDataDescriptor(81, {}));
574 
575     transformation_context.GetFactManager()->AddFactDataSynonym(
576         MakeDataDescriptor(118, {3}), MakeDataDescriptor(84, {}));
577     transformation_context.GetFactManager()->AddFactDataSynonym(
578         MakeDataDescriptor(119, {3}), MakeDataDescriptor(85, {}));
579 
580     transformation_context.GetFactManager()->AddFactDataSynonym(
581         MakeDataDescriptor(121, {1}), MakeDataDescriptor(88, {}));
582     transformation_context.GetFactManager()->AddFactDataSynonym(
583         MakeDataDescriptor(122, {1}), MakeDataDescriptor(89, {}));
584   }
585 
586   // Test OpISub for signed integer.
587   {
588     // Good: The following transformation should be applicable.
589     TransformationWrapVectorSynonym wrap_sub_int(54, 100, 101, 102, 1);
590     ASSERT_TRUE(
591         wrap_sub_int.IsApplicable(context.get(), transformation_context));
592     ApplyAndCheckFreshIds(wrap_sub_int, context.get(), &transformation_context);
593 
594     // |instruction_id| and id at |scalar_position of the result vector should
595     // be synonyms.
596     ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
597         MakeDataDescriptor(102, {1}), MakeDataDescriptor(54, {})));
598   }
599 
600   // Test OpIMul for signed integer.
601   {
602     // Good: The following transformation should be applicable.
603     TransformationWrapVectorSynonym wrap_mul_int(58, 103, 104, 105, 0);
604     ASSERT_TRUE(
605         wrap_mul_int.IsApplicable(context.get(), transformation_context));
606     ApplyAndCheckFreshIds(wrap_mul_int, context.get(), &transformation_context);
607 
608     // |instruction_id| and id at |scalar_position of the result vector should
609     // be synonyms.
610     ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
611         MakeDataDescriptor(105, {0}), MakeDataDescriptor(58, {})));
612   }
613 
614   // Test OpIAdd for unsigned integer.
615   {
616     // Good: The following transformation should be applicable.
617     TransformationWrapVectorSynonym wrap_add_uint(66, 106, 107, 108, 2);
618     ASSERT_TRUE(
619         wrap_add_uint.IsApplicable(context.get(), transformation_context));
620     ApplyAndCheckFreshIds(wrap_add_uint, context.get(),
621                           &transformation_context);
622 
623     // |instruction_id| and id at |scalar_position of the result vector should
624     // be synonyms.
625     ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
626         MakeDataDescriptor(108, {2}), MakeDataDescriptor(66, {})));
627   }
628 
629   // Test OpISub for signed integer.
630   {
631     // Good: The following transformation should be applicable.
632     TransformationWrapVectorSynonym wrap_sub_uint(70, 109, 110, 111, 2);
633     ASSERT_TRUE(
634         wrap_sub_uint.IsApplicable(context.get(), transformation_context));
635     ApplyAndCheckFreshIds(wrap_sub_uint, context.get(),
636                           &transformation_context);
637 
638     // |instruction_id| and id at |scalar_position of the result vector should
639     // be synonyms.
640     ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
641         MakeDataDescriptor(111, {2}), MakeDataDescriptor(70, {})));
642   }
643 
644   // Test OpIMul for signed integer.
645   {
646     // Good: The following transformation should be applicable.
647     TransformationWrapVectorSynonym wrap_mul_uint(74, 112, 113, 114, 1);
648     ASSERT_TRUE(
649         wrap_mul_uint.IsApplicable(context.get(), transformation_context));
650     ApplyAndCheckFreshIds(wrap_mul_uint, context.get(),
651                           &transformation_context);
652 
653     // |instruction_id| and id at |scalar_position of the result vector should
654     // be synonyms.
655     ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
656         MakeDataDescriptor(114, {1}), MakeDataDescriptor(74, {})));
657   }
658 
659   // Test OpFAdd for float.
660   {
661     // Good: The following transformation should be applicable.
662     TransformationWrapVectorSynonym wrap_add_float(82, 115, 116, 117, 2);
663     ASSERT_TRUE(
664         wrap_add_float.IsApplicable(context.get(), transformation_context));
665     ApplyAndCheckFreshIds(wrap_add_float, context.get(),
666                           &transformation_context);
667 
668     // |instruction_id| and id at |scalar_position of the result vector should
669     // be synonyms.
670     ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
671         MakeDataDescriptor(117, {2}), MakeDataDescriptor(82, {})));
672   }
673 
674   // Test OpFSub for float.
675   {
676     // Good: The following transformation should be applicable.
677     TransformationWrapVectorSynonym wrap_add_float(86, 118, 119, 120, 3);
678     ASSERT_TRUE(
679         wrap_add_float.IsApplicable(context.get(), transformation_context));
680     ApplyAndCheckFreshIds(wrap_add_float, context.get(),
681                           &transformation_context);
682 
683     // |instruction_id| and id at |scalar_position of the result vector should
684     // be synonyms.
685     ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
686         MakeDataDescriptor(120, {3}), MakeDataDescriptor(86, {})));
687   }
688 
689   // Test OpFMul for float.
690   {
691     // Good: The following transformation should be applicable.
692     TransformationWrapVectorSynonym wrap_mul_float(90, 121, 122, 123, 1);
693     ASSERT_TRUE(
694         wrap_mul_float.IsApplicable(context.get(), transformation_context));
695     ApplyAndCheckFreshIds(wrap_mul_float, context.get(),
696                           &transformation_context);
697 
698     // |instruction_id| and id at |scalar_position of the result vector should
699     // be synonyms.
700     ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
701         MakeDataDescriptor(123, {1}), MakeDataDescriptor(90, {})));
702   }
703 
704   std::string after_transformation = R"(
705                OpCapability Shader
706           %1 = OpExtInstImport "GLSL.std.450"
707                OpMemoryModel Logical GLSL450
708                OpEntryPoint Fragment %4 "main" %97
709                OpExecutionMode %4 OriginUpperLeft
710                OpSource ESSL 310
711                OpName %4 "main"
712           %2 = OpTypeVoid
713           %3 = OpTypeFunction %2
714           %6 = OpTypeInt 32 1
715           %7 = OpTypePointer Function %6
716           %9 = OpConstant %6 10
717          %11 = OpConstant %6 -5
718          %12 = OpTypeVector %6 2
719          %13 = OpTypePointer Function %12
720          %18 = OpTypeInt 32 0
721          %19 = OpTypePointer Function %18
722          %21 = OpConstant %18 8
723          %23 = OpConstant %18 2
724          %24 = OpTypeVector %18 3
725          %25 = OpTypePointer Function %24
726          %31 = OpTypeFloat 32
727          %32 = OpTypePointer Function %31
728          %34 = OpConstant %31 3.29999995
729          %36 = OpConstant %31 1.10000002
730          %37 = OpTypeVector %31 4
731          %38 = OpTypePointer Function %37
732          %96 = OpTypePointer Input %31
733          %97 = OpVariable %96 Input
734           %4 = OpFunction %2 None %3
735           %5 = OpLabel
736           %8 = OpVariable %7 Function
737          %10 = OpVariable %7 Function
738          %14 = OpVariable %13 Function
739          %20 = OpVariable %19 Function
740          %22 = OpVariable %19 Function
741          %26 = OpVariable %25 Function
742          %33 = OpVariable %32 Function
743          %35 = OpVariable %32 Function
744          %39 = OpVariable %38 Function
745          %47 = OpVariable %7 Function
746          %51 = OpVariable %7 Function
747          %55 = OpVariable %7 Function
748          %59 = OpVariable %7 Function
749          %63 = OpVariable %19 Function
750          %67 = OpVariable %19 Function
751          %71 = OpVariable %19 Function
752          %75 = OpVariable %19 Function
753          %79 = OpVariable %32 Function
754          %83 = OpVariable %32 Function
755          %87 = OpVariable %32 Function
756          %91 = OpVariable %32 Function
757                OpStore %8 %9
758                OpStore %10 %11
759          %15 = OpLoad %6 %8
760          %16 = OpLoad %6 %10
761          %17 = OpCompositeConstruct %12 %15 %16
762                OpStore %14 %17
763                OpStore %20 %21
764                OpStore %22 %23
765          %27 = OpLoad %18 %20
766          %28 = OpLoad %18 %20
767          %29 = OpLoad %18 %22
768          %30 = OpCompositeConstruct %24 %27 %28 %29
769                OpStore %26 %30
770                OpStore %33 %34
771                OpStore %35 %36
772          %40 = OpLoad %31 %33
773          %41 = OpLoad %31 %33
774          %42 = OpLoad %31 %35
775          %43 = OpLoad %31 %35
776          %44 = OpCompositeConstruct %37 %40 %41 %42 %43
777          %45 = OpLoad %37 %39
778          %46 = OpVectorShuffle %37 %45 %44 5 6 7 4
779                OpStore %39 %46
780          %48 = OpLoad %6 %8
781          %49 = OpLoad %6 %10
782          %50 = OpIAdd %6 %48 %49
783                OpStore %47 %50
784          %52 = OpLoad %6 %8
785          %53 = OpLoad %6 %10
786         %100 = OpCompositeConstruct %12 %52 %52
787         %101 = OpCompositeConstruct %12 %53 %53
788         %102 = OpISub %12 %100 %101
789          %54 = OpISub %6 %52 %53
790                OpStore %51 %54
791          %56 = OpLoad %6 %8
792          %57 = OpLoad %6 %10
793         %103 = OpCompositeConstruct %12 %56 %56
794         %104 = OpCompositeConstruct %12 %57 %57
795         %105 = OpIMul %12 %103 %104
796          %58 = OpIMul %6 %56 %57
797                OpStore %55 %58
798          %60 = OpLoad %6 %8
799          %61 = OpLoad %6 %10
800          %62 = OpSDiv %6 %60 %61
801                OpStore %59 %62
802          %64 = OpLoad %18 %20
803          %65 = OpLoad %18 %22
804         %106 = OpCompositeConstruct %24 %64 %64 %64
805         %107 = OpCompositeConstruct %24 %65 %65 %65
806         %108 = OpIAdd %24 %106 %107
807          %66 = OpIAdd %18 %64 %65
808                OpStore %63 %66
809          %68 = OpLoad %18 %20
810          %69 = OpLoad %18 %22
811         %109 = OpCompositeConstruct %24 %68 %68 %68
812         %110 = OpCompositeConstruct %24 %69 %69 %69
813         %111 = OpISub %24 %109 %110
814          %70 = OpISub %18 %68 %69
815                OpStore %67 %70
816          %72 = OpLoad %18 %20
817          %73 = OpLoad %18 %22
818         %112 = OpCompositeConstruct %24 %72 %72 %72
819         %113 = OpCompositeConstruct %24 %73 %73 %73
820         %114 = OpIMul %24 %112 %113
821          %74 = OpIMul %18 %72 %73
822                OpStore %71 %74
823          %76 = OpLoad %18 %20
824          %77 = OpLoad %18 %22
825          %78 = OpUDiv %18 %76 %77
826                OpStore %75 %78
827          %80 = OpLoad %31 %33
828          %81 = OpLoad %31 %35
829         %115 = OpCompositeConstruct %37 %80 %80 %80 %80
830         %116 = OpCompositeConstruct %37 %81 %81 %81 %81
831         %117 = OpFAdd %37 %115 %116
832          %82 = OpFAdd %31 %80 %81
833                OpStore %79 %82
834          %84 = OpLoad %31 %33
835          %85 = OpLoad %31 %35
836         %118 = OpCompositeConstruct %37 %84 %84 %84 %84
837         %119 = OpCompositeConstruct %37 %85 %85 %85 %85
838         %120 = OpFSub %37 %118 %119
839          %86 = OpFSub %31 %84 %85
840                OpStore %83 %86
841          %88 = OpLoad %31 %33
842          %89 = OpLoad %31 %35
843         %121 = OpCompositeConstruct %37 %88 %88 %88 %88
844         %122 = OpCompositeConstruct %37 %89 %89 %89 %89
845         %123 = OpFMul %37 %121 %122
846          %90 = OpFMul %31 %88 %89
847                OpStore %87 %90
848          %92 = OpLoad %31 %33
849          %93 = OpLoad %31 %35
850          %94 = OpFDiv %31 %92 %93
851                OpStore %91 %94
852                OpReturn
853                OpFunctionEnd
854   )";
855   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
856 }
857 
TEST(TransformationWrapVectorSynonym, DivSupportTest)858 TEST(TransformationWrapVectorSynonym, DivSupportTest) {
859   std::string shader = R"(
860                OpCapability Shader
861           %1 = OpExtInstImport "GLSL.std.450"
862                OpMemoryModel Logical GLSL450
863                OpEntryPoint Fragment %4 "main" %97
864                OpExecutionMode %4 OriginUpperLeft
865                OpSource ESSL 310
866                OpName %4 "main"
867           %2 = OpTypeVoid
868           %3 = OpTypeFunction %2
869           %6 = OpTypeInt 32 1
870           %7 = OpTypePointer Function %6
871           %9 = OpConstant %6 10
872          %11 = OpConstant %6 -5
873          %12 = OpTypeVector %6 2
874          %13 = OpTypePointer Function %12
875          %18 = OpTypeInt 32 0
876          %19 = OpTypePointer Function %18
877          %21 = OpConstant %18 8
878          %23 = OpConstant %18 2
879          %24 = OpTypeVector %18 3
880          %25 = OpTypePointer Function %24
881          %31 = OpTypeFloat 32
882          %32 = OpTypePointer Function %31
883          %34 = OpConstant %31 3.29999995
884          %36 = OpConstant %31 1.10000002
885          %37 = OpTypeVector %31 4
886          %38 = OpTypePointer Function %37
887          %96 = OpTypePointer Input %31
888          %97 = OpVariable %96 Input
889           %4 = OpFunction %2 None %3
890           %5 = OpLabel
891           %8 = OpVariable %7 Function
892          %10 = OpVariable %7 Function
893          %14 = OpVariable %13 Function
894          %20 = OpVariable %19 Function
895          %22 = OpVariable %19 Function
896          %26 = OpVariable %25 Function
897          %33 = OpVariable %32 Function
898          %35 = OpVariable %32 Function
899          %39 = OpVariable %38 Function
900          %47 = OpVariable %7 Function
901          %51 = OpVariable %7 Function
902          %55 = OpVariable %7 Function
903          %59 = OpVariable %7 Function
904          %63 = OpVariable %19 Function
905          %67 = OpVariable %19 Function
906          %71 = OpVariable %19 Function
907          %75 = OpVariable %19 Function
908          %79 = OpVariable %32 Function
909          %83 = OpVariable %32 Function
910          %87 = OpVariable %32 Function
911          %91 = OpVariable %32 Function
912                OpStore %8 %9
913                OpStore %10 %11
914          %15 = OpLoad %6 %8
915          %16 = OpLoad %6 %10
916          %17 = OpCompositeConstruct %12 %15 %16
917                OpStore %14 %17
918                OpStore %20 %21
919                OpStore %22 %23
920          %27 = OpLoad %18 %20
921          %28 = OpLoad %18 %20
922          %29 = OpLoad %18 %22
923          %30 = OpCompositeConstruct %24 %27 %28 %29
924                OpStore %26 %30
925                OpStore %33 %34
926                OpStore %35 %36
927          %40 = OpLoad %31 %33
928          %41 = OpLoad %31 %33
929          %42 = OpLoad %31 %35
930          %43 = OpLoad %31 %35
931          %44 = OpCompositeConstruct %37 %40 %41 %42 %43
932          %45 = OpLoad %37 %39
933          %46 = OpVectorShuffle %37 %45 %44 5 6 7 4
934                OpStore %39 %46
935          %48 = OpLoad %6 %8
936          %49 = OpLoad %6 %10
937          %50 = OpIAdd %6 %48 %49
938                OpStore %47 %50
939          %52 = OpLoad %6 %8
940          %53 = OpLoad %6 %10
941          %54 = OpISub %6 %52 %53
942                OpStore %51 %54
943          %56 = OpLoad %6 %8
944          %57 = OpLoad %6 %10
945          %58 = OpIMul %6 %56 %57
946                OpStore %55 %58
947          %60 = OpLoad %6 %8
948          %61 = OpLoad %6 %10
949         %100 = OpCompositeConstruct %12 %60 %60
950         %101 = OpCompositeConstruct %12 %61 %61
951          %62 = OpSDiv %6 %60 %61
952                OpStore %59 %62
953          %64 = OpLoad %18 %20
954          %65 = OpLoad %18 %22
955          %66 = OpIAdd %18 %64 %65
956                OpStore %63 %66
957          %68 = OpLoad %18 %20
958          %69 = OpLoad %18 %22
959          %70 = OpISub %18 %68 %69
960                OpStore %67 %70
961          %72 = OpLoad %18 %20
962          %73 = OpLoad %18 %22
963          %74 = OpIMul %18 %72 %73
964                OpStore %71 %74
965          %76 = OpLoad %18 %20
966          %77 = OpLoad %18 %22
967         %102 = OpCompositeConstruct %24 %76 %76 %76
968         %103 = OpCompositeConstruct %24 %77 %77 %77
969          %78 = OpUDiv %18 %76 %77
970                OpStore %75 %78
971          %80 = OpLoad %31 %33
972          %81 = OpLoad %31 %35
973          %82 = OpFAdd %31 %80 %81
974                OpStore %79 %82
975          %84 = OpLoad %31 %33
976          %85 = OpLoad %31 %35
977          %86 = OpFSub %31 %84 %85
978                OpStore %83 %86
979          %88 = OpLoad %31 %33
980          %89 = OpLoad %31 %35
981          %90 = OpFMul %31 %88 %89
982                OpStore %87 %90
983          %92 = OpLoad %31 %33
984          %93 = OpLoad %31 %35
985         %104 = OpCompositeConstruct %37 %92 %92 %92 %92
986         %105 = OpCompositeConstruct %37 %93 %93 %93 %93
987          %94 = OpFDiv %31 %92 %93
988                OpStore %91 %94
989                OpReturn
990                OpFunctionEnd
991   )";
992   const auto env = SPV_ENV_UNIVERSAL_1_3;
993   const auto consumer = nullptr;
994   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
995   spvtools::ValidatorOptions validator_options;
996 
997   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
998                                                kConsoleMessageConsumer));
999 
1000   TransformationContext transformation_context(
1001       MakeUnique<FactManager>(context.get()), validator_options);
1002 
1003   transformation_context.GetFactManager()->AddFactDataSynonym(
1004       MakeDataDescriptor(100, {1}), MakeDataDescriptor(60, {}));
1005   transformation_context.GetFactManager()->AddFactDataSynonym(
1006       MakeDataDescriptor(101, {1}), MakeDataDescriptor(61, {}));
1007 
1008   transformation_context.GetFactManager()->AddFactDataSynonym(
1009       MakeDataDescriptor(102, {1}), MakeDataDescriptor(76, {}));
1010   transformation_context.GetFactManager()->AddFactDataSynonym(
1011       MakeDataDescriptor(103, {1}), MakeDataDescriptor(77, {}));
1012 
1013   transformation_context.GetFactManager()->AddFactDataSynonym(
1014       MakeDataDescriptor(104, {1}), MakeDataDescriptor(92, {}));
1015   transformation_context.GetFactManager()->AddFactDataSynonym(
1016       MakeDataDescriptor(105, {1}), MakeDataDescriptor(93, {}));
1017 
1018   // Div operations are not currently supported.
1019   {
1020     TransformationWrapVectorSynonym wrap_div_bad1(62, 100, 101, 106, 1);
1021     ASSERT_FALSE(
1022         wrap_div_bad1.IsApplicable(context.get(), transformation_context));
1023 
1024     TransformationWrapVectorSynonym wrap_div_bad2(78, 102, 103, 106, 1);
1025     ASSERT_FALSE(
1026         wrap_div_bad2.IsApplicable(context.get(), transformation_context));
1027 
1028     TransformationWrapVectorSynonym wrap_div_bad3(94, 104, 105, 106, 1);
1029     ASSERT_FALSE(
1030         wrap_div_bad3.IsApplicable(context.get(), transformation_context));
1031   }
1032 }
1033 
TEST(TransformationWrapVectorSynonym, AdditionalWidthSupportTest)1034 TEST(TransformationWrapVectorSynonym, AdditionalWidthSupportTest) {
1035   std::string shader = R"(
1036                OpCapability Shader
1037                OpCapability Int64
1038                OpCapability Float64
1039           %1 = OpExtInstImport "GLSL.std.450"
1040                OpMemoryModel Logical GLSL450
1041                OpEntryPoint Fragment %4 "main" %97
1042                OpExecutionMode %4 OriginUpperLeft
1043                OpSource ESSL 310
1044                OpName %4 "main"
1045           %2 = OpTypeVoid
1046           %3 = OpTypeFunction %2
1047           %6 = OpTypeInt 64 1
1048           %7 = OpTypePointer Function %6
1049           %9 = OpConstant %6 10
1050          %11 = OpConstant %6 -5
1051          %12 = OpTypeVector %6 2
1052          %13 = OpTypePointer Function %12
1053          %18 = OpTypeInt 64 0
1054          %19 = OpTypePointer Function %18
1055          %21 = OpConstant %18 8
1056          %23 = OpConstant %18 2
1057          %24 = OpTypeVector %18 3
1058          %25 = OpTypePointer Function %24
1059          %31 = OpTypeFloat 64
1060          %32 = OpTypePointer Function %31
1061          %34 = OpConstant %31 3.29999995
1062          %36 = OpConstant %31 1.10000002
1063          %37 = OpTypeVector %31 4
1064          %38 = OpTypePointer Function %37
1065          %96 = OpTypePointer Input %31
1066          %97 = OpVariable %96 Input
1067           %4 = OpFunction %2 None %3
1068           %5 = OpLabel
1069           %8 = OpVariable %7 Function
1070          %10 = OpVariable %7 Function
1071          %14 = OpVariable %13 Function
1072          %20 = OpVariable %19 Function
1073          %22 = OpVariable %19 Function
1074          %26 = OpVariable %25 Function
1075          %33 = OpVariable %32 Function
1076          %35 = OpVariable %32 Function
1077          %39 = OpVariable %38 Function
1078          %47 = OpVariable %7 Function
1079          %51 = OpVariable %7 Function
1080          %55 = OpVariable %7 Function
1081          %59 = OpVariable %7 Function
1082          %63 = OpVariable %19 Function
1083          %67 = OpVariable %19 Function
1084          %71 = OpVariable %19 Function
1085          %75 = OpVariable %19 Function
1086          %79 = OpVariable %32 Function
1087          %83 = OpVariable %32 Function
1088          %87 = OpVariable %32 Function
1089          %91 = OpVariable %32 Function
1090                OpStore %8 %9
1091                OpStore %10 %11
1092          %15 = OpLoad %6 %8
1093          %16 = OpLoad %6 %10
1094          %17 = OpCompositeConstruct %12 %15 %16
1095                OpStore %14 %17
1096                OpStore %20 %21
1097                OpStore %22 %23
1098          %27 = OpLoad %18 %20
1099          %28 = OpLoad %18 %20
1100          %29 = OpLoad %18 %22
1101          %30 = OpCompositeConstruct %24 %27 %28 %29
1102                OpStore %26 %30
1103                OpStore %33 %34
1104                OpStore %35 %36
1105          %40 = OpLoad %31 %33
1106          %41 = OpLoad %31 %33
1107          %42 = OpLoad %31 %35
1108          %43 = OpLoad %31 %35
1109          %44 = OpCompositeConstruct %37 %40 %41 %42 %43
1110          %45 = OpLoad %37 %39
1111          %46 = OpVectorShuffle %37 %45 %44 5 6 7 4
1112                OpStore %39 %46
1113          %48 = OpLoad %6 %8
1114          %49 = OpLoad %6 %10
1115         %100 = OpCompositeConstruct %12 %48 %48
1116         %101 = OpCompositeConstruct %12 %49 %49
1117          %50 = OpIAdd %6 %48 %49
1118                OpStore %47 %50
1119          %52 = OpLoad %6 %8
1120          %53 = OpLoad %6 %10
1121          %54 = OpISub %6 %52 %53
1122                OpStore %51 %54
1123          %56 = OpLoad %6 %8
1124          %57 = OpLoad %6 %10
1125          %58 = OpIMul %6 %56 %57
1126                OpStore %55 %58
1127          %60 = OpLoad %6 %8
1128          %61 = OpLoad %6 %10
1129          %62 = OpSDiv %6 %60 %61
1130                OpStore %59 %62
1131          %64 = OpLoad %18 %20
1132          %65 = OpLoad %18 %22
1133          %66 = OpIAdd %18 %64 %65
1134                OpStore %63 %66
1135          %68 = OpLoad %18 %20
1136          %69 = OpLoad %18 %22
1137         %103 = OpCompositeConstruct %24 %68 %68 %68
1138         %104 = OpCompositeConstruct %24 %69 %69 %69
1139          %70 = OpISub %18 %68 %69
1140                OpStore %67 %70
1141          %72 = OpLoad %18 %20
1142          %73 = OpLoad %18 %22
1143          %74 = OpIMul %18 %72 %73
1144                OpStore %71 %74
1145          %76 = OpLoad %18 %20
1146          %77 = OpLoad %18 %22
1147          %78 = OpUDiv %18 %76 %77
1148                OpStore %75 %78
1149          %80 = OpLoad %31 %33
1150          %81 = OpLoad %31 %35
1151          %82 = OpFAdd %31 %80 %81
1152                OpStore %79 %82
1153          %84 = OpLoad %31 %33
1154          %85 = OpLoad %31 %35
1155          %86 = OpFSub %31 %84 %85
1156                OpStore %83 %86
1157          %88 = OpLoad %31 %33
1158          %89 = OpLoad %31 %35
1159         %106 = OpCompositeConstruct %37 %88 %88 %88 %88
1160         %107 = OpCompositeConstruct %37 %89 %89 %89 %89
1161          %90 = OpFMul %31 %88 %89
1162                OpStore %87 %90
1163          %92 = OpLoad %31 %33
1164          %93 = OpLoad %31 %35
1165          %94 = OpFDiv %31 %92 %93
1166                OpStore %91 %94
1167                OpReturn
1168                OpFunctionEnd
1169   )";
1170   const auto env = SPV_ENV_UNIVERSAL_1_3;
1171   const auto consumer = nullptr;
1172   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1173   spvtools::ValidatorOptions validator_options;
1174 
1175   // Check context validity.
1176   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1177                                                kConsoleMessageConsumer));
1178 
1179   TransformationContext transformation_context(
1180       MakeUnique<FactManager>(context.get()), validator_options);
1181 
1182   // Vec Type Id |   Vector Type  |  Element Type id |   Element Type  |
1183   // ------------+----------------+------------------+-----------------+
1184   //     12      |      vec2      |         6        |      int64      |
1185   //     24      |      vec3      |        18        |     uint64      |
1186   //     37      |      vec4      |        31        |    float64      |
1187 
1188   // Test support for 64-bit signed int.
1189   {
1190     // Assert that the target scalar instruction result id is relevant.
1191     ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(50));
1192     transformation_context.GetFactManager()->AddFactDataSynonym(
1193         MakeDataDescriptor(100, {1}), MakeDataDescriptor(48, {}));
1194     transformation_context.GetFactManager()->AddFactDataSynonym(
1195         MakeDataDescriptor(101, {1}), MakeDataDescriptor(49, {}));
1196 
1197     // Good: The following transformation should be applicable.
1198     TransformationWrapVectorSynonym wrap_add_int64(50, 100, 101, 102, 1);
1199     ASSERT_TRUE(
1200         wrap_add_int64.IsApplicable(context.get(), transformation_context));
1201     // Insert an arithmetic instruction of the same type to add two vectors.
1202     ApplyAndCheckFreshIds(wrap_add_int64, context.get(),
1203                           &transformation_context);
1204 
1205     // |instruction_id| and id at |scalar_position of the result vector should
1206     // be synonyms.
1207     ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1208         MakeDataDescriptor(102, {1}), MakeDataDescriptor(50, {})));
1209   }
1210 
1211   // Test support for 64-bit unsigned int.
1212   {
1213     ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(70));
1214     transformation_context.GetFactManager()->AddFactDataSynonym(
1215         MakeDataDescriptor(103, {2}), MakeDataDescriptor(68, {}));
1216     transformation_context.GetFactManager()->AddFactDataSynonym(
1217         MakeDataDescriptor(104, {2}), MakeDataDescriptor(69, {}));
1218 
1219     // Good: The following transformation should be applicable.
1220     TransformationWrapVectorSynonym wrap_sub_uint64(70, 103, 104, 105, 2);
1221     ASSERT_TRUE(
1222         wrap_sub_uint64.IsApplicable(context.get(), transformation_context));
1223 
1224     ApplyAndCheckFreshIds(wrap_sub_uint64, context.get(),
1225                           &transformation_context);
1226 
1227     ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1228         MakeDataDescriptor(105, {2}), MakeDataDescriptor(70, {})));
1229   }
1230 
1231   // Test support for 64-bit float.
1232   {
1233     ASSERT_FALSE(transformation_context.GetFactManager()->IdIsIrrelevant(90));
1234     transformation_context.GetFactManager()->AddFactDataSynonym(
1235         MakeDataDescriptor(106, {3}), MakeDataDescriptor(88, {}));
1236     transformation_context.GetFactManager()->AddFactDataSynonym(
1237         MakeDataDescriptor(107, {3}), MakeDataDescriptor(89, {}));
1238 
1239     // Good: The following transformation should be applicable.
1240     TransformationWrapVectorSynonym wrap_mul_float64(90, 106, 107, 108, 3);
1241     ASSERT_TRUE(
1242         wrap_mul_float64.IsApplicable(context.get(), transformation_context));
1243 
1244     ApplyAndCheckFreshIds(wrap_mul_float64, context.get(),
1245                           &transformation_context);
1246 
1247     ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1248         MakeDataDescriptor(108, {3}), MakeDataDescriptor(90, {})));
1249   }
1250 
1251   std::string after_transformation = R"(
1252                OpCapability Shader
1253                OpCapability Int64
1254                OpCapability Float64
1255           %1 = OpExtInstImport "GLSL.std.450"
1256                OpMemoryModel Logical GLSL450
1257                OpEntryPoint Fragment %4 "main" %97
1258                OpExecutionMode %4 OriginUpperLeft
1259                OpSource ESSL 310
1260                OpName %4 "main"
1261           %2 = OpTypeVoid
1262           %3 = OpTypeFunction %2
1263           %6 = OpTypeInt 64 1
1264           %7 = OpTypePointer Function %6
1265           %9 = OpConstant %6 10
1266          %11 = OpConstant %6 -5
1267          %12 = OpTypeVector %6 2
1268          %13 = OpTypePointer Function %12
1269          %18 = OpTypeInt 64 0
1270          %19 = OpTypePointer Function %18
1271          %21 = OpConstant %18 8
1272          %23 = OpConstant %18 2
1273          %24 = OpTypeVector %18 3
1274          %25 = OpTypePointer Function %24
1275          %31 = OpTypeFloat 64
1276          %32 = OpTypePointer Function %31
1277          %34 = OpConstant %31 3.29999995
1278          %36 = OpConstant %31 1.10000002
1279          %37 = OpTypeVector %31 4
1280          %38 = OpTypePointer Function %37
1281          %96 = OpTypePointer Input %31
1282          %97 = OpVariable %96 Input
1283           %4 = OpFunction %2 None %3
1284           %5 = OpLabel
1285           %8 = OpVariable %7 Function
1286          %10 = OpVariable %7 Function
1287          %14 = OpVariable %13 Function
1288          %20 = OpVariable %19 Function
1289          %22 = OpVariable %19 Function
1290          %26 = OpVariable %25 Function
1291          %33 = OpVariable %32 Function
1292          %35 = OpVariable %32 Function
1293          %39 = OpVariable %38 Function
1294          %47 = OpVariable %7 Function
1295          %51 = OpVariable %7 Function
1296          %55 = OpVariable %7 Function
1297          %59 = OpVariable %7 Function
1298          %63 = OpVariable %19 Function
1299          %67 = OpVariable %19 Function
1300          %71 = OpVariable %19 Function
1301          %75 = OpVariable %19 Function
1302          %79 = OpVariable %32 Function
1303          %83 = OpVariable %32 Function
1304          %87 = OpVariable %32 Function
1305          %91 = OpVariable %32 Function
1306                OpStore %8 %9
1307                OpStore %10 %11
1308          %15 = OpLoad %6 %8
1309          %16 = OpLoad %6 %10
1310          %17 = OpCompositeConstruct %12 %15 %16
1311                OpStore %14 %17
1312                OpStore %20 %21
1313                OpStore %22 %23
1314          %27 = OpLoad %18 %20
1315          %28 = OpLoad %18 %20
1316          %29 = OpLoad %18 %22
1317          %30 = OpCompositeConstruct %24 %27 %28 %29
1318                OpStore %26 %30
1319                OpStore %33 %34
1320                OpStore %35 %36
1321          %40 = OpLoad %31 %33
1322          %41 = OpLoad %31 %33
1323          %42 = OpLoad %31 %35
1324          %43 = OpLoad %31 %35
1325          %44 = OpCompositeConstruct %37 %40 %41 %42 %43
1326          %45 = OpLoad %37 %39
1327          %46 = OpVectorShuffle %37 %45 %44 5 6 7 4
1328                OpStore %39 %46
1329          %48 = OpLoad %6 %8
1330          %49 = OpLoad %6 %10
1331         %100 = OpCompositeConstruct %12 %48 %48
1332         %101 = OpCompositeConstruct %12 %49 %49
1333         %102 = OpIAdd %12 %100 %101
1334          %50 = OpIAdd %6 %48 %49
1335                OpStore %47 %50
1336          %52 = OpLoad %6 %8
1337          %53 = OpLoad %6 %10
1338          %54 = OpISub %6 %52 %53
1339                OpStore %51 %54
1340          %56 = OpLoad %6 %8
1341          %57 = OpLoad %6 %10
1342          %58 = OpIMul %6 %56 %57
1343                OpStore %55 %58
1344          %60 = OpLoad %6 %8
1345          %61 = OpLoad %6 %10
1346          %62 = OpSDiv %6 %60 %61
1347                OpStore %59 %62
1348          %64 = OpLoad %18 %20
1349          %65 = OpLoad %18 %22
1350          %66 = OpIAdd %18 %64 %65
1351                OpStore %63 %66
1352          %68 = OpLoad %18 %20
1353          %69 = OpLoad %18 %22
1354         %103 = OpCompositeConstruct %24 %68 %68 %68
1355         %104 = OpCompositeConstruct %24 %69 %69 %69
1356         %105 = OpISub %24 %103 %104
1357          %70 = OpISub %18 %68 %69
1358                OpStore %67 %70
1359          %72 = OpLoad %18 %20
1360          %73 = OpLoad %18 %22
1361          %74 = OpIMul %18 %72 %73
1362                OpStore %71 %74
1363          %76 = OpLoad %18 %20
1364          %77 = OpLoad %18 %22
1365          %78 = OpUDiv %18 %76 %77
1366                OpStore %75 %78
1367          %80 = OpLoad %31 %33
1368          %81 = OpLoad %31 %35
1369          %82 = OpFAdd %31 %80 %81
1370                OpStore %79 %82
1371          %84 = OpLoad %31 %33
1372          %85 = OpLoad %31 %35
1373          %86 = OpFSub %31 %84 %85
1374                OpStore %83 %86
1375          %88 = OpLoad %31 %33
1376          %89 = OpLoad %31 %35
1377         %106 = OpCompositeConstruct %37 %88 %88 %88 %88
1378         %107 = OpCompositeConstruct %37 %89 %89 %89 %89
1379         %108 = OpFMul %37 %106 %107
1380          %90 = OpFMul %31 %88 %89
1381                OpStore %87 %90
1382          %92 = OpLoad %31 %33
1383          %93 = OpLoad %31 %35
1384          %94 = OpFDiv %31 %92 %93
1385                OpStore %91 %94
1386                OpReturn
1387                OpFunctionEnd
1388   )";
1389   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
1390 }
1391 
TEST(TransformationWrapVectorSynonym, DifferentVectorSignedness)1392 TEST(TransformationWrapVectorSynonym, DifferentVectorSignedness) {
1393   std::string shader = R"(
1394                OpCapability Shader
1395           %1 = OpExtInstImport "GLSL.std.450"
1396                OpMemoryModel Logical GLSL450
1397                OpEntryPoint Fragment %4 "main"
1398                OpExecutionMode %4 OriginUpperLeft
1399                OpSource ESSL 320
1400           %2 = OpTypeVoid
1401           %3 = OpTypeFunction %2
1402           %6 = OpTypeInt 32 1
1403           %7 = OpTypeVector %6 2
1404           %8 = OpTypePointer Function %7
1405          %10 = OpConstant %6 1
1406          %11 = OpConstant %6 0
1407          %12 = OpConstantComposite %7 %10 %11
1408          %14 = OpTypeInt 32 0
1409          %15 = OpTypeVector %14 2
1410          %18 = OpConstant %14 3
1411          %19 = OpConstant %14 0
1412          %20 = OpConstantComposite %15 %18 %19
1413          %21 = OpConstantComposite %15 %19 %18
1414           %4 = OpFunction %2 None %3
1415           %5 = OpLabel
1416         %100 = OpIAdd %14 %10 %18
1417         %101 = OpIAdd %6 %10 %18
1418         %102 = OpIAdd %6 %18 %19
1419                OpReturn
1420                OpFunctionEnd
1421   )";
1422   const auto env = SPV_ENV_UNIVERSAL_1_3;
1423   const auto consumer = nullptr;
1424   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1425   spvtools::ValidatorOptions validator_options;
1426 
1427   // Check context validity.
1428   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1429                                                kConsoleMessageConsumer));
1430 
1431   TransformationContext transformation_context(
1432       MakeUnique<FactManager>(context.get()), validator_options);
1433 
1434   transformation_context.GetFactManager()->AddFactDataSynonym(
1435       MakeDataDescriptor(10, {}), MakeDataDescriptor(12, {0}));
1436   transformation_context.GetFactManager()->AddFactDataSynonym(
1437       MakeDataDescriptor(18, {}), MakeDataDescriptor(20, {0}));
1438   transformation_context.GetFactManager()->AddFactDataSynonym(
1439       MakeDataDescriptor(19, {}), MakeDataDescriptor(21, {0}));
1440 
1441   {
1442     TransformationWrapVectorSynonym transformation1(100, 12, 20, 200, 0);
1443     ASSERT_TRUE(
1444         transformation1.IsApplicable(context.get(), transformation_context));
1445     ApplyAndCheckFreshIds(transformation1, context.get(),
1446                           &transformation_context);
1447     ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1448         MakeDataDescriptor(200, {0}), MakeDataDescriptor(100, {})));
1449   }
1450 
1451   {
1452     TransformationWrapVectorSynonym transformation2(101, 12, 20, 201, 0);
1453     ASSERT_TRUE(
1454         transformation2.IsApplicable(context.get(), transformation_context));
1455     ApplyAndCheckFreshIds(transformation2, context.get(),
1456                           &transformation_context);
1457     ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1458         MakeDataDescriptor(201, {0}), MakeDataDescriptor(101, {})));
1459   }
1460 
1461   {
1462     TransformationWrapVectorSynonym transformation3(102, 20, 21, 202, 0);
1463     ASSERT_TRUE(
1464         transformation3.IsApplicable(context.get(), transformation_context));
1465     ApplyAndCheckFreshIds(transformation3, context.get(),
1466                           &transformation_context);
1467     ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
1468         MakeDataDescriptor(202, {0}), MakeDataDescriptor(102, {})));
1469   }
1470 
1471   std::string after_transformation = R"(
1472                OpCapability Shader
1473           %1 = OpExtInstImport "GLSL.std.450"
1474                OpMemoryModel Logical GLSL450
1475                OpEntryPoint Fragment %4 "main"
1476                OpExecutionMode %4 OriginUpperLeft
1477                OpSource ESSL 320
1478           %2 = OpTypeVoid
1479           %3 = OpTypeFunction %2
1480           %6 = OpTypeInt 32 1
1481           %7 = OpTypeVector %6 2
1482           %8 = OpTypePointer Function %7
1483          %10 = OpConstant %6 1
1484          %11 = OpConstant %6 0
1485          %12 = OpConstantComposite %7 %10 %11
1486          %14 = OpTypeInt 32 0
1487          %15 = OpTypeVector %14 2
1488          %18 = OpConstant %14 3
1489          %19 = OpConstant %14 0
1490          %20 = OpConstantComposite %15 %18 %19
1491          %21 = OpConstantComposite %15 %19 %18
1492           %4 = OpFunction %2 None %3
1493           %5 = OpLabel
1494         %200 = OpIAdd %15 %12 %20
1495         %100 = OpIAdd %14 %10 %18
1496         %201 = OpIAdd %7 %12 %20
1497         %101 = OpIAdd %6 %10 %18
1498         %202 = OpIAdd %7 %20 %21
1499         %102 = OpIAdd %6 %18 %19
1500                OpReturn
1501                OpFunctionEnd
1502   )";
1503   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
1504 }
1505 
TEST(TransformationWrapVectorSynonym, SignednessDoesNotMatchResultType)1506 TEST(TransformationWrapVectorSynonym, SignednessDoesNotMatchResultType) {
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 320
1514           %2 = OpTypeVoid
1515           %3 = OpTypeFunction %2
1516           %6 = OpTypeInt 32 1
1517           %7 = OpTypeVector %6 2
1518           %8 = OpTypePointer Function %7
1519          %10 = OpConstant %6 1
1520          %11 = OpConstant %6 0
1521          %12 = OpConstantComposite %7 %10 %11
1522          %13 = OpConstantComposite %7 %11 %10
1523          %14 = OpTypeInt 32 0
1524           %4 = OpFunction %2 None %3
1525           %5 = OpLabel
1526         %100 = OpIAdd %14 %10 %11
1527                OpReturn
1528                OpFunctionEnd
1529   )";
1530   const auto env = SPV_ENV_UNIVERSAL_1_3;
1531   const auto consumer = nullptr;
1532   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1533   spvtools::ValidatorOptions validator_options;
1534 
1535   // Check context validity.
1536   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1537                                                kConsoleMessageConsumer));
1538 
1539   TransformationContext transformation_context(
1540       MakeUnique<FactManager>(context.get()), validator_options);
1541 
1542   transformation_context.GetFactManager()->AddFactDataSynonym(
1543       MakeDataDescriptor(10, {}), MakeDataDescriptor(12, {0}));
1544   transformation_context.GetFactManager()->AddFactDataSynonym(
1545       MakeDataDescriptor(11, {}), MakeDataDescriptor(13, {0}));
1546 
1547   ASSERT_FALSE(TransformationWrapVectorSynonym(100, 12, 13, 200, 0)
1548                    .IsApplicable(context.get(), transformation_context));
1549 }
1550 
1551 }  // namespace
1552 }  // namespace fuzz
1553 }  // namespace spvtools
1554