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