• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "source/fuzz/transformation_vector_shuffle.h"
16 #include "source/fuzz/instruction_descriptor.h"
17 #include "test/fuzz/fuzz_test_util.h"
18 
19 namespace spvtools {
20 namespace fuzz {
21 namespace {
22 
TEST(TransformationVectorShuffle,BasicTest)23 TEST(TransformationVectorShuffle, BasicTest) {
24   std::string shader = R"(
25                OpCapability Shader
26           %1 = OpExtInstImport "GLSL.std.450"
27                OpMemoryModel Logical GLSL450
28                OpEntryPoint Fragment %4 "main"
29                OpExecutionMode %4 OriginUpperLeft
30                OpSource ESSL 310
31           %2 = OpTypeVoid
32           %3 = OpTypeFunction %2
33           %6 = OpTypeBool
34           %7 = OpTypeVector %6 2
35          %10 = OpConstantTrue %6
36          %11 = OpConstantFalse %6
37          %12 = OpConstantComposite %7 %10 %11
38         %112 = OpUndef %7
39          %13 = OpTypeVector %6 3
40          %16 = OpConstantComposite %13 %10 %11 %10
41          %17 = OpTypeVector %6 4
42          %20 = OpConstantComposite %17 %10 %11 %10 %11
43          %21 = OpTypeInt 32 1
44          %22 = OpTypeVector %21 2
45          %25 = OpConstant %21 1
46          %26 = OpConstant %21 0
47          %27 = OpConstantComposite %22 %25 %26
48          %28 = OpTypeVector %21 3
49          %31 = OpConstantComposite %28 %25 %26 %25
50          %32 = OpTypeVector %21 4
51          %33 = OpTypePointer Function %32
52          %35 = OpConstantComposite %32 %25 %26 %25 %26
53          %36 = OpTypeInt 32 0
54          %37 = OpTypeVector %36 2
55          %40 = OpConstant %36 1
56          %41 = OpConstant %36 0
57          %42 = OpConstantComposite %37 %40 %41
58          %43 = OpTypeVector %36 3
59          %46 = OpConstantComposite %43 %40 %41 %40
60          %47 = OpTypeVector %36 4
61          %50 = OpConstantComposite %47 %40 %41 %40 %41
62          %51 = OpTypeFloat 32
63          %55 = OpConstant %51 1
64          %56 = OpConstant %51 0
65          %58 = OpTypeVector %51 3
66          %61 = OpConstantComposite %58 %55 %56 %55
67          %62 = OpTypeVector %51 4
68          %65 = OpConstantComposite %62 %55 %56 %55 %56
69           %4 = OpFunction %2 None %3
70           %5 = OpLabel
71                OpSelectionMerge %100 None
72                OpBranchConditional %10 %101 %102
73         %101 = OpLabel
74         %103 = OpCompositeConstruct %62 %55 %55 %55 %56
75                OpBranch %100
76         %102 = OpLabel
77                OpBranch %100
78         %100 = OpLabel
79                OpReturn
80                OpFunctionEnd
81   )";
82 
83   const auto env = SPV_ENV_UNIVERSAL_1_4;
84   const auto consumer = nullptr;
85   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
86   ASSERT_TRUE(IsValid(env, context.get()));
87 
88   FactManager fact_manager;
89   spvtools::ValidatorOptions validator_options;
90   TransformationContext transformation_context(&fact_manager,
91                                                validator_options);
92 
93   transformation_context.GetFactManager()->AddFactDataSynonym(
94       MakeDataDescriptor(10, {}), MakeDataDescriptor(12, {0}), context.get());
95   transformation_context.GetFactManager()->AddFactDataSynonym(
96       MakeDataDescriptor(11, {}), MakeDataDescriptor(12, {1}), context.get());
97 
98   transformation_context.GetFactManager()->AddFactDataSynonym(
99       MakeDataDescriptor(10, {}), MakeDataDescriptor(16, {0}), context.get());
100   transformation_context.GetFactManager()->AddFactDataSynonym(
101       MakeDataDescriptor(11, {}), MakeDataDescriptor(16, {1}), context.get());
102   transformation_context.GetFactManager()->AddFactDataSynonym(
103       MakeDataDescriptor(10, {}), MakeDataDescriptor(16, {2}), context.get());
104 
105   transformation_context.GetFactManager()->AddFactDataSynonym(
106       MakeDataDescriptor(10, {}), MakeDataDescriptor(20, {0}), context.get());
107   transformation_context.GetFactManager()->AddFactDataSynonym(
108       MakeDataDescriptor(11, {}), MakeDataDescriptor(20, {1}), context.get());
109   transformation_context.GetFactManager()->AddFactDataSynonym(
110       MakeDataDescriptor(10, {}), MakeDataDescriptor(20, {2}), context.get());
111   transformation_context.GetFactManager()->AddFactDataSynonym(
112       MakeDataDescriptor(11, {}), MakeDataDescriptor(20, {3}), context.get());
113 
114   transformation_context.GetFactManager()->AddFactDataSynonym(
115       MakeDataDescriptor(25, {}), MakeDataDescriptor(27, {0}), context.get());
116   transformation_context.GetFactManager()->AddFactDataSynonym(
117       MakeDataDescriptor(26, {}), MakeDataDescriptor(27, {1}), context.get());
118 
119   transformation_context.GetFactManager()->AddFactDataSynonym(
120       MakeDataDescriptor(25, {}), MakeDataDescriptor(31, {0}), context.get());
121   transformation_context.GetFactManager()->AddFactDataSynonym(
122       MakeDataDescriptor(26, {}), MakeDataDescriptor(31, {1}), context.get());
123   transformation_context.GetFactManager()->AddFactDataSynonym(
124       MakeDataDescriptor(25, {}), MakeDataDescriptor(31, {2}), context.get());
125 
126   transformation_context.GetFactManager()->AddFactDataSynonym(
127       MakeDataDescriptor(25, {}), MakeDataDescriptor(35, {0}), context.get());
128   transformation_context.GetFactManager()->AddFactDataSynonym(
129       MakeDataDescriptor(26, {}), MakeDataDescriptor(35, {1}), context.get());
130   transformation_context.GetFactManager()->AddFactDataSynonym(
131       MakeDataDescriptor(25, {}), MakeDataDescriptor(35, {2}), context.get());
132   transformation_context.GetFactManager()->AddFactDataSynonym(
133       MakeDataDescriptor(26, {}), MakeDataDescriptor(35, {3}), context.get());
134 
135   transformation_context.GetFactManager()->AddFactDataSynonym(
136       MakeDataDescriptor(40, {}), MakeDataDescriptor(42, {0}), context.get());
137   transformation_context.GetFactManager()->AddFactDataSynonym(
138       MakeDataDescriptor(41, {}), MakeDataDescriptor(42, {1}), context.get());
139 
140   transformation_context.GetFactManager()->AddFactDataSynonym(
141       MakeDataDescriptor(40, {}), MakeDataDescriptor(46, {0}), context.get());
142   transformation_context.GetFactManager()->AddFactDataSynonym(
143       MakeDataDescriptor(41, {}), MakeDataDescriptor(46, {1}), context.get());
144   transformation_context.GetFactManager()->AddFactDataSynonym(
145       MakeDataDescriptor(40, {}), MakeDataDescriptor(46, {2}), context.get());
146 
147   transformation_context.GetFactManager()->AddFactDataSynonym(
148       MakeDataDescriptor(40, {}), MakeDataDescriptor(50, {0}), context.get());
149   transformation_context.GetFactManager()->AddFactDataSynonym(
150       MakeDataDescriptor(41, {}), MakeDataDescriptor(50, {1}), context.get());
151   transformation_context.GetFactManager()->AddFactDataSynonym(
152       MakeDataDescriptor(40, {}), MakeDataDescriptor(50, {2}), context.get());
153   transformation_context.GetFactManager()->AddFactDataSynonym(
154       MakeDataDescriptor(41, {}), MakeDataDescriptor(50, {3}), context.get());
155 
156   transformation_context.GetFactManager()->AddFactDataSynonym(
157       MakeDataDescriptor(55, {}), MakeDataDescriptor(61, {0}), context.get());
158   transformation_context.GetFactManager()->AddFactDataSynonym(
159       MakeDataDescriptor(56, {}), MakeDataDescriptor(61, {1}), context.get());
160   transformation_context.GetFactManager()->AddFactDataSynonym(
161       MakeDataDescriptor(55, {}), MakeDataDescriptor(61, {2}), context.get());
162 
163   transformation_context.GetFactManager()->AddFactDataSynonym(
164       MakeDataDescriptor(55, {}), MakeDataDescriptor(65, {0}), context.get());
165   transformation_context.GetFactManager()->AddFactDataSynonym(
166       MakeDataDescriptor(56, {}), MakeDataDescriptor(65, {1}), context.get());
167   transformation_context.GetFactManager()->AddFactDataSynonym(
168       MakeDataDescriptor(55, {}), MakeDataDescriptor(65, {2}), context.get());
169   transformation_context.GetFactManager()->AddFactDataSynonym(
170       MakeDataDescriptor(56, {}), MakeDataDescriptor(65, {3}), context.get());
171 
172   // %103 does not dominate the return instruction.
173   ASSERT_FALSE(TransformationVectorShuffle(
174                    MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 103, 65,
175                    {3, 5, 7})
176                    .IsApplicable(context.get(), transformation_context));
177 
178   // Illegal to shuffle a bvec2 and a vec3
179   ASSERT_FALSE(TransformationVectorShuffle(
180                    MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 112, 61,
181                    {0, 2, 4})
182                    .IsApplicable(context.get(), transformation_context));
183 
184   // Illegal to shuffle an ivec2 and a uvec4
185   ASSERT_FALSE(TransformationVectorShuffle(
186                    MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 27, 50,
187                    {1, 3, 5})
188                    .IsApplicable(context.get(), transformation_context));
189 
190   // Vector 1 does not exist
191   ASSERT_FALSE(TransformationVectorShuffle(
192                    MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 300, 50,
193                    {1, 3, 5})
194                    .IsApplicable(context.get(), transformation_context));
195 
196   // Vector 2 does not exist
197   ASSERT_FALSE(TransformationVectorShuffle(
198                    MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 27, 300,
199                    {1, 3, 5})
200                    .IsApplicable(context.get(), transformation_context));
201 
202   // Index out of range
203   ASSERT_FALSE(
204       TransformationVectorShuffle(
205           MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {0, 20})
206           .IsApplicable(context.get(), transformation_context));
207 
208   // Too many indices
209   ASSERT_FALSE(TransformationVectorShuffle(
210                    MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112,
211                    {0, 1, 0, 1, 0, 1, 0, 1})
212                    .IsApplicable(context.get(), transformation_context));
213 
214   // Too few indices
215   ASSERT_FALSE(
216       TransformationVectorShuffle(
217           MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {})
218           .IsApplicable(context.get(), transformation_context));
219 
220   // Too few indices again
221   ASSERT_FALSE(
222       TransformationVectorShuffle(
223           MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {0})
224           .IsApplicable(context.get(), transformation_context));
225 
226   // Indices define unknown type: we do not have vec2
227   ASSERT_FALSE(
228       TransformationVectorShuffle(
229           MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 65, 65, {0, 1})
230           .IsApplicable(context.get(), transformation_context));
231 
232   // The instruction to insert before does not exist
233   ASSERT_FALSE(TransformationVectorShuffle(
234                    MakeInstructionDescriptor(100, SpvOpCompositeConstruct, 1),
235                    201, 20, 12, {0xFFFFFFFF, 3, 5})
236                    .IsApplicable(context.get(), transformation_context));
237 
238   // The 'fresh' id is already in use
239   ASSERT_FALSE(
240       TransformationVectorShuffle(
241           MakeInstructionDescriptor(100, SpvOpReturn, 0), 12, 12, 112, {})
242           .IsApplicable(context.get(), transformation_context));
243 
244   protobufs::DataDescriptor temp_dd;
245 
246   TransformationVectorShuffle transformation1(
247       MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {1, 0});
248   ASSERT_TRUE(
249       transformation1.IsApplicable(context.get(), transformation_context));
250   transformation1.Apply(context.get(), &transformation_context);
251   temp_dd = MakeDataDescriptor(200, {0});
252   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
253       MakeDataDescriptor(11, {}), temp_dd, context.get()));
254   temp_dd = MakeDataDescriptor(200, {1});
255   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
256       MakeDataDescriptor(10, {}), temp_dd, context.get()));
257 
258   TransformationVectorShuffle transformation2(
259       MakeInstructionDescriptor(100, SpvOpReturn, 0), 201, 20, 12,
260       {0xFFFFFFFF, 3, 5});
261   ASSERT_TRUE(
262       transformation2.IsApplicable(context.get(), transformation_context));
263   transformation2.Apply(context.get(), &transformation_context);
264   temp_dd = MakeDataDescriptor(201, {1});
265   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
266       MakeDataDescriptor(11, {}), temp_dd, context.get()));
267   temp_dd = MakeDataDescriptor(201, {2});
268   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
269       MakeDataDescriptor(11, {}), temp_dd, context.get()));
270 
271   TransformationVectorShuffle transformation3(
272       MakeInstructionDescriptor(100, SpvOpReturn, 0), 202, 27, 35, {5, 4, 1});
273   ASSERT_TRUE(
274       transformation3.IsApplicable(context.get(), transformation_context));
275   transformation3.Apply(context.get(), &transformation_context);
276   temp_dd = MakeDataDescriptor(202, {0});
277   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
278       MakeDataDescriptor(26, {}), temp_dd, context.get()));
279   temp_dd = MakeDataDescriptor(202, {1});
280   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
281       MakeDataDescriptor(25, {}), temp_dd, context.get()));
282   temp_dd = MakeDataDescriptor(202, {2});
283   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
284       MakeDataDescriptor(26, {}), temp_dd, context.get()));
285 
286   TransformationVectorShuffle transformation4(
287       MakeInstructionDescriptor(100, SpvOpReturn, 0), 203, 42, 46, {0, 1});
288   ASSERT_TRUE(
289       transformation4.IsApplicable(context.get(), transformation_context));
290   transformation4.Apply(context.get(), &transformation_context);
291   temp_dd = MakeDataDescriptor(203, {0});
292   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
293       MakeDataDescriptor(40, {}), temp_dd, context.get()));
294   temp_dd = MakeDataDescriptor(203, {1});
295   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
296       MakeDataDescriptor(41, {}), temp_dd, context.get()));
297 
298   TransformationVectorShuffle transformation5(
299       MakeInstructionDescriptor(100, SpvOpReturn, 0), 204, 42, 46, {2, 3, 4});
300   ASSERT_TRUE(
301       transformation5.IsApplicable(context.get(), transformation_context));
302   transformation5.Apply(context.get(), &transformation_context);
303   temp_dd = MakeDataDescriptor(204, {0});
304   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
305       MakeDataDescriptor(40, {}), temp_dd, context.get()));
306   temp_dd = MakeDataDescriptor(204, {1});
307   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
308       MakeDataDescriptor(41, {}), temp_dd, context.get()));
309   temp_dd = MakeDataDescriptor(204, {2});
310   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
311       MakeDataDescriptor(40, {}), temp_dd, context.get()));
312 
313   TransformationVectorShuffle transformation6(
314       MakeInstructionDescriptor(100, SpvOpReturn, 0), 205, 42, 42,
315       {0, 1, 2, 3});
316   ASSERT_TRUE(
317       transformation6.IsApplicable(context.get(), transformation_context));
318   transformation6.Apply(context.get(), &transformation_context);
319   temp_dd = MakeDataDescriptor(205, {0});
320   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
321       MakeDataDescriptor(40, {}), temp_dd, context.get()));
322   temp_dd = MakeDataDescriptor(205, {1});
323   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
324       MakeDataDescriptor(41, {}), temp_dd, context.get()));
325   temp_dd = MakeDataDescriptor(205, {2});
326   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
327       MakeDataDescriptor(40, {}), temp_dd, context.get()));
328   temp_dd = MakeDataDescriptor(205, {3});
329   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
330       MakeDataDescriptor(41, {}), temp_dd, context.get()));
331 
332   // swizzle vec4 from vec4 and vec4 using some undefs
333   TransformationVectorShuffle transformation7(
334       MakeInstructionDescriptor(100, SpvOpReturn, 0), 206, 65, 65,
335       {0xFFFFFFFF, 3, 6, 0xFFFFFFFF});
336   ASSERT_TRUE(
337       transformation7.IsApplicable(context.get(), transformation_context));
338   transformation7.Apply(context.get(), &transformation_context);
339   temp_dd = MakeDataDescriptor(206, {1});
340   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
341       MakeDataDescriptor(56, {}), temp_dd, context.get()));
342 
343   std::string after_transformation = R"(
344                OpCapability Shader
345           %1 = OpExtInstImport "GLSL.std.450"
346                OpMemoryModel Logical GLSL450
347                OpEntryPoint Fragment %4 "main"
348                OpExecutionMode %4 OriginUpperLeft
349                OpSource ESSL 310
350           %2 = OpTypeVoid
351           %3 = OpTypeFunction %2
352           %6 = OpTypeBool
353           %7 = OpTypeVector %6 2
354          %10 = OpConstantTrue %6
355          %11 = OpConstantFalse %6
356          %12 = OpConstantComposite %7 %10 %11
357         %112 = OpUndef %7
358          %13 = OpTypeVector %6 3
359          %16 = OpConstantComposite %13 %10 %11 %10
360          %17 = OpTypeVector %6 4
361          %20 = OpConstantComposite %17 %10 %11 %10 %11
362          %21 = OpTypeInt 32 1
363          %22 = OpTypeVector %21 2
364          %25 = OpConstant %21 1
365          %26 = OpConstant %21 0
366          %27 = OpConstantComposite %22 %25 %26
367          %28 = OpTypeVector %21 3
368          %31 = OpConstantComposite %28 %25 %26 %25
369          %32 = OpTypeVector %21 4
370          %33 = OpTypePointer Function %32
371          %35 = OpConstantComposite %32 %25 %26 %25 %26
372          %36 = OpTypeInt 32 0
373          %37 = OpTypeVector %36 2
374          %40 = OpConstant %36 1
375          %41 = OpConstant %36 0
376          %42 = OpConstantComposite %37 %40 %41
377          %43 = OpTypeVector %36 3
378          %46 = OpConstantComposite %43 %40 %41 %40
379          %47 = OpTypeVector %36 4
380          %50 = OpConstantComposite %47 %40 %41 %40 %41
381          %51 = OpTypeFloat 32
382          %55 = OpConstant %51 1
383          %56 = OpConstant %51 0
384          %58 = OpTypeVector %51 3
385          %61 = OpConstantComposite %58 %55 %56 %55
386          %62 = OpTypeVector %51 4
387          %65 = OpConstantComposite %62 %55 %56 %55 %56
388           %4 = OpFunction %2 None %3
389           %5 = OpLabel
390                OpSelectionMerge %100 None
391                OpBranchConditional %10 %101 %102
392         %101 = OpLabel
393         %103 = OpCompositeConstruct %62 %55 %55 %55 %56
394                OpBranch %100
395         %102 = OpLabel
396                OpBranch %100
397         %100 = OpLabel
398         %200 = OpVectorShuffle %7 %12 %112 1 0
399         %201 = OpVectorShuffle %13 %20 %12 0xFFFFFFFF 3 5
400         %202 = OpVectorShuffle %28 %27 %35 5 4 1
401         %203 = OpVectorShuffle %37 %42 %46 0 1
402         %204 = OpVectorShuffle %43 %42 %46 2 3 4
403         %205 = OpVectorShuffle %47 %42 %42 0 1 2 3
404         %206 = OpVectorShuffle %62 %65 %65 0xFFFFFFFF 3 6 0xFFFFFFFF
405                OpReturn
406                OpFunctionEnd
407   )";
408   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
409 }
410 
TEST(TransformationVectorShuffleTest,IllegalInsertionPoints)411 TEST(TransformationVectorShuffleTest, IllegalInsertionPoints) {
412   std::string shader = R"(
413                OpCapability Shader
414           %1 = OpExtInstImport "GLSL.std.450"
415                OpMemoryModel Logical GLSL450
416                OpEntryPoint Fragment %4 "main" %51 %27
417                OpExecutionMode %4 OriginUpperLeft
418                OpSource ESSL 310
419                OpName %4 "main"
420                OpName %25 "buf"
421                OpMemberName %25 0 "value"
422                OpName %27 ""
423                OpName %51 "color"
424                OpMemberDecorate %25 0 Offset 0
425                OpDecorate %25 Block
426                OpDecorate %27 DescriptorSet 0
427                OpDecorate %27 Binding 0
428                OpDecorate %51 Location 0
429           %2 = OpTypeVoid
430           %3 = OpTypeFunction %2
431           %6 = OpTypeFloat 32
432           %7 = OpTypeVector %6 4
433         %150 = OpTypeVector %6 2
434          %10 = OpConstant %6 0.300000012
435          %11 = OpConstant %6 0.400000006
436          %12 = OpConstant %6 0.5
437          %13 = OpConstant %6 1
438          %14 = OpConstantComposite %7 %10 %11 %12 %13
439          %15 = OpTypeInt 32 1
440          %18 = OpConstant %15 0
441          %25 = OpTypeStruct %6
442          %26 = OpTypePointer Uniform %25
443          %27 = OpVariable %26 Uniform
444          %28 = OpTypePointer Uniform %6
445          %32 = OpTypeBool
446         %103 = OpConstantTrue %32
447          %34 = OpConstant %6 0.100000001
448          %48 = OpConstant %15 1
449          %50 = OpTypePointer Output %7
450          %51 = OpVariable %50 Output
451         %100 = OpTypePointer Function %6
452           %4 = OpFunction %2 None %3
453           %5 = OpLabel
454         %101 = OpVariable %100 Function
455         %102 = OpVariable %100 Function
456                OpBranch %19
457          %19 = OpLabel
458          %60 = OpPhi %7 %14 %5 %58 %20
459          %59 = OpPhi %15 %18 %5 %49 %20
460          %29 = OpAccessChain %28 %27 %18
461          %30 = OpLoad %6 %29
462          %31 = OpConvertFToS %15 %30
463          %33 = OpSLessThan %32 %59 %31
464                OpLoopMerge %21 %20 None
465                OpBranchConditional %33 %20 %21
466          %20 = OpLabel
467          %39 = OpCompositeExtract %6 %60 0
468          %40 = OpFAdd %6 %39 %34
469          %55 = OpCompositeInsert %7 %40 %60 0
470          %44 = OpCompositeExtract %6 %60 1
471          %45 = OpFSub %6 %44 %34
472          %58 = OpCompositeInsert %7 %45 %55 1
473          %49 = OpIAdd %15 %59 %48
474                OpBranch %19
475          %21 = OpLabel
476                OpStore %51 %60
477                OpSelectionMerge %105 None
478                OpBranchConditional %103 %104 %105
479         %104 = OpLabel
480                OpBranch %105
481         %105 = OpLabel
482                OpReturn
483                OpFunctionEnd
484   )";
485 
486   const auto env = SPV_ENV_UNIVERSAL_1_4;
487   const auto consumer = nullptr;
488   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
489   ASSERT_TRUE(IsValid(env, context.get()));
490 
491   FactManager fact_manager;
492   spvtools::ValidatorOptions validator_options;
493   TransformationContext transformation_context(&fact_manager,
494                                                validator_options);
495 
496   // Cannot insert before the OpVariables of a function.
497   ASSERT_FALSE(
498       TransformationVectorShuffle(
499           MakeInstructionDescriptor(101, SpvOpVariable, 0), 200, 14, 14, {0, 1})
500           .IsApplicable(context.get(), transformation_context));
501   ASSERT_FALSE(
502       TransformationVectorShuffle(
503           MakeInstructionDescriptor(101, SpvOpVariable, 1), 200, 14, 14, {1, 2})
504           .IsApplicable(context.get(), transformation_context));
505   ASSERT_FALSE(
506       TransformationVectorShuffle(
507           MakeInstructionDescriptor(102, SpvOpVariable, 0), 200, 14, 14, {1, 2})
508           .IsApplicable(context.get(), transformation_context));
509   // OK to insert right after the OpVariables.
510   ASSERT_FALSE(
511       TransformationVectorShuffle(
512           MakeInstructionDescriptor(102, SpvOpBranch, 1), 200, 14, 14, {1, 1})
513           .IsApplicable(context.get(), transformation_context));
514 
515   // Cannot insert before the OpPhis of a block.
516   ASSERT_FALSE(
517       TransformationVectorShuffle(MakeInstructionDescriptor(60, SpvOpPhi, 0),
518                                   200, 14, 14, {2, 0})
519           .IsApplicable(context.get(), transformation_context));
520   ASSERT_FALSE(
521       TransformationVectorShuffle(MakeInstructionDescriptor(59, SpvOpPhi, 0),
522                                   200, 14, 14, {3, 0})
523           .IsApplicable(context.get(), transformation_context));
524   // OK to insert after the OpPhis.
525   ASSERT_TRUE(TransformationVectorShuffle(
526                   MakeInstructionDescriptor(59, SpvOpAccessChain, 0), 200, 14,
527                   14, {3, 4})
528                   .IsApplicable(context.get(), transformation_context));
529 
530   // Cannot insert before OpLoopMerge
531   ASSERT_FALSE(TransformationVectorShuffle(
532                    MakeInstructionDescriptor(33, SpvOpBranchConditional, 0),
533                    200, 14, 14, {3})
534                    .IsApplicable(context.get(), transformation_context));
535 
536   // Cannot insert before OpSelectionMerge
537   ASSERT_FALSE(TransformationVectorShuffle(
538                    MakeInstructionDescriptor(21, SpvOpBranchConditional, 0),
539                    200, 14, 14, {2})
540                    .IsApplicable(context.get(), transformation_context));
541 }
542 
543 }  // namespace
544 }  // namespace fuzz
545 }  // namespace spvtools
546