1 // Copyright (c) 2020 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_access_chain.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(TransformationAccessChainTest,BasicTest)26 TEST(TransformationAccessChainTest, BasicTest) {
27 std::string shader = R"(
28 OpCapability Shader
29 %1 = OpExtInstImport "GLSL.std.450"
30 OpMemoryModel Logical GLSL450
31 OpEntryPoint Fragment %4 "main" %48 %54
32 OpExecutionMode %4 OriginUpperLeft
33 OpSource ESSL 310
34 %2 = OpTypeVoid
35 %3 = OpTypeFunction %2
36 %6 = OpTypeFloat 32
37 %7 = OpTypeVector %6 2
38 %50 = OpTypeMatrix %7 2
39 %70 = OpTypePointer Function %7
40 %71 = OpTypePointer Function %50
41 %8 = OpTypeStruct %7 %6
42 %9 = OpTypePointer Function %8
43 %10 = OpTypeInt 32 1
44 %11 = OpTypePointer Function %10
45 %12 = OpTypeFunction %10 %9 %11
46 %17 = OpConstant %10 0
47 %18 = OpTypeInt 32 0
48 %19 = OpConstant %18 0
49 %20 = OpTypePointer Function %6
50 %99 = OpTypePointer Private %6
51 %29 = OpConstant %6 0
52 %30 = OpConstant %6 1
53 %31 = OpConstantComposite %7 %29 %30
54 %32 = OpConstant %6 2
55 %33 = OpConstantComposite %8 %31 %32
56 %35 = OpConstant %10 10
57 %51 = OpConstant %18 10
58 %80 = OpConstant %18 0
59 %81 = OpConstant %10 1
60 %82 = OpConstant %18 2
61 %83 = OpConstant %10 3
62 %84 = OpConstant %18 4
63 %85 = OpConstant %10 5
64 %52 = OpTypeArray %50 %51
65 %53 = OpTypePointer Private %52
66 %45 = OpUndef %9
67 %46 = OpConstantNull %9
68 %47 = OpTypePointer Private %8
69 %48 = OpVariable %47 Private
70 %54 = OpVariable %53 Private
71 %4 = OpFunction %2 None %3
72 %5 = OpLabel
73 %28 = OpVariable %9 Function
74 %34 = OpVariable %11 Function
75 %36 = OpVariable %9 Function
76 %38 = OpVariable %11 Function
77 %44 = OpCopyObject %9 %36
78 OpStore %28 %33
79 OpStore %34 %35
80 %37 = OpLoad %8 %28
81 OpStore %36 %37
82 %39 = OpLoad %10 %34
83 OpStore %38 %39
84 %40 = OpFunctionCall %10 %15 %36 %38
85 %41 = OpLoad %10 %34
86 %42 = OpIAdd %10 %41 %40
87 OpStore %34 %42
88 OpReturn
89 OpFunctionEnd
90 %15 = OpFunction %10 None %12
91 %13 = OpFunctionParameter %9
92 %14 = OpFunctionParameter %11
93 %16 = OpLabel
94 %21 = OpAccessChain %20 %13 %17 %19
95 %43 = OpCopyObject %9 %13
96 %22 = OpLoad %6 %21
97 %23 = OpConvertFToS %10 %22
98 %24 = OpLoad %10 %14
99 %25 = OpIAdd %10 %23 %24
100 OpReturnValue %25
101 OpFunctionEnd
102 )";
103
104 const auto env = SPV_ENV_UNIVERSAL_1_4;
105 const auto consumer = nullptr;
106 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
107 spvtools::ValidatorOptions validator_options;
108 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
109 kConsoleMessageConsumer));
110
111 // Types:
112 // Ptr | Pointee | Storage class | GLSL for pointee | Ids of this type
113 // ----+---------+---------------+---------------------+------------------
114 // 9 | 8 | Function | struct(vec2, float) | 28, 36, 44, 13, 43
115 // 11 | 10 | Function | int | 34, 38, 14
116 // 20 | 6 | Function | float | -
117 // 99 | 6 | Private | float | -
118 // 53 | 52 | Private | mat2x2[10] | 54
119 // 47 | 8 | Private | struct(vec2, float) | 48
120 // 70 | 7 | Function | vec2 | -
121 // 71 | 59 | Function | mat2x2 | -
122
123 // Indices 0-5 are in ids 80-85
124
125 TransformationContext transformation_context(
126 MakeUnique<FactManager>(context.get()), validator_options);
127 transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
128 54);
129
130 // Bad: id is not fresh
131 ASSERT_FALSE(TransformationAccessChain(
132 43, 43, {80}, MakeInstructionDescriptor(24, SpvOpLoad, 0))
133 .IsApplicable(context.get(), transformation_context));
134
135 // Bad: pointer id does not exist
136 ASSERT_FALSE(TransformationAccessChain(
137 100, 1000, {80}, MakeInstructionDescriptor(24, SpvOpLoad, 0))
138 .IsApplicable(context.get(), transformation_context));
139
140 // Bad: pointer id is not a type
141 ASSERT_FALSE(TransformationAccessChain(
142 100, 5, {80}, MakeInstructionDescriptor(24, SpvOpLoad, 0))
143 .IsApplicable(context.get(), transformation_context));
144
145 // Bad: pointer id is not a pointer
146 ASSERT_FALSE(TransformationAccessChain(
147 100, 23, {80}, MakeInstructionDescriptor(24, SpvOpLoad, 0))
148 .IsApplicable(context.get(), transformation_context));
149
150 // Bad: index id does not exist
151 ASSERT_FALSE(TransformationAccessChain(
152 100, 43, {1000}, MakeInstructionDescriptor(24, SpvOpLoad, 0))
153 .IsApplicable(context.get(), transformation_context));
154
155 // Bad: index id is not a constant and the pointer refers to a struct
156 ASSERT_FALSE(TransformationAccessChain(
157 100, 43, {24}, MakeInstructionDescriptor(25, SpvOpIAdd, 0))
158 .IsApplicable(context.get(), transformation_context));
159
160 // Bad: too many indices
161 ASSERT_FALSE(
162 TransformationAccessChain(100, 43, {80, 80, 80},
163 MakeInstructionDescriptor(24, SpvOpLoad, 0))
164 .IsApplicable(context.get(), transformation_context));
165
166 // Bad: index id is out of bounds when accessing a struct
167 ASSERT_FALSE(
168 TransformationAccessChain(100, 43, {83, 80},
169 MakeInstructionDescriptor(24, SpvOpLoad, 0))
170 .IsApplicable(context.get(), transformation_context));
171
172 // Bad: attempt to insert before variable
173 ASSERT_FALSE(TransformationAccessChain(
174 100, 34, {}, MakeInstructionDescriptor(36, SpvOpVariable, 0))
175 .IsApplicable(context.get(), transformation_context));
176
177 // Bad: OpTypeBool must be present in the module to clamp an index
178 ASSERT_FALSE(
179 TransformationAccessChain(100, 36, {80, 81},
180 MakeInstructionDescriptor(37, SpvOpStore, 0))
181 .IsApplicable(context.get(), transformation_context));
182
183 // Bad: pointer not available
184 ASSERT_FALSE(
185 TransformationAccessChain(
186 100, 43, {80}, MakeInstructionDescriptor(21, SpvOpAccessChain, 0))
187 .IsApplicable(context.get(), transformation_context));
188
189 // Bad: instruction descriptor does not identify anything
190 ASSERT_FALSE(TransformationAccessChain(
191 100, 43, {80}, MakeInstructionDescriptor(24, SpvOpLoad, 100))
192 .IsApplicable(context.get(), transformation_context));
193
194 #ifndef NDEBUG
195 // Bad: pointer is null
196 ASSERT_DEATH(
197 TransformationAccessChain(100, 45, {80},
198 MakeInstructionDescriptor(24, SpvOpLoad, 0))
199 .IsApplicable(context.get(), transformation_context),
200 "Access chains should not be created from null/undefined pointers");
201 #endif
202
203 #ifndef NDEBUG
204 // Bad: pointer is undef
205 ASSERT_DEATH(
206 TransformationAccessChain(100, 46, {80},
207 MakeInstructionDescriptor(24, SpvOpLoad, 0))
208 .IsApplicable(context.get(), transformation_context),
209 "Access chains should not be created from null/undefined pointers");
210 #endif
211
212 // Bad: pointer to result type does not exist
213 ASSERT_FALSE(TransformationAccessChain(
214 100, 52, {0}, MakeInstructionDescriptor(24, SpvOpLoad, 0))
215 .IsApplicable(context.get(), transformation_context));
216
217 {
218 TransformationAccessChain transformation(
219 100, 43, {80}, MakeInstructionDescriptor(24, SpvOpLoad, 0));
220 ASSERT_TRUE(
221 transformation.IsApplicable(context.get(), transformation_context));
222 ApplyAndCheckFreshIds(transformation, context.get(),
223 &transformation_context);
224 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
225 context.get(), validator_options, kConsoleMessageConsumer));
226 ASSERT_FALSE(
227 transformation_context.GetFactManager()->PointeeValueIsIrrelevant(100));
228 }
229
230 {
231 TransformationAccessChain transformation(
232 101, 28, {81}, MakeInstructionDescriptor(42, SpvOpReturn, 0));
233 ASSERT_TRUE(
234 transformation.IsApplicable(context.get(), transformation_context));
235 ApplyAndCheckFreshIds(transformation, context.get(),
236 &transformation_context);
237 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
238 context.get(), validator_options, kConsoleMessageConsumer));
239 ASSERT_FALSE(
240 transformation_context.GetFactManager()->PointeeValueIsIrrelevant(101));
241 }
242
243 {
244 TransformationAccessChain transformation(
245 102, 44, {}, MakeInstructionDescriptor(44, SpvOpStore, 0));
246 ASSERT_TRUE(
247 transformation.IsApplicable(context.get(), transformation_context));
248 ApplyAndCheckFreshIds(transformation, context.get(),
249 &transformation_context);
250 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
251 context.get(), validator_options, kConsoleMessageConsumer));
252 ASSERT_FALSE(
253 transformation_context.GetFactManager()->PointeeValueIsIrrelevant(103));
254 }
255
256 {
257 TransformationAccessChain transformation(
258 103, 13, {80}, MakeInstructionDescriptor(21, SpvOpAccessChain, 0));
259 ASSERT_TRUE(
260 transformation.IsApplicable(context.get(), transformation_context));
261 ApplyAndCheckFreshIds(transformation, context.get(),
262 &transformation_context);
263 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
264 context.get(), validator_options, kConsoleMessageConsumer));
265 ASSERT_FALSE(
266 transformation_context.GetFactManager()->PointeeValueIsIrrelevant(104));
267 }
268
269 {
270 TransformationAccessChain transformation(
271 104, 34, {}, MakeInstructionDescriptor(44, SpvOpStore, 1));
272 ASSERT_TRUE(
273 transformation.IsApplicable(context.get(), transformation_context));
274 ApplyAndCheckFreshIds(transformation, context.get(),
275 &transformation_context);
276 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
277 context.get(), validator_options, kConsoleMessageConsumer));
278 ASSERT_FALSE(
279 transformation_context.GetFactManager()->PointeeValueIsIrrelevant(105));
280 }
281
282 {
283 TransformationAccessChain transformation(
284 105, 38, {}, MakeInstructionDescriptor(40, SpvOpFunctionCall, 0));
285 ASSERT_TRUE(
286 transformation.IsApplicable(context.get(), transformation_context));
287 ApplyAndCheckFreshIds(transformation, context.get(),
288 &transformation_context);
289 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
290 context.get(), validator_options, kConsoleMessageConsumer));
291 ASSERT_FALSE(
292 transformation_context.GetFactManager()->PointeeValueIsIrrelevant(106));
293 }
294
295 {
296 TransformationAccessChain transformation(
297 106, 14, {}, MakeInstructionDescriptor(24, SpvOpLoad, 0));
298 ASSERT_TRUE(
299 transformation.IsApplicable(context.get(), transformation_context));
300 ApplyAndCheckFreshIds(transformation, context.get(),
301 &transformation_context);
302 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
303 context.get(), validator_options, kConsoleMessageConsumer));
304 ASSERT_FALSE(
305 transformation_context.GetFactManager()->PointeeValueIsIrrelevant(107));
306 }
307
308 std::string after_transformation = R"(
309 OpCapability Shader
310 %1 = OpExtInstImport "GLSL.std.450"
311 OpMemoryModel Logical GLSL450
312 OpEntryPoint Fragment %4 "main" %48 %54
313 OpExecutionMode %4 OriginUpperLeft
314 OpSource ESSL 310
315 %2 = OpTypeVoid
316 %3 = OpTypeFunction %2
317 %6 = OpTypeFloat 32
318 %7 = OpTypeVector %6 2
319 %50 = OpTypeMatrix %7 2
320 %70 = OpTypePointer Function %7
321 %71 = OpTypePointer Function %50
322 %8 = OpTypeStruct %7 %6
323 %9 = OpTypePointer Function %8
324 %10 = OpTypeInt 32 1
325 %11 = OpTypePointer Function %10
326 %12 = OpTypeFunction %10 %9 %11
327 %17 = OpConstant %10 0
328 %18 = OpTypeInt 32 0
329 %19 = OpConstant %18 0
330 %20 = OpTypePointer Function %6
331 %99 = OpTypePointer Private %6
332 %29 = OpConstant %6 0
333 %30 = OpConstant %6 1
334 %31 = OpConstantComposite %7 %29 %30
335 %32 = OpConstant %6 2
336 %33 = OpConstantComposite %8 %31 %32
337 %35 = OpConstant %10 10
338 %51 = OpConstant %18 10
339 %80 = OpConstant %18 0
340 %81 = OpConstant %10 1
341 %82 = OpConstant %18 2
342 %83 = OpConstant %10 3
343 %84 = OpConstant %18 4
344 %85 = OpConstant %10 5
345 %52 = OpTypeArray %50 %51
346 %53 = OpTypePointer Private %52
347 %45 = OpUndef %9
348 %46 = OpConstantNull %9
349 %47 = OpTypePointer Private %8
350 %48 = OpVariable %47 Private
351 %54 = OpVariable %53 Private
352 %4 = OpFunction %2 None %3
353 %5 = OpLabel
354 %28 = OpVariable %9 Function
355 %34 = OpVariable %11 Function
356 %36 = OpVariable %9 Function
357 %38 = OpVariable %11 Function
358 %44 = OpCopyObject %9 %36
359 %102 = OpAccessChain %9 %44
360 OpStore %28 %33
361 %104 = OpAccessChain %11 %34
362 OpStore %34 %35
363 %37 = OpLoad %8 %28
364 OpStore %36 %37
365 %39 = OpLoad %10 %34
366 OpStore %38 %39
367 %105 = OpAccessChain %11 %38
368 %40 = OpFunctionCall %10 %15 %36 %38
369 %41 = OpLoad %10 %34
370 %42 = OpIAdd %10 %41 %40
371 OpStore %34 %42
372 %101 = OpAccessChain %20 %28 %81
373 OpReturn
374 OpFunctionEnd
375 %15 = OpFunction %10 None %12
376 %13 = OpFunctionParameter %9
377 %14 = OpFunctionParameter %11
378 %16 = OpLabel
379 %103 = OpAccessChain %70 %13 %80
380 %21 = OpAccessChain %20 %13 %17 %19
381 %43 = OpCopyObject %9 %13
382 %22 = OpLoad %6 %21
383 %23 = OpConvertFToS %10 %22
384 %100 = OpAccessChain %70 %43 %80
385 %106 = OpAccessChain %11 %14
386 %24 = OpLoad %10 %14
387 %25 = OpIAdd %10 %23 %24
388 OpReturnValue %25
389 OpFunctionEnd
390 )";
391 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
392 }
393
TEST(TransformationAccessChainTest,IsomorphicStructs)394 TEST(TransformationAccessChainTest, IsomorphicStructs) {
395 std::string shader = R"(
396 OpCapability Shader
397 %1 = OpExtInstImport "GLSL.std.450"
398 OpMemoryModel Logical GLSL450
399 OpEntryPoint Fragment %4 "main" %11 %12
400 OpExecutionMode %4 OriginUpperLeft
401 OpSource ESSL 310
402 %2 = OpTypeVoid
403 %3 = OpTypeFunction %2
404 %6 = OpTypeFloat 32
405 %7 = OpTypeStruct %6
406 %8 = OpTypePointer Private %7
407 %9 = OpTypeStruct %6
408 %10 = OpTypePointer Private %9
409 %11 = OpVariable %8 Private
410 %12 = OpVariable %10 Private
411 %4 = OpFunction %2 None %3
412 %5 = OpLabel
413 OpReturn
414 OpFunctionEnd
415 )";
416
417 const auto env = SPV_ENV_UNIVERSAL_1_4;
418 const auto consumer = nullptr;
419 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
420 spvtools::ValidatorOptions validator_options;
421 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
422 kConsoleMessageConsumer));
423 TransformationContext transformation_context(
424 MakeUnique<FactManager>(context.get()), validator_options);
425 {
426 TransformationAccessChain transformation(
427 100, 11, {}, MakeInstructionDescriptor(5, SpvOpReturn, 0));
428 ASSERT_TRUE(
429 transformation.IsApplicable(context.get(), transformation_context));
430 ApplyAndCheckFreshIds(transformation, context.get(),
431 &transformation_context);
432 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
433 context.get(), validator_options, kConsoleMessageConsumer));
434 }
435 {
436 TransformationAccessChain transformation(
437 101, 12, {}, MakeInstructionDescriptor(5, SpvOpReturn, 0));
438 ASSERT_TRUE(
439 transformation.IsApplicable(context.get(), transformation_context));
440 ApplyAndCheckFreshIds(transformation, context.get(),
441 &transformation_context);
442 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
443 context.get(), validator_options, kConsoleMessageConsumer));
444 }
445
446 std::string after_transformation = R"(
447 OpCapability Shader
448 %1 = OpExtInstImport "GLSL.std.450"
449 OpMemoryModel Logical GLSL450
450 OpEntryPoint Fragment %4 "main" %11 %12
451 OpExecutionMode %4 OriginUpperLeft
452 OpSource ESSL 310
453 %2 = OpTypeVoid
454 %3 = OpTypeFunction %2
455 %6 = OpTypeFloat 32
456 %7 = OpTypeStruct %6
457 %8 = OpTypePointer Private %7
458 %9 = OpTypeStruct %6
459 %10 = OpTypePointer Private %9
460 %11 = OpVariable %8 Private
461 %12 = OpVariable %10 Private
462 %4 = OpFunction %2 None %3
463 %5 = OpLabel
464 %100 = OpAccessChain %8 %11
465 %101 = OpAccessChain %10 %12
466 OpReturn
467 OpFunctionEnd
468 )";
469 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
470 }
471
TEST(TransformationAccessChainTest,ClampingVariables)472 TEST(TransformationAccessChainTest, ClampingVariables) {
473 std::string shader = R"(
474 OpCapability Shader
475 %1 = OpExtInstImport "GLSL.std.450"
476 OpMemoryModel Logical GLSL450
477 OpEntryPoint Fragment %2 "main" %3
478 OpExecutionMode %2 OriginUpperLeft
479 OpSource ESSL 310
480 %4 = OpTypeVoid
481 %5 = OpTypeBool
482 %6 = OpTypeFunction %4
483 %7 = OpTypeInt 32 1
484 %8 = OpTypeVector %7 4
485 %9 = OpTypePointer Function %8
486 %10 = OpConstant %7 0
487 %11 = OpConstant %7 1
488 %12 = OpConstant %7 3
489 %13 = OpConstant %7 2
490 %14 = OpConstantComposite %8 %10 %11 %12 %13
491 %15 = OpTypePointer Function %7
492 %16 = OpTypeInt 32 0
493 %17 = OpConstant %16 1
494 %18 = OpConstant %16 3
495 %19 = OpTypeStruct %8
496 %20 = OpTypePointer Function %19
497 %21 = OpConstant %7 9
498 %22 = OpConstant %16 10
499 %23 = OpTypeArray %19 %22
500 %24 = OpTypePointer Function %23
501 %25 = OpTypeFloat 32
502 %26 = OpTypeVector %25 4
503 %27 = OpTypePointer Output %26
504 %3 = OpVariable %27 Output
505 %2 = OpFunction %4 None %6
506 %28 = OpLabel
507 %29 = OpVariable %9 Function
508 %30 = OpVariable %15 Function
509 %31 = OpVariable %15 Function
510 %32 = OpVariable %20 Function
511 %33 = OpVariable %15 Function
512 %34 = OpVariable %24 Function
513 OpStore %29 %14
514 OpStore %30 %10
515 %36 = OpLoad %7 %30
516 %38 = OpLoad %8 %29
517 %39 = OpCompositeConstruct %19 %38
518 %40 = OpLoad %7 %30
519 %42 = OpLoad %8 %29
520 %43 = OpCompositeConstruct %19 %42
521 %45 = OpLoad %7 %30
522 %46 = OpLoad %7 %33
523 OpReturn
524 OpFunctionEnd
525 )";
526
527 const auto env = SPV_ENV_UNIVERSAL_1_4;
528 const auto consumer = nullptr;
529 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
530 spvtools::ValidatorOptions validator_options;
531 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
532 kConsoleMessageConsumer));
533 TransformationContext transformation_context(
534 MakeUnique<FactManager>(context.get()), validator_options);
535 // Bad: no ids given for clamping
536 ASSERT_FALSE(TransformationAccessChain(
537 100, 29, {17}, MakeInstructionDescriptor(36, SpvOpLoad, 0))
538 .IsApplicable(context.get(), transformation_context));
539
540 // Bad: an id given for clamping is not fresh
541 ASSERT_FALSE(TransformationAccessChain(
542 100, 29, {17}, MakeInstructionDescriptor(36, SpvOpLoad, 0),
543 {{46, 201}})
544 .IsApplicable(context.get(), transformation_context));
545
546 // Bad: an id given for clamping is not fresh
547 ASSERT_FALSE(TransformationAccessChain(
548 100, 29, {17}, MakeInstructionDescriptor(36, SpvOpLoad, 0),
549 {{200, 46}})
550 .IsApplicable(context.get(), transformation_context));
551
552 // Bad: an id given for clamping is the same as the id for the access chain
553 ASSERT_FALSE(TransformationAccessChain(
554 100, 29, {17}, MakeInstructionDescriptor(36, SpvOpLoad, 0),
555 {{100, 201}})
556 .IsApplicable(context.get(), transformation_context));
557
558 // Bad: the fresh ids given are not distinct
559 ASSERT_FALSE(TransformationAccessChain(
560 100, 29, {17}, MakeInstructionDescriptor(36, SpvOpLoad, 0),
561 {{200, 200}})
562 .IsApplicable(context.get(), transformation_context));
563
564 // Bad: not enough ids given for clamping (2 pairs needed)
565 ASSERT_FALSE(
566 TransformationAccessChain(104, 34, {45, 10, 46},
567 MakeInstructionDescriptor(46, SpvOpReturn, 0),
568 {{208, 209}, {209, 211}})
569 .IsApplicable(context.get(), transformation_context));
570
571 // Bad: the fresh ids given are not distinct
572 ASSERT_FALSE(
573 TransformationAccessChain(104, 34, {45, 10, 46},
574 MakeInstructionDescriptor(46, SpvOpReturn, 0),
575 {{208, 209}, {209, 211}})
576 .IsApplicable(context.get(), transformation_context));
577
578 {
579 TransformationAccessChain transformation(
580 100, 29, {17}, MakeInstructionDescriptor(36, SpvOpLoad, 0),
581 {{200, 201}});
582 ASSERT_TRUE(
583 transformation.IsApplicable(context.get(), transformation_context));
584 ApplyAndCheckFreshIds(transformation, context.get(),
585 &transformation_context);
586 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
587 context.get(), validator_options, kConsoleMessageConsumer));
588 }
589
590 {
591 TransformationAccessChain transformation(
592 101, 29, {36}, MakeInstructionDescriptor(38, SpvOpLoad, 0),
593 {{202, 203}});
594 ASSERT_TRUE(
595 transformation.IsApplicable(context.get(), transformation_context));
596 ApplyAndCheckFreshIds(transformation, context.get(),
597 &transformation_context);
598 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
599 context.get(), validator_options, kConsoleMessageConsumer));
600 }
601
602 {
603 TransformationAccessChain transformation(
604 102, 32, {10, 40}, MakeInstructionDescriptor(42, SpvOpLoad, 0),
605 {{204, 205}});
606 ASSERT_TRUE(
607 transformation.IsApplicable(context.get(), transformation_context));
608 ApplyAndCheckFreshIds(transformation, context.get(),
609 &transformation_context);
610 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
611 context.get(), validator_options, kConsoleMessageConsumer));
612 }
613
614 {
615 TransformationAccessChain transformation(
616 103, 34, {11}, MakeInstructionDescriptor(45, SpvOpLoad, 0),
617 {{206, 207}});
618 ASSERT_TRUE(
619 transformation.IsApplicable(context.get(), transformation_context));
620 ApplyAndCheckFreshIds(transformation, context.get(),
621 &transformation_context);
622 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
623 context.get(), validator_options, kConsoleMessageConsumer));
624 }
625
626 {
627 TransformationAccessChain transformation(
628 104, 34, {45, 10, 46}, MakeInstructionDescriptor(46, SpvOpReturn, 0),
629 {{208, 209}, {210, 211}});
630 ASSERT_TRUE(
631 transformation.IsApplicable(context.get(), transformation_context));
632 ApplyAndCheckFreshIds(transformation, context.get(),
633 &transformation_context);
634 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
635 context.get(), validator_options, kConsoleMessageConsumer));
636 }
637
638 std::string after_transformation = R"(
639 OpCapability Shader
640 %1 = OpExtInstImport "GLSL.std.450"
641 OpMemoryModel Logical GLSL450
642 OpEntryPoint Fragment %2 "main" %3
643 OpExecutionMode %2 OriginUpperLeft
644 OpSource ESSL 310
645 %4 = OpTypeVoid
646 %5 = OpTypeBool
647 %6 = OpTypeFunction %4
648 %7 = OpTypeInt 32 1
649 %8 = OpTypeVector %7 4
650 %9 = OpTypePointer Function %8
651 %10 = OpConstant %7 0
652 %11 = OpConstant %7 1
653 %12 = OpConstant %7 3
654 %13 = OpConstant %7 2
655 %14 = OpConstantComposite %8 %10 %11 %12 %13
656 %15 = OpTypePointer Function %7
657 %16 = OpTypeInt 32 0
658 %17 = OpConstant %16 1
659 %18 = OpConstant %16 3
660 %19 = OpTypeStruct %8
661 %20 = OpTypePointer Function %19
662 %21 = OpConstant %7 9
663 %22 = OpConstant %16 10
664 %23 = OpTypeArray %19 %22
665 %24 = OpTypePointer Function %23
666 %25 = OpTypeFloat 32
667 %26 = OpTypeVector %25 4
668 %27 = OpTypePointer Output %26
669 %3 = OpVariable %27 Output
670 %2 = OpFunction %4 None %6
671 %28 = OpLabel
672 %29 = OpVariable %9 Function
673 %30 = OpVariable %15 Function
674 %31 = OpVariable %15 Function
675 %32 = OpVariable %20 Function
676 %33 = OpVariable %15 Function
677 %34 = OpVariable %24 Function
678 OpStore %29 %14
679 OpStore %30 %10
680 %200 = OpULessThanEqual %5 %17 %18
681 %201 = OpSelect %16 %200 %17 %18
682 %100 = OpAccessChain %15 %29 %201
683 %36 = OpLoad %7 %30
684 %202 = OpULessThanEqual %5 %36 %12
685 %203 = OpSelect %7 %202 %36 %12
686 %101 = OpAccessChain %15 %29 %203
687 %38 = OpLoad %8 %29
688 %39 = OpCompositeConstruct %19 %38
689 %40 = OpLoad %7 %30
690 %204 = OpULessThanEqual %5 %40 %12
691 %205 = OpSelect %7 %204 %40 %12
692 %102 = OpAccessChain %15 %32 %10 %205
693 %42 = OpLoad %8 %29
694 %43 = OpCompositeConstruct %19 %42
695 %206 = OpULessThanEqual %5 %11 %21
696 %207 = OpSelect %7 %206 %11 %21
697 %103 = OpAccessChain %20 %34 %207
698 %45 = OpLoad %7 %30
699 %46 = OpLoad %7 %33
700 %208 = OpULessThanEqual %5 %45 %21
701 %209 = OpSelect %7 %208 %45 %21
702 %210 = OpULessThanEqual %5 %46 %12
703 %211 = OpSelect %7 %210 %46 %12
704 %104 = OpAccessChain %15 %34 %209 %10 %211
705 OpReturn
706 OpFunctionEnd
707 )";
708 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
709 }
710
711 } // namespace
712 } // namespace fuzz
713 } // namespace spvtools
714