• 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_store.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(TransformationStoreTest,BasicTest)26 TEST(TransformationStoreTest, BasicTest) {
27   std::string shader = R"(
28                OpCapability Shader
29                OpCapability VariablePointers
30           %1 = OpExtInstImport "GLSL.std.450"
31                OpMemoryModel Logical GLSL450
32                OpEntryPoint Fragment %4 "main" %92 %52 %53
33                OpExecutionMode %4 OriginUpperLeft
34                OpSource ESSL 310
35                OpDecorate %92 BuiltIn FragCoord
36           %2 = OpTypeVoid
37           %3 = OpTypeFunction %2
38           %6 = OpTypeInt 32 1
39           %7 = OpTypeFloat 32
40           %8 = OpTypeStruct %6 %7
41           %9 = OpTypePointer Function %8
42          %10 = OpTypeFunction %6 %9
43          %14 = OpConstant %6 0
44          %15 = OpTypePointer Function %6
45          %51 = OpTypePointer Private %6
46          %21 = OpConstant %6 2
47          %23 = OpConstant %6 1
48          %24 = OpConstant %7 1
49          %25 = OpTypePointer Function %7
50          %50 = OpTypePointer Private %7
51          %34 = OpTypeBool
52          %35 = OpConstantFalse %34
53          %60 = OpConstantNull %50
54          %52 = OpVariable %50 Private
55          %53 = OpVariable %51 Private
56          %80 = OpConstantComposite %8 %21 %24
57          %90 = OpTypeVector %7 4
58          %91 = OpTypePointer Input %90
59          %92 = OpVariable %91 Input
60          %93 = OpConstantComposite %90 %24 %24 %24 %24
61           %4 = OpFunction %2 None %3
62           %5 = OpLabel
63          %20 = OpVariable %9 Function
64          %27 = OpVariable %9 Function ; irrelevant
65          %22 = OpAccessChain %15 %20 %14
66          %44 = OpCopyObject %9 %20
67          %26 = OpAccessChain %25 %20 %23
68          %29 = OpFunctionCall %6 %12 %27
69          %30 = OpAccessChain %15 %20 %14
70          %45 = OpCopyObject %15 %30
71          %81 = OpCopyObject %9 %27 ; irrelevant
72          %33 = OpAccessChain %15 %20 %14
73                OpSelectionMerge %37 None
74                OpBranchConditional %35 %36 %37
75          %36 = OpLabel
76          %38 = OpAccessChain %15 %20 %14
77          %40 = OpAccessChain %15 %20 %14
78          %43 = OpAccessChain %15 %20 %14
79          %82 = OpCopyObject %9 %27 ; irrelevant
80                OpBranch %37
81          %37 = OpLabel
82                OpReturn
83                OpFunctionEnd
84          %12 = OpFunction %6 None %10
85          %11 = OpFunctionParameter %9 ; irrelevant
86          %13 = OpLabel
87          %46 = OpCopyObject %9 %11 ; irrelevant
88          %16 = OpAccessChain %15 %11 %14 ; irrelevant
89          %95 = OpCopyObject %8 %80
90                OpReturnValue %21
91                OpFunctionEnd
92   )";
93 
94   const auto env = SPV_ENV_UNIVERSAL_1_4;
95   const auto consumer = nullptr;
96   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
97   spvtools::ValidatorOptions validator_options;
98   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
99                                                kConsoleMessageConsumer));
100   TransformationContext transformation_context(
101       MakeUnique<FactManager>(context.get()), validator_options);
102   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
103       27);
104   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
105       11);
106   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
107       46);
108   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
109       16);
110   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
111       52);
112   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
113       81);
114   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
115       82);
116 
117   transformation_context.GetFactManager()->AddFactBlockIsDead(36);
118 
119   // Variables with pointee types:
120   //  52 - ptr_to(7)
121   //  53 - ptr_to(6)
122   //  20 - ptr_to(8)
123   //  27 - ptr_to(8) - irrelevant
124   //  92 - ptr_to(90) - read only
125 
126   // Access chains with pointee type:
127   //  22 - ptr_to(6)
128   //  26 - ptr_to(6)
129   //  30 - ptr_to(6)
130   //  33 - ptr_to(6)
131   //  38 - ptr_to(6)
132   //  40 - ptr_to(6)
133   //  43 - ptr_to(6)
134   //  16 - ptr_to(6) - irrelevant
135 
136   // Copied object with pointee type:
137   //  44 - ptr_to(8)
138   //  45 - ptr_to(6)
139   //  46 - ptr_to(8) - irrelevant
140   //  81 - ptr_to(8) - irrelevant
141   //  82 - ptr_to(8) - irrelevant
142 
143   // Function parameters with pointee type:
144   //  11 - ptr_to(8) - irrelevant
145 
146   // Pointers that cannot be used:
147   //  60 - null
148   //  61 - undefined
149 
150   // Bad: attempt to store to 11 from outside its function
151   ASSERT_FALSE(
152       TransformationStore(11, false, 0, 0, 80,
153                           MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
154           .IsApplicable(context.get(), transformation_context));
155 
156   // Bad: pointer is not available
157   ASSERT_FALSE(
158       TransformationStore(81, false, 0, 0, 80,
159                           MakeInstructionDescriptor(45, SpvOpCopyObject, 0))
160           .IsApplicable(context.get(), transformation_context));
161 
162   // Bad: attempt to insert before OpVariable
163   ASSERT_FALSE(
164       TransformationStore(52, false, 0, 0, 24,
165                           MakeInstructionDescriptor(27, SpvOpVariable, 0))
166           .IsApplicable(context.get(), transformation_context));
167 
168   // Bad: pointer id does not exist
169   ASSERT_FALSE(
170       TransformationStore(1000, false, 0, 0, 24,
171                           MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
172           .IsApplicable(context.get(), transformation_context));
173 
174   // Bad: pointer id exists but does not have a type
175   ASSERT_FALSE(
176       TransformationStore(5, false, 0, 0, 24,
177                           MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
178           .IsApplicable(context.get(), transformation_context));
179 
180   // Bad: pointer id exists and has a type, but is not a pointer
181   ASSERT_FALSE(
182       TransformationStore(24, false, 0, 0, 24,
183                           MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
184           .IsApplicable(context.get(), transformation_context));
185 
186   // Bad: attempt to store to a null pointer
187   ASSERT_FALSE(
188       TransformationStore(60, false, 0, 0, 24,
189                           MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
190           .IsApplicable(context.get(), transformation_context));
191 
192   // Bad: attempt to store to an undefined pointer
193   ASSERT_FALSE(
194       TransformationStore(61, false, 0, 0, 21,
195                           MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
196           .IsApplicable(context.get(), transformation_context));
197 
198   // Bad: %82 is not available at the program point
199   ASSERT_FALSE(
200       TransformationStore(82, false, 0, 0, 80,
201                           MakeInstructionDescriptor(37, SpvOpReturn, 0))
202           .IsApplicable(context.get(), transformation_context));
203 
204   // Bad: value id does not exist
205   ASSERT_FALSE(
206       TransformationStore(27, false, 0, 0, 1000,
207                           MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
208           .IsApplicable(context.get(), transformation_context));
209 
210   // Bad: value id exists but does not have a type
211   ASSERT_FALSE(
212       TransformationStore(27, false, 0, 0, 15,
213                           MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
214           .IsApplicable(context.get(), transformation_context));
215 
216   // Bad: value id exists but has the wrong type
217   ASSERT_FALSE(
218       TransformationStore(27, false, 0, 0, 14,
219                           MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
220           .IsApplicable(context.get(), transformation_context));
221 
222   // Bad: attempt to store to read-only variable
223   ASSERT_FALSE(
224       TransformationStore(92, false, 0, 0, 93,
225                           MakeInstructionDescriptor(40, SpvOpAccessChain, 0))
226           .IsApplicable(context.get(), transformation_context));
227 
228   // Bad: value is not available
229   ASSERT_FALSE(
230       TransformationStore(27, false, 0, 0, 95,
231                           MakeInstructionDescriptor(40, SpvOpAccessChain, 0))
232           .IsApplicable(context.get(), transformation_context));
233 
234   // Bad: variable being stored to does not have an irrelevant pointee value,
235   // and the store is not in a dead block.
236   ASSERT_FALSE(
237       TransformationStore(20, false, 0, 0, 95,
238                           MakeInstructionDescriptor(45, SpvOpCopyObject, 0))
239           .IsApplicable(context.get(), transformation_context));
240 
241   // The described instruction does not exist.
242   ASSERT_FALSE(
243       TransformationStore(27, false, 0, 0, 80,
244                           MakeInstructionDescriptor(1000, SpvOpAccessChain, 0))
245           .IsApplicable(context.get(), transformation_context));
246 
247   {
248     // Store to irrelevant variable from dead block.
249     TransformationStore transformation(
250         27, false, 0, 0, 80,
251         MakeInstructionDescriptor(38, SpvOpAccessChain, 0));
252     ASSERT_TRUE(
253         transformation.IsApplicable(context.get(), transformation_context));
254     ApplyAndCheckFreshIds(transformation, context.get(),
255                           &transformation_context);
256     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
257         context.get(), validator_options, kConsoleMessageConsumer));
258   }
259 
260   {
261     // Store to irrelevant variable from live block.
262     TransformationStore transformation(
263         11, false, 0, 0, 95,
264         MakeInstructionDescriptor(95, SpvOpReturnValue, 0));
265     ASSERT_TRUE(
266         transformation.IsApplicable(context.get(), transformation_context));
267     ApplyAndCheckFreshIds(transformation, context.get(),
268                           &transformation_context);
269     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
270         context.get(), validator_options, kConsoleMessageConsumer));
271   }
272 
273   {
274     // Store to irrelevant variable from live block.
275     TransformationStore transformation(
276         46, false, 0, 0, 80,
277         MakeInstructionDescriptor(95, SpvOpReturnValue, 0));
278     ASSERT_TRUE(
279         transformation.IsApplicable(context.get(), transformation_context));
280     ApplyAndCheckFreshIds(transformation, context.get(),
281                           &transformation_context);
282     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
283         context.get(), validator_options, kConsoleMessageConsumer));
284   }
285 
286   {
287     // Store to irrelevant variable from live block.
288     TransformationStore transformation(
289         16, false, 0, 0, 21,
290         MakeInstructionDescriptor(95, SpvOpReturnValue, 0));
291     ASSERT_TRUE(
292         transformation.IsApplicable(context.get(), transformation_context));
293     ApplyAndCheckFreshIds(transformation, context.get(),
294                           &transformation_context);
295     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
296         context.get(), validator_options, kConsoleMessageConsumer));
297   }
298 
299   {
300     // Store to non-irrelevant variable from dead block.
301     TransformationStore transformation(
302         53, false, 0, 0, 21,
303         MakeInstructionDescriptor(38, SpvOpAccessChain, 0));
304     ASSERT_TRUE(
305         transformation.IsApplicable(context.get(), transformation_context));
306     ApplyAndCheckFreshIds(transformation, context.get(),
307                           &transformation_context);
308     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
309         context.get(), validator_options, kConsoleMessageConsumer));
310   }
311 
312   std::string after_transformation = R"(
313                OpCapability Shader
314                OpCapability VariablePointers
315           %1 = OpExtInstImport "GLSL.std.450"
316                OpMemoryModel Logical GLSL450
317                OpEntryPoint Fragment %4 "main" %92 %52 %53
318                OpExecutionMode %4 OriginUpperLeft
319                OpSource ESSL 310
320                OpDecorate %92 BuiltIn FragCoord
321           %2 = OpTypeVoid
322           %3 = OpTypeFunction %2
323           %6 = OpTypeInt 32 1
324           %7 = OpTypeFloat 32
325           %8 = OpTypeStruct %6 %7
326           %9 = OpTypePointer Function %8
327          %10 = OpTypeFunction %6 %9
328          %14 = OpConstant %6 0
329          %15 = OpTypePointer Function %6
330          %51 = OpTypePointer Private %6
331          %21 = OpConstant %6 2
332          %23 = OpConstant %6 1
333          %24 = OpConstant %7 1
334          %25 = OpTypePointer Function %7
335          %50 = OpTypePointer Private %7
336          %34 = OpTypeBool
337          %35 = OpConstantFalse %34
338          %60 = OpConstantNull %50
339          %52 = OpVariable %50 Private
340          %53 = OpVariable %51 Private
341          %80 = OpConstantComposite %8 %21 %24
342          %90 = OpTypeVector %7 4
343          %91 = OpTypePointer Input %90
344          %92 = OpVariable %91 Input
345          %93 = OpConstantComposite %90 %24 %24 %24 %24
346           %4 = OpFunction %2 None %3
347           %5 = OpLabel
348          %20 = OpVariable %9 Function
349          %27 = OpVariable %9 Function ; irrelevant
350          %22 = OpAccessChain %15 %20 %14
351          %44 = OpCopyObject %9 %20
352          %26 = OpAccessChain %25 %20 %23
353          %29 = OpFunctionCall %6 %12 %27
354          %30 = OpAccessChain %15 %20 %14
355          %45 = OpCopyObject %15 %30
356          %81 = OpCopyObject %9 %27 ; irrelevant
357          %33 = OpAccessChain %15 %20 %14
358                OpSelectionMerge %37 None
359                OpBranchConditional %35 %36 %37
360          %36 = OpLabel
361                OpStore %27 %80
362                OpStore %53 %21
363          %38 = OpAccessChain %15 %20 %14
364          %40 = OpAccessChain %15 %20 %14
365          %43 = OpAccessChain %15 %20 %14
366          %82 = OpCopyObject %9 %27 ; irrelevant
367                OpBranch %37
368          %37 = OpLabel
369                OpReturn
370                OpFunctionEnd
371          %12 = OpFunction %6 None %10
372          %11 = OpFunctionParameter %9 ; irrelevant
373          %13 = OpLabel
374          %46 = OpCopyObject %9 %11 ; irrelevant
375          %16 = OpAccessChain %15 %11 %14 ; irrelevant
376          %95 = OpCopyObject %8 %80
377                OpStore %11 %95
378                OpStore %46 %80
379                OpStore %16 %21
380                OpReturnValue %21
381                OpFunctionEnd
382   )";
383   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
384 }
385 
TEST(TransformationStoreTest,DoNotAllowStoresToReadOnlyMemory)386 TEST(TransformationStoreTest, DoNotAllowStoresToReadOnlyMemory) {
387   std::string shader = R"(
388                OpCapability Shader
389           %1 = OpExtInstImport "GLSL.std.450"
390                OpMemoryModel Logical GLSL450
391                OpEntryPoint Fragment %4 "main"
392                OpExecutionMode %4 OriginUpperLeft
393                OpSource ESSL 320
394                OpMemberDecorate %10 0 Offset 0
395                OpMemberDecorate %10 1 Offset 4
396                OpDecorate %10 Block
397                OpMemberDecorate %23 0 Offset 0
398                OpDecorate %23 Block
399                OpDecorate %25 DescriptorSet 0
400                OpDecorate %25 Binding 0
401           %2 = OpTypeVoid
402           %3 = OpTypeFunction %2
403           %6 = OpTypeInt 32 1
404           %7 = OpTypePointer Function %6
405           %9 = OpTypeFloat 32
406          %10 = OpTypeStruct %6 %9
407          %11 = OpTypePointer PushConstant %10
408          %12 = OpVariable %11 PushConstant
409          %13 = OpConstant %6 0
410          %14 = OpTypePointer PushConstant %6
411          %17 = OpConstant %6 1
412          %18 = OpTypePointer PushConstant %9
413          %23 = OpTypeStruct %9
414          %24 = OpTypePointer UniformConstant %23
415          %25 = OpVariable %24 UniformConstant
416          %26 = OpTypePointer UniformConstant %9
417          %50 = OpConstant %9 0
418           %4 = OpFunction %2 None %3
419           %5 = OpLabel
420          %15 = OpAccessChain %14 %12 %13
421          %19 = OpAccessChain %18 %12 %17
422          %27 = OpAccessChain %26 %25 %13
423                OpReturn
424                OpFunctionEnd
425   )";
426 
427   const auto env = SPV_ENV_UNIVERSAL_1_3;
428   const auto consumer = nullptr;
429   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
430   spvtools::ValidatorOptions validator_options;
431   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
432                                                kConsoleMessageConsumer));
433   TransformationContext transformation_context(
434       MakeUnique<FactManager>(context.get()), validator_options);
435   transformation_context.GetFactManager()->AddFactBlockIsDead(5);
436 
437   ASSERT_FALSE(
438       TransformationStore(15, false, 0, 0, 13,
439                           MakeInstructionDescriptor(27, SpvOpReturn, 0))
440           .IsApplicable(context.get(), transformation_context));
441   ASSERT_FALSE(
442       TransformationStore(19, false, 0, 0, 50,
443                           MakeInstructionDescriptor(27, SpvOpReturn, 0))
444           .IsApplicable(context.get(), transformation_context));
445   ASSERT_FALSE(
446       TransformationStore(27, false, 0, 0, 50,
447                           MakeInstructionDescriptor(27, SpvOpReturn, 0))
448           .IsApplicable(context.get(), transformation_context));
449 }
450 
TEST(TransformationStoreTest,SupportAtomicStore)451 TEST(TransformationStoreTest, SupportAtomicStore) {
452   const std::string shader = R"(
453                OpCapability Shader
454                OpCapability Int8
455           %1 = OpExtInstImport "GLSL.std.450"
456                OpMemoryModel Logical GLSL450
457                OpEntryPoint Fragment %4 "main"
458                OpExecutionMode %4 OriginUpperLeft
459                OpSource ESSL 320
460           %2 = OpTypeVoid
461           %3 = OpTypeFunction %2
462           %6 = OpTypeInt 32 1
463           %7 = OpTypeInt 8 1
464           %9 = OpTypeInt 32 0
465          %26 = OpTypeFloat 32
466           %8 = OpTypeStruct %6
467          %10 = OpTypePointer StorageBuffer %8
468          %11 = OpVariable %10 StorageBuffer
469          %19 = OpConstant %26 0
470          %18 = OpConstant %9 1
471          %12 = OpConstant %6 0
472          %13 = OpTypePointer StorageBuffer %6
473          %15 = OpConstant %6 4
474          %16 = OpConstant %6 7
475          %17 = OpConstant %7 4
476          %20 = OpConstant %9 64
477          %21 = OpConstant %6 15
478           %4 = OpFunction %2 None %3
479           %5 = OpLabel
480          %14 = OpAccessChain %13 %11 %12
481          %24 = OpAccessChain %13 %11 %12
482                OpReturn
483                OpFunctionEnd
484   )";
485   const auto env = SPV_ENV_UNIVERSAL_1_3;
486   const auto consumer = nullptr;
487   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
488   spvtools::ValidatorOptions validator_options;
489   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
490                                                kConsoleMessageConsumer));
491   TransformationContext transformation_context(
492       MakeUnique<FactManager>(context.get()), validator_options);
493 
494   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
495       14);
496 
497   // Bad: id 100 of memory scope instruction does not exist.
498   ASSERT_FALSE(
499       TransformationStore(14, true, 100, 20, 21,
500                           MakeInstructionDescriptor(24, SpvOpAccessChain, 0))
501           .IsApplicable(context.get(), transformation_context));
502   // Bad: id 100 of memory semantics instruction does not exist.
503   ASSERT_FALSE(
504       TransformationStore(14, true, 15, 100, 21,
505                           MakeInstructionDescriptor(24, SpvOpAccessChain, 0))
506           .IsApplicable(context.get(), transformation_context));
507   // Bad: memory scope should be |OpConstant| opcode.
508   ASSERT_FALSE(
509       TransformationStore(14, true, 5, 20, 21,
510                           MakeInstructionDescriptor(24, SpvOpAccessChain, 0))
511           .IsApplicable(context.get(), transformation_context));
512   // Bad: memory semantics should be |OpConstant| opcode.
513   ASSERT_FALSE(
514       TransformationStore(14, true, 15, 5, 21,
515                           MakeInstructionDescriptor(24, SpvOpAccessChain, 0))
516           .IsApplicable(context.get(), transformation_context));
517 
518   // Bad: The memory scope instruction must have an Integer operand.
519   ASSERT_FALSE(
520       TransformationStore(14, true, 15, 19, 21,
521                           MakeInstructionDescriptor(24, SpvOpAccessChain, 0))
522           .IsApplicable(context.get(), transformation_context));
523   // Bad: The memory memory semantics instruction must have an Integer operand.
524   ASSERT_FALSE(
525       TransformationStore(14, true, 19, 20, 21,
526                           MakeInstructionDescriptor(24, SpvOpAccessChain, 0))
527           .IsApplicable(context.get(), transformation_context));
528 
529   // Bad: Integer size of the memory scope must be equal to 32 bits.
530   ASSERT_FALSE(
531       TransformationStore(14, true, 17, 20, 21,
532                           MakeInstructionDescriptor(24, SpvOpAccessChain, 0))
533           .IsApplicable(context.get(), transformation_context));
534 
535   // Bad: Integer size of memory semantics must be equal to 32 bits.
536   ASSERT_FALSE(
537       TransformationStore(14, true, 15, 17, 21,
538                           MakeInstructionDescriptor(24, SpvOpAccessChain, 0))
539           .IsApplicable(context.get(), transformation_context));
540 
541   // Bad: memory scope value must be 4 (SpvScopeInvocation).
542   ASSERT_FALSE(
543       TransformationStore(14, true, 16, 20, 21,
544                           MakeInstructionDescriptor(24, SpvOpAccessChain, 0))
545           .IsApplicable(context.get(), transformation_context));
546 
547   // Bad: memory semantics value must be either:
548   // 64 (SpvMemorySemanticsUniformMemoryMask)
549   // 256 (SpvMemorySemanticsWorkgroupMemoryMask)
550   ASSERT_FALSE(
551       TransformationStore(14, true, 15, 16, 21,
552                           MakeInstructionDescriptor(24, SpvOpAccessChain, 0))
553           .IsApplicable(context.get(), transformation_context));
554   // Bad: The described instruction does not exist
555   ASSERT_FALSE(
556       TransformationStore(14, true, 15, 20, 21,
557                           MakeInstructionDescriptor(150, SpvOpAccessChain, 0))
558           .IsApplicable(context.get(), transformation_context));
559 
560   // Bad: Can't insert OpAccessChain before the id 15 of memory scope.
561   ASSERT_FALSE(
562       TransformationStore(14, true, 15, 20, 21,
563                           MakeInstructionDescriptor(15, SpvOpAccessChain, 0))
564           .IsApplicable(context.get(), transformation_context));
565 
566   // Bad: Can't insert OpAccessChain before the id 20 of memory semantics.
567   ASSERT_FALSE(
568       TransformationStore(14, true, 15, 20, 21,
569                           MakeInstructionDescriptor(20, SpvOpAccessChain, 0))
570           .IsApplicable(context.get(), transformation_context));
571 
572   // Successful transformations.
573   {
574     TransformationStore transformation(
575         14, true, 15, 20, 21, MakeInstructionDescriptor(24, SpvOpReturn, 0));
576     ASSERT_TRUE(
577         transformation.IsApplicable(context.get(), transformation_context));
578     ApplyAndCheckFreshIds(transformation, context.get(),
579                           &transformation_context);
580     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
581         context.get(), validator_options, kConsoleMessageConsumer));
582   }
583 
584   const std::string after_transformation = R"(
585                OpCapability Shader
586                OpCapability Int8
587           %1 = OpExtInstImport "GLSL.std.450"
588                OpMemoryModel Logical GLSL450
589                OpEntryPoint Fragment %4 "main"
590                OpExecutionMode %4 OriginUpperLeft
591                OpSource ESSL 320
592           %2 = OpTypeVoid
593           %3 = OpTypeFunction %2
594           %6 = OpTypeInt 32 1
595           %7 = OpTypeInt 8 1
596           %9 = OpTypeInt 32 0
597          %26 = OpTypeFloat 32
598           %8 = OpTypeStruct %6
599          %10 = OpTypePointer StorageBuffer %8
600          %11 = OpVariable %10 StorageBuffer
601          %19 = OpConstant %26 0
602          %18 = OpConstant %9 1
603          %12 = OpConstant %6 0
604          %13 = OpTypePointer StorageBuffer %6
605          %15 = OpConstant %6 4
606          %16 = OpConstant %6 7
607          %17 = OpConstant %7 4
608          %20 = OpConstant %9 64
609          %21 = OpConstant %6 15
610           %4 = OpFunction %2 None %3
611           %5 = OpLabel
612          %14 = OpAccessChain %13 %11 %12
613          %24 = OpAccessChain %13 %11 %12
614                OpAtomicStore %14 %15 %20 %21
615                OpReturn
616                OpFunctionEnd
617   )";
618 
619   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
620 }
621 
622 }  // namespace
623 }  // namespace fuzz
624 }  // namespace spvtools
625