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/data_descriptor.h"
16
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "source/fuzz/id_use_descriptor.h"
20 #include "source/fuzz/instruction_descriptor.h"
21 #include "source/fuzz/transformation_composite_extract.h"
22 #include "source/fuzz/transformation_replace_id_with_synonym.h"
23 #include "source/fuzz/transformation_vector_shuffle.h"
24 #include "test/fuzz/fuzz_test_util.h"
25
26 namespace spvtools {
27 namespace fuzz {
28 namespace {
29
30 // This file captures tests that check correctness of the collective use of a
31 // number of transformations that relate to data synonyms.
32
MakeSynonymFact(uint32_t first_id, const std::vector<uint32_t>& first_indices, uint32_t second_id, const std::vector<uint32_t>& second_indices)33 protobufs::Fact MakeSynonymFact(uint32_t first_id,
34 const std::vector<uint32_t>& first_indices,
35 uint32_t second_id,
36 const std::vector<uint32_t>& second_indices) {
37 protobufs::FactDataSynonym data_synonym_fact;
38 *data_synonym_fact.mutable_data1() =
39 MakeDataDescriptor(first_id, first_indices);
40 *data_synonym_fact.mutable_data2() =
41 MakeDataDescriptor(second_id, second_indices);
42 protobufs::Fact result;
43 *result.mutable_data_synonym_fact() = data_synonym_fact;
44 return result;
45 }
46
TEST(DataSynonymTransformationTest, ArrayCompositeSynonyms)47 TEST(DataSynonymTransformationTest, ArrayCompositeSynonyms) {
48 std::string shader = R"(
49 OpCapability Shader
50 %1 = OpExtInstImport "GLSL.std.450"
51 OpMemoryModel Logical GLSL450
52 OpEntryPoint Fragment %4 "main"
53 OpExecutionMode %4 OriginUpperLeft
54 OpSource ESSL 310
55 OpName %4 "main"
56 OpName %11 "A"
57 OpName %20 "B"
58 OpName %31 "g"
59 OpName %35 "h"
60 OpDecorate %11 RelaxedPrecision
61 OpDecorate %22 RelaxedPrecision
62 OpDecorate %27 RelaxedPrecision
63 OpDecorate %35 RelaxedPrecision
64 OpDecorate %36 RelaxedPrecision
65 OpDecorate %40 RelaxedPrecision
66 OpDecorate %41 RelaxedPrecision
67 %2 = OpTypeVoid
68 %3 = OpTypeFunction %2
69 %6 = OpTypeInt 32 1
70 %7 = OpTypeInt 32 0
71 %8 = OpConstant %7 3
72 %9 = OpTypeArray %6 %8
73 %10 = OpTypePointer Function %9
74 %12 = OpConstant %6 0
75 %13 = OpConstant %6 3
76 %14 = OpTypePointer Function %6
77 %16 = OpTypeFloat 32
78 %17 = OpConstant %7 4
79 %18 = OpTypeArray %16 %17
80 %19 = OpTypePointer Function %18
81 %24 = OpTypePointer Function %16
82 %28 = OpConstant %16 42
83 %30 = OpConstant %6 2
84 %34 = OpConstant %6 1
85 %38 = OpConstant %6 42
86 %4 = OpFunction %2 None %3
87 %5 = OpLabel
88 %11 = OpVariable %10 Function
89 %20 = OpVariable %19 Function
90 %31 = OpVariable %24 Function
91 %35 = OpVariable %14 Function
92 %15 = OpAccessChain %14 %11 %12
93 %21 = OpAccessChain %14 %11 %12
94 %22 = OpLoad %6 %21
95 %100 = OpCompositeConstruct %9 %12 %13 %22
96 OpStore %15 %13
97 %23 = OpConvertSToF %16 %22
98 %25 = OpAccessChain %24 %20 %12
99 OpStore %25 %23
100 %26 = OpAccessChain %14 %11 %12
101 %27 = OpLoad %6 %26
102 %29 = OpAccessChain %24 %20 %27
103 OpStore %29 %28
104 %32 = OpLoad %16 %31
105 %101 = OpCompositeConstruct %18 %28 %23 %32 %23
106 %50 = OpCopyObject %16 %23
107 %51 = OpCopyObject %16 %23
108 %33 = OpAccessChain %24 %20 %30
109 OpStore %33 %28
110 OpStore %33 %32
111 %36 = OpLoad %6 %35
112 %37 = OpAccessChain %14 %11 %34
113 OpStore %37 %36
114 %39 = OpAccessChain %14 %11 %12
115 %40 = OpLoad %6 %39
116 %41 = OpIAdd %6 %38 %40
117 %42 = OpAccessChain %14 %11 %30
118 OpStore %42 %41
119 OpReturn
120 OpFunctionEnd
121 )";
122
123 const auto env = SPV_ENV_UNIVERSAL_1_3;
124 const auto consumer = nullptr;
125 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
126 spvtools::ValidatorOptions validator_options;
127 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
128 kConsoleMessageConsumer));
129 TransformationContext transformation_context(
130 MakeUnique<FactManager>(context.get()), validator_options);
131
132 transformation_context.GetFactManager()->MaybeAddFact(
133 MakeSynonymFact(12, {}, 100, {0}));
134 transformation_context.GetFactManager()->MaybeAddFact(
135 MakeSynonymFact(13, {}, 100, {1}));
136 transformation_context.GetFactManager()->MaybeAddFact(
137 MakeSynonymFact(22, {}, 100, {2}));
138 transformation_context.GetFactManager()->MaybeAddFact(
139 MakeSynonymFact(28, {}, 101, {0}));
140 transformation_context.GetFactManager()->MaybeAddFact(
141 MakeSynonymFact(23, {}, 101, {1}));
142 transformation_context.GetFactManager()->MaybeAddFact(
143 MakeSynonymFact(32, {}, 101, {2}));
144 transformation_context.GetFactManager()->MaybeAddFact(
145 MakeSynonymFact(23, {}, 101, {3}));
146
147 // Replace %12 with %100[0] in '%25 = OpAccessChain %24 %20 %12'
148 auto instruction_descriptor_1 =
149 MakeInstructionDescriptor(25, spv::Op::OpAccessChain, 0);
150 auto good_extract_1 =
151 TransformationCompositeExtract(instruction_descriptor_1, 102, 100, {0});
152 // Bad: id already in use
153 auto bad_extract_1 = TransformationCompositeExtract(
154 MakeInstructionDescriptor(25, spv::Op::OpAccessChain, 0), 25, 100, {0});
155 ASSERT_TRUE(
156 good_extract_1.IsApplicable(context.get(), transformation_context));
157 ASSERT_FALSE(
158 bad_extract_1.IsApplicable(context.get(), transformation_context));
159 good_extract_1.Apply(context.get(), &transformation_context);
160 auto replacement_1 = TransformationReplaceIdWithSynonym(
161 MakeIdUseDescriptor(12, instruction_descriptor_1, 1), 102);
162 ASSERT_TRUE(
163 replacement_1.IsApplicable(context.get(), transformation_context));
164 replacement_1.Apply(context.get(), &transformation_context);
165 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
166 kConsoleMessageConsumer));
167
168 // Replace %13 with %100[1] in 'OpStore %15 %13'
169 auto instruction_descriptor_2 =
170 MakeInstructionDescriptor(100, spv::Op::OpStore, 0);
171 auto good_extract_2 =
172 TransformationCompositeExtract(instruction_descriptor_2, 103, 100, {1});
173 // No bad example provided here.
174 ASSERT_TRUE(
175 good_extract_2.IsApplicable(context.get(), transformation_context));
176 good_extract_2.Apply(context.get(), &transformation_context);
177 auto replacement_2 = TransformationReplaceIdWithSynonym(
178 MakeIdUseDescriptor(13, instruction_descriptor_2, 1), 103);
179 ASSERT_TRUE(
180 replacement_2.IsApplicable(context.get(), transformation_context));
181 replacement_2.Apply(context.get(), &transformation_context);
182 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
183 kConsoleMessageConsumer));
184
185 // Replace %22 with %100[2] in '%23 = OpConvertSToF %16 %22'
186 auto instruction_descriptor_3 =
187 MakeInstructionDescriptor(23, spv::Op::OpConvertSToF, 0);
188 auto good_extract_3 =
189 TransformationCompositeExtract(instruction_descriptor_3, 104, 100, {2});
190 ASSERT_TRUE(
191 good_extract_3.IsApplicable(context.get(), transformation_context));
192 good_extract_3.Apply(context.get(), &transformation_context);
193 auto replacement_3 = TransformationReplaceIdWithSynonym(
194 MakeIdUseDescriptor(22, instruction_descriptor_3, 0), 104);
195 // Bad: wrong input operand index
196 auto bad_replacement_3 = TransformationReplaceIdWithSynonym(
197 MakeIdUseDescriptor(22, instruction_descriptor_3, 1), 104);
198 ASSERT_TRUE(
199 replacement_3.IsApplicable(context.get(), transformation_context));
200 ASSERT_FALSE(
201 bad_replacement_3.IsApplicable(context.get(), transformation_context));
202 replacement_3.Apply(context.get(), &transformation_context);
203 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
204 kConsoleMessageConsumer));
205
206 // Replace %28 with %101[0] in 'OpStore %33 %28'
207 auto instruction_descriptor_4 =
208 MakeInstructionDescriptor(33, spv::Op::OpStore, 0);
209 auto good_extract_4 =
210 TransformationCompositeExtract(instruction_descriptor_4, 105, 101, {0});
211 // Bad: instruction descriptor does not identify an appropriate instruction
212 auto bad_extract_4 = TransformationCompositeExtract(
213 MakeInstructionDescriptor(33, spv::Op::OpCopyObject, 0), 105, 101, {0});
214 ASSERT_TRUE(
215 good_extract_4.IsApplicable(context.get(), transformation_context));
216 ASSERT_FALSE(
217 bad_extract_4.IsApplicable(context.get(), transformation_context));
218 good_extract_4.Apply(context.get(), &transformation_context);
219 auto replacement_4 = TransformationReplaceIdWithSynonym(
220 MakeIdUseDescriptor(28, instruction_descriptor_4, 1), 105);
221 ASSERT_TRUE(
222 replacement_4.IsApplicable(context.get(), transformation_context));
223 replacement_4.Apply(context.get(), &transformation_context);
224 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
225 kConsoleMessageConsumer));
226
227 // Replace %23 with %101[1] in '%50 = OpCopyObject %16 %23'
228 auto instruction_descriptor_5 =
229 MakeInstructionDescriptor(50, spv::Op::OpCopyObject, 0);
230 auto good_extract_5 =
231 TransformationCompositeExtract(instruction_descriptor_5, 106, 101, {1});
232 ASSERT_TRUE(
233 good_extract_5.IsApplicable(context.get(), transformation_context));
234 good_extract_5.Apply(context.get(), &transformation_context);
235 auto replacement_5 = TransformationReplaceIdWithSynonym(
236 MakeIdUseDescriptor(23, instruction_descriptor_5, 0), 106);
237 // Bad: wrong synonym fact being used
238 auto bad_replacement_5 = TransformationReplaceIdWithSynonym(
239 MakeIdUseDescriptor(23, instruction_descriptor_5, 0), 105);
240 ASSERT_TRUE(
241 replacement_5.IsApplicable(context.get(), transformation_context));
242 ASSERT_FALSE(
243 bad_replacement_5.IsApplicable(context.get(), transformation_context));
244 replacement_5.Apply(context.get(), &transformation_context);
245 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
246 kConsoleMessageConsumer));
247
248 // Replace %32 with %101[2] in 'OpStore %33 %32'
249 auto instruction_descriptor_6 =
250 MakeInstructionDescriptor(33, spv::Op::OpStore, 1);
251 auto good_extract_6 =
252 TransformationCompositeExtract(instruction_descriptor_6, 107, 101, {2});
253 // Bad: id 1001 does not exist
254 auto bad_extract_6 =
255 TransformationCompositeExtract(instruction_descriptor_6, 107, 1001, {2});
256 ASSERT_TRUE(
257 good_extract_6.IsApplicable(context.get(), transformation_context));
258 ASSERT_FALSE(
259 bad_extract_6.IsApplicable(context.get(), transformation_context));
260 good_extract_6.Apply(context.get(), &transformation_context);
261 auto replacement_6 = TransformationReplaceIdWithSynonym(
262 MakeIdUseDescriptor(32, instruction_descriptor_6, 1), 107);
263 ASSERT_TRUE(
264 replacement_6.IsApplicable(context.get(), transformation_context));
265 replacement_6.Apply(context.get(), &transformation_context);
266 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
267 kConsoleMessageConsumer));
268
269 // Replace %23 with %101[3] in '%51 = OpCopyObject %16 %23'
270 auto instruction_descriptor_7 =
271 MakeInstructionDescriptor(51, spv::Op::OpCopyObject, 0);
272 auto good_extract_7 =
273 TransformationCompositeExtract(instruction_descriptor_7, 108, 101, {3});
274 ASSERT_TRUE(
275 good_extract_7.IsApplicable(context.get(), transformation_context));
276 good_extract_7.Apply(context.get(), &transformation_context);
277 auto replacement_7 = TransformationReplaceIdWithSynonym(
278 MakeIdUseDescriptor(23, instruction_descriptor_7, 0), 108);
279 // Bad: use id 0 is invalid
280 auto bad_replacement_7 = TransformationReplaceIdWithSynonym(
281 MakeIdUseDescriptor(0, instruction_descriptor_7, 0), 108);
282 ASSERT_TRUE(
283 replacement_7.IsApplicable(context.get(), transformation_context));
284 ASSERT_FALSE(
285 bad_replacement_7.IsApplicable(context.get(), transformation_context));
286 replacement_7.Apply(context.get(), &transformation_context);
287 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
288 kConsoleMessageConsumer));
289
290 const std::string after_transformation = R"(
291 OpCapability Shader
292 %1 = OpExtInstImport "GLSL.std.450"
293 OpMemoryModel Logical GLSL450
294 OpEntryPoint Fragment %4 "main"
295 OpExecutionMode %4 OriginUpperLeft
296 OpSource ESSL 310
297 OpName %4 "main"
298 OpName %11 "A"
299 OpName %20 "B"
300 OpName %31 "g"
301 OpName %35 "h"
302 OpDecorate %11 RelaxedPrecision
303 OpDecorate %22 RelaxedPrecision
304 OpDecorate %27 RelaxedPrecision
305 OpDecorate %35 RelaxedPrecision
306 OpDecorate %36 RelaxedPrecision
307 OpDecorate %40 RelaxedPrecision
308 OpDecorate %41 RelaxedPrecision
309 %2 = OpTypeVoid
310 %3 = OpTypeFunction %2
311 %6 = OpTypeInt 32 1
312 %7 = OpTypeInt 32 0
313 %8 = OpConstant %7 3
314 %9 = OpTypeArray %6 %8
315 %10 = OpTypePointer Function %9
316 %12 = OpConstant %6 0
317 %13 = OpConstant %6 3
318 %14 = OpTypePointer Function %6
319 %16 = OpTypeFloat 32
320 %17 = OpConstant %7 4
321 %18 = OpTypeArray %16 %17
322 %19 = OpTypePointer Function %18
323 %24 = OpTypePointer Function %16
324 %28 = OpConstant %16 42
325 %30 = OpConstant %6 2
326 %34 = OpConstant %6 1
327 %38 = OpConstant %6 42
328 %4 = OpFunction %2 None %3
329 %5 = OpLabel
330 %11 = OpVariable %10 Function
331 %20 = OpVariable %19 Function
332 %31 = OpVariable %24 Function
333 %35 = OpVariable %14 Function
334 %15 = OpAccessChain %14 %11 %12
335 %21 = OpAccessChain %14 %11 %12
336 %22 = OpLoad %6 %21
337 %100 = OpCompositeConstruct %9 %12 %13 %22
338 %103 = OpCompositeExtract %6 %100 1
339 OpStore %15 %103
340 %104 = OpCompositeExtract %6 %100 2
341 %23 = OpConvertSToF %16 %104
342 %102 = OpCompositeExtract %6 %100 0
343 %25 = OpAccessChain %24 %20 %102
344 OpStore %25 %23
345 %26 = OpAccessChain %14 %11 %12
346 %27 = OpLoad %6 %26
347 %29 = OpAccessChain %24 %20 %27
348 OpStore %29 %28
349 %32 = OpLoad %16 %31
350 %101 = OpCompositeConstruct %18 %28 %23 %32 %23
351 %106 = OpCompositeExtract %16 %101 1
352 %50 = OpCopyObject %16 %106
353 %108 = OpCompositeExtract %16 %101 3
354 %51 = OpCopyObject %16 %108
355 %33 = OpAccessChain %24 %20 %30
356 %105 = OpCompositeExtract %16 %101 0
357 OpStore %33 %105
358 %107 = OpCompositeExtract %16 %101 2
359 OpStore %33 %107
360 %36 = OpLoad %6 %35
361 %37 = OpAccessChain %14 %11 %34
362 OpStore %37 %36
363 %39 = OpAccessChain %14 %11 %12
364 %40 = OpLoad %6 %39
365 %41 = OpIAdd %6 %38 %40
366 %42 = OpAccessChain %14 %11 %30
367 OpStore %42 %41
368 OpReturn
369 OpFunctionEnd
370 )";
371
372 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
373 }
374
TEST(DataSynonymTransformationTest, MatrixCompositeSynonyms)375 TEST(DataSynonymTransformationTest, MatrixCompositeSynonyms) {
376 std::string shader = R"(
377 OpCapability Shader
378 %1 = OpExtInstImport "GLSL.std.450"
379 OpMemoryModel Logical GLSL450
380 OpEntryPoint Fragment %4 "main"
381 OpExecutionMode %4 OriginUpperLeft
382 OpSource ESSL 310
383 OpName %4 "main"
384 OpName %10 "m"
385 %2 = OpTypeVoid
386 %3 = OpTypeFunction %2
387 %6 = OpTypeFloat 32
388 %7 = OpTypeVector %6 4
389 %50 = OpUndef %7
390 %8 = OpTypeMatrix %7 3
391 %9 = OpTypePointer Function %8
392 %11 = OpTypeInt 32 1
393 %12 = OpConstant %11 0
394 %13 = OpConstant %6 1
395 %14 = OpConstantComposite %7 %13 %13 %13 %13
396 %15 = OpTypePointer Function %7
397 %17 = OpConstant %11 1
398 %18 = OpConstant %6 2
399 %19 = OpConstantComposite %7 %18 %18 %18 %18
400 %21 = OpConstant %11 2
401 %4 = OpFunction %2 None %3
402 %5 = OpLabel
403 %10 = OpVariable %9 Function
404 %16 = OpAccessChain %15 %10 %12
405 OpStore %16 %14
406 %20 = OpAccessChain %15 %10 %17
407 OpStore %20 %19
408 %22 = OpAccessChain %15 %10 %12
409 %23 = OpLoad %7 %22
410 %24 = OpAccessChain %15 %10 %17
411 %25 = OpLoad %7 %24
412 %100 = OpCompositeConstruct %8 %23 %25 %50
413 %26 = OpFAdd %7 %23 %25
414 %27 = OpAccessChain %15 %10 %21
415 OpStore %27 %26
416 OpReturn
417 OpFunctionEnd
418 )";
419
420 const auto env = SPV_ENV_UNIVERSAL_1_3;
421 const auto consumer = nullptr;
422 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
423 spvtools::ValidatorOptions validator_options;
424 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
425 kConsoleMessageConsumer));
426 TransformationContext transformation_context(
427 MakeUnique<FactManager>(context.get()), validator_options);
428
429 transformation_context.GetFactManager()->MaybeAddFact(
430 MakeSynonymFact(23, {}, 100, {0}));
431 transformation_context.GetFactManager()->MaybeAddFact(
432 MakeSynonymFact(25, {}, 100, {1}));
433 transformation_context.GetFactManager()->MaybeAddFact(
434 MakeSynonymFact(50, {}, 100, {2}));
435
436 // Replace %23 with %100[0] in '%26 = OpFAdd %7 %23 %25'
437 auto instruction_descriptor_1 =
438 MakeInstructionDescriptor(26, spv::Op::OpFAdd, 0);
439 auto extract_1 =
440 TransformationCompositeExtract(instruction_descriptor_1, 101, 100, {0});
441 ASSERT_TRUE(extract_1.IsApplicable(context.get(), transformation_context));
442 extract_1.Apply(context.get(), &transformation_context);
443 auto replacement_1 = TransformationReplaceIdWithSynonym(
444 MakeIdUseDescriptor(23, instruction_descriptor_1, 0), 101);
445 ASSERT_TRUE(
446 replacement_1.IsApplicable(context.get(), transformation_context));
447 replacement_1.Apply(context.get(), &transformation_context);
448 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
449 kConsoleMessageConsumer));
450
451 // Replace %25 with %100[1] in '%26 = OpFAdd %7 %23 %25'
452 auto instruction_descriptor_2 =
453 MakeInstructionDescriptor(26, spv::Op::OpFAdd, 0);
454 auto extract_2 =
455 TransformationCompositeExtract(instruction_descriptor_2, 102, 100, {1});
456 ASSERT_TRUE(extract_2.IsApplicable(context.get(), transformation_context));
457 extract_2.Apply(context.get(), &transformation_context);
458 auto replacement_2 = TransformationReplaceIdWithSynonym(
459 MakeIdUseDescriptor(25, instruction_descriptor_2, 1), 102);
460 ASSERT_TRUE(
461 replacement_2.IsApplicable(context.get(), transformation_context));
462 replacement_2.Apply(context.get(), &transformation_context);
463 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
464 kConsoleMessageConsumer));
465
466 const std::string after_transformation = R"(
467 OpCapability Shader
468 %1 = OpExtInstImport "GLSL.std.450"
469 OpMemoryModel Logical GLSL450
470 OpEntryPoint Fragment %4 "main"
471 OpExecutionMode %4 OriginUpperLeft
472 OpSource ESSL 310
473 OpName %4 "main"
474 OpName %10 "m"
475 %2 = OpTypeVoid
476 %3 = OpTypeFunction %2
477 %6 = OpTypeFloat 32
478 %7 = OpTypeVector %6 4
479 %50 = OpUndef %7
480 %8 = OpTypeMatrix %7 3
481 %9 = OpTypePointer Function %8
482 %11 = OpTypeInt 32 1
483 %12 = OpConstant %11 0
484 %13 = OpConstant %6 1
485 %14 = OpConstantComposite %7 %13 %13 %13 %13
486 %15 = OpTypePointer Function %7
487 %17 = OpConstant %11 1
488 %18 = OpConstant %6 2
489 %19 = OpConstantComposite %7 %18 %18 %18 %18
490 %21 = OpConstant %11 2
491 %4 = OpFunction %2 None %3
492 %5 = OpLabel
493 %10 = OpVariable %9 Function
494 %16 = OpAccessChain %15 %10 %12
495 OpStore %16 %14
496 %20 = OpAccessChain %15 %10 %17
497 OpStore %20 %19
498 %22 = OpAccessChain %15 %10 %12
499 %23 = OpLoad %7 %22
500 %24 = OpAccessChain %15 %10 %17
501 %25 = OpLoad %7 %24
502 %100 = OpCompositeConstruct %8 %23 %25 %50
503 %101 = OpCompositeExtract %7 %100 0
504 %102 = OpCompositeExtract %7 %100 1
505 %26 = OpFAdd %7 %101 %102
506 %27 = OpAccessChain %15 %10 %21
507 OpStore %27 %26
508 OpReturn
509 OpFunctionEnd
510 )";
511
512 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
513 }
514
TEST(DataSynonymTransformationTest, StructCompositeSynonyms)515 TEST(DataSynonymTransformationTest, StructCompositeSynonyms) {
516 std::string shader = R"(
517 OpCapability Shader
518 %1 = OpExtInstImport "GLSL.std.450"
519 OpMemoryModel Logical GLSL450
520 OpEntryPoint Fragment %4 "main"
521 OpExecutionMode %4 OriginUpperLeft
522 OpSource ESSL 310
523 OpName %4 "main"
524 OpName %9 "Inner"
525 OpMemberName %9 0 "a"
526 OpMemberName %9 1 "b"
527 OpName %11 "i1"
528 OpName %17 "i2"
529 OpName %31 "Point"
530 OpMemberName %31 0 "x"
531 OpMemberName %31 1 "y"
532 OpMemberName %31 2 "z"
533 OpName %32 "Outer"
534 OpMemberName %32 0 "c"
535 OpMemberName %32 1 "d"
536 OpName %34 "o1"
537 %2 = OpTypeVoid
538 %3 = OpTypeFunction %2
539 %6 = OpTypeInt 32 1
540 %7 = OpTypeFloat 32
541 %8 = OpTypeVector %7 2
542 %9 = OpTypeStruct %6 %8
543 %10 = OpTypePointer Function %9
544 %12 = OpConstant %6 1
545 %13 = OpConstant %7 2
546 %14 = OpConstant %7 3
547 %15 = OpConstantComposite %8 %13 %14
548 %16 = OpConstantComposite %9 %12 %15
549 %18 = OpConstant %6 0
550 %19 = OpTypePointer Function %6
551 %24 = OpTypePointer Function %8
552 %27 = OpConstant %7 4
553 %31 = OpTypeStruct %7 %7 %7
554 %32 = OpTypeStruct %9 %31
555 %33 = OpTypePointer Function %32
556 %36 = OpConstant %7 10
557 %37 = OpTypeInt 32 0
558 %38 = OpConstant %37 0
559 %39 = OpTypePointer Function %7
560 %42 = OpConstant %37 1
561 %4 = OpFunction %2 None %3
562 %5 = OpLabel
563 %11 = OpVariable %10 Function
564 %17 = OpVariable %10 Function
565 %34 = OpVariable %33 Function
566 %101 = OpCompositeConstruct %31 %27 %36 %27
567 OpStore %11 %16
568 %20 = OpAccessChain %19 %11 %18
569 %21 = OpLoad %6 %20
570 %22 = OpIAdd %6 %21 %12
571 %102 = OpCompositeConstruct %9 %22 %15
572 %23 = OpAccessChain %19 %17 %18
573 OpStore %23 %22
574 %25 = OpAccessChain %24 %17 %12
575 %26 = OpLoad %8 %25
576 %28 = OpCompositeConstruct %8 %27 %27
577 %29 = OpFAdd %8 %26 %28
578 %30 = OpAccessChain %24 %17 %12
579 OpStore %30 %29
580 %35 = OpLoad %9 %11
581 %40 = OpAccessChain %39 %11 %12 %38
582 %41 = OpLoad %7 %40
583 %43 = OpAccessChain %39 %11 %12 %42
584 %44 = OpLoad %7 %43
585 %45 = OpCompositeConstruct %31 %36 %41 %44
586 %100 = OpCompositeConstruct %32 %16 %45
587 %46 = OpCompositeConstruct %32 %35 %45
588 OpStore %34 %46
589 OpReturn
590 OpFunctionEnd
591 )";
592
593 const auto env = SPV_ENV_UNIVERSAL_1_3;
594 const auto consumer = nullptr;
595 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
596 spvtools::ValidatorOptions validator_options;
597 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
598 kConsoleMessageConsumer));
599 TransformationContext transformation_context(
600 MakeUnique<FactManager>(context.get()), validator_options);
601
602 transformation_context.GetFactManager()->MaybeAddFact(
603 MakeSynonymFact(16, {}, 100, {0}));
604 transformation_context.GetFactManager()->MaybeAddFact(
605 MakeSynonymFact(45, {}, 100, {1}));
606 transformation_context.GetFactManager()->MaybeAddFact(
607 MakeSynonymFact(27, {}, 101, {0}));
608 transformation_context.GetFactManager()->MaybeAddFact(
609 MakeSynonymFact(36, {}, 101, {1}));
610 transformation_context.GetFactManager()->MaybeAddFact(
611 MakeSynonymFact(27, {}, 101, {2}));
612 transformation_context.GetFactManager()->MaybeAddFact(
613 MakeSynonymFact(22, {}, 102, {0}));
614 transformation_context.GetFactManager()->MaybeAddFact(
615 MakeSynonymFact(15, {}, 102, {1}));
616
617 // Replace %45 with %100[1] in '%46 = OpCompositeConstruct %32 %35 %45'
618 auto instruction_descriptor_1 =
619 MakeInstructionDescriptor(46, spv::Op::OpCompositeConstruct, 0);
620 auto extract_1 =
621 TransformationCompositeExtract(instruction_descriptor_1, 201, 100, {1});
622 ASSERT_TRUE(extract_1.IsApplicable(context.get(), transformation_context));
623 extract_1.Apply(context.get(), &transformation_context);
624 auto replacement_1 = TransformationReplaceIdWithSynonym(
625 MakeIdUseDescriptor(45, instruction_descriptor_1, 1), 201);
626 ASSERT_TRUE(
627 replacement_1.IsApplicable(context.get(), transformation_context));
628 replacement_1.Apply(context.get(), &transformation_context);
629 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
630 kConsoleMessageConsumer));
631
632 // Replace second occurrence of %27 with %101[0] in '%28 =
633 // OpCompositeConstruct %8 %27 %27'
634 auto instruction_descriptor_2 =
635 MakeInstructionDescriptor(28, spv::Op::OpCompositeConstruct, 0);
636 auto extract_2 =
637 TransformationCompositeExtract(instruction_descriptor_2, 202, 101, {0});
638 ASSERT_TRUE(extract_2.IsApplicable(context.get(), transformation_context));
639 extract_2.Apply(context.get(), &transformation_context);
640 auto replacement_2 = TransformationReplaceIdWithSynonym(
641 MakeIdUseDescriptor(27, instruction_descriptor_2, 1), 202);
642 ASSERT_TRUE(
643 replacement_2.IsApplicable(context.get(), transformation_context));
644 replacement_2.Apply(context.get(), &transformation_context);
645 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
646 kConsoleMessageConsumer));
647
648 // Replace %36 with %101[1] in '%45 = OpCompositeConstruct %31 %36 %41 %44'
649 auto instruction_descriptor_3 =
650 MakeInstructionDescriptor(45, spv::Op::OpCompositeConstruct, 0);
651 auto extract_3 =
652 TransformationCompositeExtract(instruction_descriptor_3, 203, 101, {1});
653 ASSERT_TRUE(extract_3.IsApplicable(context.get(), transformation_context));
654 extract_3.Apply(context.get(), &transformation_context);
655 auto replacement_3 = TransformationReplaceIdWithSynonym(
656 MakeIdUseDescriptor(36, instruction_descriptor_3, 0), 203);
657 ASSERT_TRUE(
658 replacement_3.IsApplicable(context.get(), transformation_context));
659 replacement_3.Apply(context.get(), &transformation_context);
660 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
661 kConsoleMessageConsumer));
662
663 // Replace first occurrence of %27 with %101[2] in '%28 = OpCompositeConstruct
664 // %8 %27 %27'
665 auto instruction_descriptor_4 =
666 MakeInstructionDescriptor(28, spv::Op::OpCompositeConstruct, 0);
667 auto extract_4 =
668 TransformationCompositeExtract(instruction_descriptor_4, 204, 101, {2});
669 ASSERT_TRUE(extract_4.IsApplicable(context.get(), transformation_context));
670 extract_4.Apply(context.get(), &transformation_context);
671 auto replacement_4 = TransformationReplaceIdWithSynonym(
672 MakeIdUseDescriptor(27, instruction_descriptor_4, 0), 204);
673 ASSERT_TRUE(
674 replacement_4.IsApplicable(context.get(), transformation_context));
675 replacement_4.Apply(context.get(), &transformation_context);
676 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
677 kConsoleMessageConsumer));
678
679 // Replace %22 with %102[0] in 'OpStore %23 %22'
680 auto instruction_descriptor_5 =
681 MakeInstructionDescriptor(23, spv::Op::OpStore, 0);
682 auto extract_5 =
683 TransformationCompositeExtract(instruction_descriptor_5, 205, 102, {0});
684 ASSERT_TRUE(extract_5.IsApplicable(context.get(), transformation_context));
685 extract_5.Apply(context.get(), &transformation_context);
686 auto replacement_5 = TransformationReplaceIdWithSynonym(
687 MakeIdUseDescriptor(22, instruction_descriptor_5, 1), 205);
688 ASSERT_TRUE(
689 replacement_5.IsApplicable(context.get(), transformation_context));
690 replacement_5.Apply(context.get(), &transformation_context);
691 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
692 kConsoleMessageConsumer));
693
694 const std::string after_transformation = R"(
695 OpCapability Shader
696 %1 = OpExtInstImport "GLSL.std.450"
697 OpMemoryModel Logical GLSL450
698 OpEntryPoint Fragment %4 "main"
699 OpExecutionMode %4 OriginUpperLeft
700 OpSource ESSL 310
701 OpName %4 "main"
702 OpName %9 "Inner"
703 OpMemberName %9 0 "a"
704 OpMemberName %9 1 "b"
705 OpName %11 "i1"
706 OpName %17 "i2"
707 OpName %31 "Point"
708 OpMemberName %31 0 "x"
709 OpMemberName %31 1 "y"
710 OpMemberName %31 2 "z"
711 OpName %32 "Outer"
712 OpMemberName %32 0 "c"
713 OpMemberName %32 1 "d"
714 OpName %34 "o1"
715 %2 = OpTypeVoid
716 %3 = OpTypeFunction %2
717 %6 = OpTypeInt 32 1
718 %7 = OpTypeFloat 32
719 %8 = OpTypeVector %7 2
720 %9 = OpTypeStruct %6 %8
721 %10 = OpTypePointer Function %9
722 %12 = OpConstant %6 1
723 %13 = OpConstant %7 2
724 %14 = OpConstant %7 3
725 %15 = OpConstantComposite %8 %13 %14
726 %16 = OpConstantComposite %9 %12 %15
727 %18 = OpConstant %6 0
728 %19 = OpTypePointer Function %6
729 %24 = OpTypePointer Function %8
730 %27 = OpConstant %7 4
731 %31 = OpTypeStruct %7 %7 %7
732 %32 = OpTypeStruct %9 %31
733 %33 = OpTypePointer Function %32
734 %36 = OpConstant %7 10
735 %37 = OpTypeInt 32 0
736 %38 = OpConstant %37 0
737 %39 = OpTypePointer Function %7
738 %42 = OpConstant %37 1
739 %4 = OpFunction %2 None %3
740 %5 = OpLabel
741 %11 = OpVariable %10 Function
742 %17 = OpVariable %10 Function
743 %34 = OpVariable %33 Function
744 %101 = OpCompositeConstruct %31 %27 %36 %27
745 OpStore %11 %16
746 %20 = OpAccessChain %19 %11 %18
747 %21 = OpLoad %6 %20
748 %22 = OpIAdd %6 %21 %12
749 %102 = OpCompositeConstruct %9 %22 %15
750 %23 = OpAccessChain %19 %17 %18
751 %205 = OpCompositeExtract %6 %102 0
752 OpStore %23 %205
753 %25 = OpAccessChain %24 %17 %12
754 %26 = OpLoad %8 %25
755 %202 = OpCompositeExtract %7 %101 0
756 %204 = OpCompositeExtract %7 %101 2
757 %28 = OpCompositeConstruct %8 %204 %202
758 %29 = OpFAdd %8 %26 %28
759 %30 = OpAccessChain %24 %17 %12
760 OpStore %30 %29
761 %35 = OpLoad %9 %11
762 %40 = OpAccessChain %39 %11 %12 %38
763 %41 = OpLoad %7 %40
764 %43 = OpAccessChain %39 %11 %12 %42
765 %44 = OpLoad %7 %43
766 %203 = OpCompositeExtract %7 %101 1
767 %45 = OpCompositeConstruct %31 %203 %41 %44
768 %100 = OpCompositeConstruct %32 %16 %45
769 %201 = OpCompositeExtract %31 %100 1
770 %46 = OpCompositeConstruct %32 %35 %201
771 OpStore %34 %46
772 OpReturn
773 OpFunctionEnd
774 )";
775
776 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
777 }
778
TEST(DataSynonymTransformationTest, VectorCompositeSynonyms)779 TEST(DataSynonymTransformationTest, VectorCompositeSynonyms) {
780 std::string shader = R"(
781 OpCapability Shader
782 %1 = OpExtInstImport "GLSL.std.450"
783 OpMemoryModel Logical GLSL450
784 OpEntryPoint Fragment %4 "main"
785 OpExecutionMode %4 OriginUpperLeft
786 OpSource ESSL 310
787 OpName %4 "main"
788 OpName %8 "f"
789 OpName %12 "v2"
790 OpName %18 "v3"
791 OpName %23 "v4"
792 OpName %32 "b"
793 OpName %36 "bv2"
794 OpName %41 "bv3"
795 OpName %50 "bv4"
796 %2 = OpTypeVoid
797 %3 = OpTypeFunction %2
798 %6 = OpTypeFloat 32
799 %7 = OpTypePointer Function %6
800 %9 = OpConstant %6 42
801 %10 = OpTypeVector %6 2
802 %11 = OpTypePointer Function %10
803 %16 = OpTypeVector %6 3
804 %17 = OpTypePointer Function %16
805 %21 = OpTypeVector %6 4
806 %22 = OpTypePointer Function %21
807 %30 = OpTypeBool
808 %31 = OpTypePointer Function %30
809 %33 = OpConstantFalse %30
810 %34 = OpTypeVector %30 2
811 %35 = OpTypePointer Function %34
812 %37 = OpConstantTrue %30
813 %38 = OpConstantComposite %34 %37 %37
814 %39 = OpTypeVector %30 3
815 %40 = OpTypePointer Function %39
816 %48 = OpTypeVector %30 4
817 %49 = OpTypePointer Function %48
818 %51 = OpTypeInt 32 0
819 %52 = OpConstant %51 2
820 %55 = OpConstant %6 0
821 %57 = OpConstant %51 1
822 %4 = OpFunction %2 None %3
823 %5 = OpLabel
824 %8 = OpVariable %7 Function
825 %12 = OpVariable %11 Function
826 %18 = OpVariable %17 Function
827 %23 = OpVariable %22 Function
828 %32 = OpVariable %31 Function
829 %36 = OpVariable %35 Function
830 %41 = OpVariable %40 Function
831 %50 = OpVariable %49 Function
832 OpStore %8 %9
833 %13 = OpLoad %6 %8
834 %14 = OpLoad %6 %8
835 %15 = OpCompositeConstruct %10 %13 %14
836 OpStore %12 %15
837 %19 = OpLoad %10 %12
838 %20 = OpVectorShuffle %16 %19 %19 0 0 1
839 OpStore %18 %20
840 %24 = OpLoad %16 %18
841 %25 = OpLoad %6 %8
842 %26 = OpCompositeExtract %6 %24 0
843 %27 = OpCompositeExtract %6 %24 1
844 %28 = OpCompositeExtract %6 %24 2
845 %29 = OpCompositeConstruct %21 %26 %27 %28 %25
846 OpStore %23 %29
847 OpStore %32 %33
848 OpStore %36 %38
849 %42 = OpLoad %30 %32
850 %43 = OpLoad %34 %36
851 %44 = OpVectorShuffle %34 %43 %43 0 0
852 %45 = OpCompositeExtract %30 %44 0
853 %46 = OpCompositeExtract %30 %44 1
854 %47 = OpCompositeConstruct %39 %42 %45 %46
855 OpStore %41 %47
856 %53 = OpAccessChain %7 %23 %52
857 %54 = OpLoad %6 %53
858
859 %100 = OpCompositeConstruct %21 %20 %54
860 %101 = OpCompositeConstruct %21 %15 %19
861 %102 = OpCompositeConstruct %16 %27 %15
862 %103 = OpCompositeConstruct %48 %33 %47
863 %104 = OpCompositeConstruct %34 %42 %45
864 %105 = OpCompositeConstruct %39 %38 %46
865
866 %86 = OpCopyObject %30 %33
867 %56 = OpFOrdNotEqual %30 %54 %55
868 %80 = OpCopyObject %16 %20
869 %58 = OpAccessChain %7 %18 %57
870 %59 = OpLoad %6 %58
871 %60 = OpFOrdNotEqual %30 %59 %55
872 %61 = OpLoad %34 %36
873 %62 = OpLogicalAnd %30 %45 %46
874 %63 = OpLogicalOr %30 %45 %46
875 %64 = OpCompositeConstruct %48 %56 %60 %62 %63
876 OpStore %12 %15
877 %81 = OpVectorShuffle %16 %19 %19 0 0 1
878 %82 = OpCompositeConstruct %21 %26 %27 %28 %25
879 %83 = OpCopyObject %10 %15
880 %84 = OpCopyObject %39 %47
881 OpStore %50 %64
882 %85 = OpCopyObject %30 %42
883 OpStore %36 %38
884 OpReturn
885 OpFunctionEnd
886 )";
887
888 const auto env = SPV_ENV_UNIVERSAL_1_3;
889 const auto consumer = nullptr;
890 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
891 spvtools::ValidatorOptions validator_options;
892 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
893 kConsoleMessageConsumer));
894 TransformationContext transformation_context(
895 MakeUnique<FactManager>(context.get()), validator_options);
896
897 transformation_context.GetFactManager()->MaybeAddFact(
898 MakeSynonymFact(20, {0}, 100, {0}));
899 transformation_context.GetFactManager()->MaybeAddFact(
900 MakeSynonymFact(20, {1}, 100, {1}));
901 transformation_context.GetFactManager()->MaybeAddFact(
902 MakeSynonymFact(20, {2}, 100, {2}));
903 transformation_context.GetFactManager()->MaybeAddFact(
904 MakeSynonymFact(54, {}, 100, {3}));
905 transformation_context.GetFactManager()->MaybeAddFact(
906 MakeSynonymFact(15, {0}, 101, {0}));
907 transformation_context.GetFactManager()->MaybeAddFact(
908 MakeSynonymFact(15, {1}, 101, {1}));
909 transformation_context.GetFactManager()->MaybeAddFact(
910 MakeSynonymFact(19, {0}, 101, {2}));
911 transformation_context.GetFactManager()->MaybeAddFact(
912 MakeSynonymFact(19, {1}, 101, {3}));
913 transformation_context.GetFactManager()->MaybeAddFact(
914 MakeSynonymFact(27, {}, 102, {0}));
915 transformation_context.GetFactManager()->MaybeAddFact(
916 MakeSynonymFact(15, {0}, 102, {1}));
917 transformation_context.GetFactManager()->MaybeAddFact(
918 MakeSynonymFact(15, {1}, 102, {2}));
919 transformation_context.GetFactManager()->MaybeAddFact(
920 MakeSynonymFact(33, {}, 103, {0}));
921 transformation_context.GetFactManager()->MaybeAddFact(
922 MakeSynonymFact(47, {0}, 103, {1}));
923 transformation_context.GetFactManager()->MaybeAddFact(
924 MakeSynonymFact(47, {1}, 103, {2}));
925 transformation_context.GetFactManager()->MaybeAddFact(
926 MakeSynonymFact(47, {2}, 103, {3}));
927 transformation_context.GetFactManager()->MaybeAddFact(
928 MakeSynonymFact(42, {}, 104, {0}));
929 transformation_context.GetFactManager()->MaybeAddFact(
930 MakeSynonymFact(45, {}, 104, {1}));
931 transformation_context.GetFactManager()->MaybeAddFact(
932 MakeSynonymFact(38, {0}, 105, {0}));
933 transformation_context.GetFactManager()->MaybeAddFact(
934 MakeSynonymFact(38, {1}, 105, {1}));
935 transformation_context.GetFactManager()->MaybeAddFact(
936 MakeSynonymFact(46, {}, 105, {2}));
937
938 // Replace %20 with %100[0:2] in '%80 = OpCopyObject %16 %20'
939 auto instruction_descriptor_1 =
940 MakeInstructionDescriptor(80, spv::Op::OpCopyObject, 0);
941 auto shuffle_1 = TransformationVectorShuffle(instruction_descriptor_1, 200,
942 100, 100, {0, 1, 2});
943 ASSERT_TRUE(shuffle_1.IsApplicable(context.get(), transformation_context));
944 shuffle_1.Apply(context.get(), &transformation_context);
945 transformation_context.GetFactManager()->ComputeClosureOfFacts(100);
946
947 auto replacement_1 = TransformationReplaceIdWithSynonym(
948 MakeIdUseDescriptor(20, instruction_descriptor_1, 0), 200);
949 ASSERT_TRUE(
950 replacement_1.IsApplicable(context.get(), transformation_context));
951 replacement_1.Apply(context.get(), &transformation_context);
952 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
953 kConsoleMessageConsumer));
954
955 // Replace %54 with %100[3] in '%56 = OpFOrdNotEqual %30 %54 %55'
956 auto instruction_descriptor_2 =
957 MakeInstructionDescriptor(56, spv::Op::OpFOrdNotEqual, 0);
958 auto extract_2 =
959 TransformationCompositeExtract(instruction_descriptor_2, 201, 100, {3});
960
961 ASSERT_TRUE(extract_2.IsApplicable(context.get(), transformation_context));
962 extract_2.Apply(context.get(), &transformation_context);
963 auto replacement_2 = TransformationReplaceIdWithSynonym(
964 MakeIdUseDescriptor(54, instruction_descriptor_2, 0), 201);
965 ASSERT_TRUE(
966 replacement_2.IsApplicable(context.get(), transformation_context));
967 replacement_2.Apply(context.get(), &transformation_context);
968 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
969 kConsoleMessageConsumer));
970
971 // Replace %15 with %101[0:1] in 'OpStore %12 %15'
972 auto instruction_descriptor_3 =
973 MakeInstructionDescriptor(64, spv::Op::OpStore, 0);
974 auto shuffle_3 = TransformationVectorShuffle(instruction_descriptor_3, 202,
975 101, 101, {0, 1});
976 ASSERT_TRUE(shuffle_3.IsApplicable(context.get(), transformation_context));
977 shuffle_3.Apply(context.get(), &transformation_context);
978 transformation_context.GetFactManager()->ComputeClosureOfFacts(100);
979
980 auto replacement_3 = TransformationReplaceIdWithSynonym(
981 MakeIdUseDescriptor(15, instruction_descriptor_3, 1), 202);
982 ASSERT_TRUE(
983 replacement_3.IsApplicable(context.get(), transformation_context));
984 replacement_3.Apply(context.get(), &transformation_context);
985 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
986 kConsoleMessageConsumer));
987
988 // Replace %19 with %101[2:3] in '%81 = OpVectorShuffle %16 %19 %19 0 0 1'
989 auto instruction_descriptor_4 =
990 MakeInstructionDescriptor(81, spv::Op::OpVectorShuffle, 0);
991 auto shuffle_4 = TransformationVectorShuffle(instruction_descriptor_4, 203,
992 101, 101, {2, 3});
993 ASSERT_TRUE(shuffle_4.IsApplicable(context.get(), transformation_context));
994 shuffle_4.Apply(context.get(), &transformation_context);
995 transformation_context.GetFactManager()->ComputeClosureOfFacts(100);
996
997 auto replacement_4 = TransformationReplaceIdWithSynonym(
998 MakeIdUseDescriptor(19, instruction_descriptor_4, 0), 203);
999 ASSERT_TRUE(
1000 replacement_4.IsApplicable(context.get(), transformation_context));
1001 replacement_4.Apply(context.get(), &transformation_context);
1002 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1003 kConsoleMessageConsumer));
1004
1005 // Replace %27 with %102[0] in '%82 = OpCompositeConstruct %21 %26 %27 %28
1006 // %25'
1007 auto instruction_descriptor_5 =
1008 MakeInstructionDescriptor(82, spv::Op::OpCompositeConstruct, 0);
1009 auto extract_5 =
1010 TransformationCompositeExtract(instruction_descriptor_5, 204, 102, {0});
1011
1012 ASSERT_TRUE(extract_5.IsApplicable(context.get(), transformation_context));
1013 extract_5.Apply(context.get(), &transformation_context);
1014 auto replacement_5 = TransformationReplaceIdWithSynonym(
1015 MakeIdUseDescriptor(27, instruction_descriptor_5, 1), 204);
1016 ASSERT_TRUE(
1017 replacement_5.IsApplicable(context.get(), transformation_context));
1018 replacement_5.Apply(context.get(), &transformation_context);
1019 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1020 kConsoleMessageConsumer));
1021
1022 // Replace %15 with %102[1:2] in '%83 = OpCopyObject %10 %15'
1023 auto instruction_descriptor_6 =
1024 MakeInstructionDescriptor(83, spv::Op::OpCopyObject, 0);
1025 auto shuffle_6 = TransformationVectorShuffle(instruction_descriptor_6, 205,
1026 102, 102, {1, 2});
1027 ASSERT_TRUE(shuffle_6.IsApplicable(context.get(), transformation_context));
1028 shuffle_6.Apply(context.get(), &transformation_context);
1029 transformation_context.GetFactManager()->ComputeClosureOfFacts(100);
1030
1031 auto replacement_6 = TransformationReplaceIdWithSynonym(
1032 MakeIdUseDescriptor(15, instruction_descriptor_6, 0), 205);
1033 ASSERT_TRUE(
1034 replacement_6.IsApplicable(context.get(), transformation_context));
1035 replacement_6.Apply(context.get(), &transformation_context);
1036 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1037 kConsoleMessageConsumer));
1038
1039 // Replace %33 with %103[0] in '%86 = OpCopyObject %30 %33'
1040 auto instruction_descriptor_7 =
1041 MakeInstructionDescriptor(86, spv::Op::OpCopyObject, 0);
1042 auto extract_7 =
1043 TransformationCompositeExtract(instruction_descriptor_7, 206, 103, {0});
1044 ASSERT_TRUE(extract_7.IsApplicable(context.get(), transformation_context));
1045 extract_7.Apply(context.get(), &transformation_context);
1046 auto replacement_7 = TransformationReplaceIdWithSynonym(
1047 MakeIdUseDescriptor(33, instruction_descriptor_7, 0), 206);
1048 ASSERT_TRUE(
1049 replacement_7.IsApplicable(context.get(), transformation_context));
1050 replacement_7.Apply(context.get(), &transformation_context);
1051 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1052 kConsoleMessageConsumer));
1053
1054 // Replace %47 with %103[1:3] in '%84 = OpCopyObject %39 %47'
1055 auto instruction_descriptor_8 =
1056 MakeInstructionDescriptor(84, spv::Op::OpCopyObject, 0);
1057 auto shuffle_8 = TransformationVectorShuffle(instruction_descriptor_8, 207,
1058 103, 103, {1, 2, 3});
1059 ASSERT_TRUE(shuffle_8.IsApplicable(context.get(), transformation_context));
1060 shuffle_8.Apply(context.get(), &transformation_context);
1061 transformation_context.GetFactManager()->ComputeClosureOfFacts(100);
1062
1063 auto replacement_8 = TransformationReplaceIdWithSynonym(
1064 MakeIdUseDescriptor(47, instruction_descriptor_8, 0), 207);
1065 ASSERT_TRUE(
1066 replacement_8.IsApplicable(context.get(), transformation_context));
1067 replacement_8.Apply(context.get(), &transformation_context);
1068 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1069 kConsoleMessageConsumer));
1070
1071 // Replace %42 with %104[0] in '%85 = OpCopyObject %30 %42'
1072 auto instruction_descriptor_9 =
1073 MakeInstructionDescriptor(85, spv::Op::OpCopyObject, 0);
1074 auto extract_9 =
1075 TransformationCompositeExtract(instruction_descriptor_9, 208, 104, {0});
1076 ASSERT_TRUE(extract_9.IsApplicable(context.get(), transformation_context));
1077 extract_9.Apply(context.get(), &transformation_context);
1078 auto replacement_9 = TransformationReplaceIdWithSynonym(
1079 MakeIdUseDescriptor(42, instruction_descriptor_9, 0), 208);
1080 ASSERT_TRUE(
1081 replacement_9.IsApplicable(context.get(), transformation_context));
1082 replacement_9.Apply(context.get(), &transformation_context);
1083 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1084 kConsoleMessageConsumer));
1085
1086 // Replace %45 with %104[1] in '%63 = OpLogicalOr %30 %45 %46'
1087 auto instruction_descriptor_10 =
1088 MakeInstructionDescriptor(63, spv::Op::OpLogicalOr, 0);
1089 auto extract_10 =
1090 TransformationCompositeExtract(instruction_descriptor_10, 209, 104, {1});
1091 ASSERT_TRUE(extract_10.IsApplicable(context.get(), transformation_context));
1092 extract_10.Apply(context.get(), &transformation_context);
1093 auto replacement_10 = TransformationReplaceIdWithSynonym(
1094 MakeIdUseDescriptor(45, instruction_descriptor_10, 0), 209);
1095 ASSERT_TRUE(
1096 replacement_10.IsApplicable(context.get(), transformation_context));
1097 replacement_10.Apply(context.get(), &transformation_context);
1098 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1099 kConsoleMessageConsumer));
1100
1101 // Replace %38 with %105[0:1] in 'OpStore %36 %38'
1102 auto instruction_descriptor_11 =
1103 MakeInstructionDescriptor(85, spv::Op::OpStore, 0);
1104 auto shuffle_11 = TransformationVectorShuffle(instruction_descriptor_11, 210,
1105 105, 105, {0, 1});
1106 ASSERT_TRUE(shuffle_11.IsApplicable(context.get(), transformation_context));
1107 shuffle_11.Apply(context.get(), &transformation_context);
1108 transformation_context.GetFactManager()->ComputeClosureOfFacts(100);
1109
1110 auto replacement_11 = TransformationReplaceIdWithSynonym(
1111 MakeIdUseDescriptor(38, instruction_descriptor_11, 1), 210);
1112 ASSERT_TRUE(
1113 replacement_11.IsApplicable(context.get(), transformation_context));
1114 replacement_11.Apply(context.get(), &transformation_context);
1115 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1116 kConsoleMessageConsumer));
1117
1118 // Replace %46 with %105[2] in '%62 = OpLogicalAnd %30 %45 %46'
1119 auto instruction_descriptor_12 =
1120 MakeInstructionDescriptor(62, spv::Op::OpLogicalAnd, 0);
1121 auto extract_12 =
1122 TransformationCompositeExtract(instruction_descriptor_12, 211, 105, {2});
1123 ASSERT_TRUE(extract_12.IsApplicable(context.get(), transformation_context));
1124 extract_12.Apply(context.get(), &transformation_context);
1125 auto replacement_12 = TransformationReplaceIdWithSynonym(
1126 MakeIdUseDescriptor(46, instruction_descriptor_12, 1), 211);
1127 ASSERT_TRUE(
1128 replacement_12.IsApplicable(context.get(), transformation_context));
1129 replacement_12.Apply(context.get(), &transformation_context);
1130 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1131 kConsoleMessageConsumer));
1132
1133 const std::string after_transformation = R"(
1134 OpCapability Shader
1135 %1 = OpExtInstImport "GLSL.std.450"
1136 OpMemoryModel Logical GLSL450
1137 OpEntryPoint Fragment %4 "main"
1138 OpExecutionMode %4 OriginUpperLeft
1139 OpSource ESSL 310
1140 OpName %4 "main"
1141 OpName %8 "f"
1142 OpName %12 "v2"
1143 OpName %18 "v3"
1144 OpName %23 "v4"
1145 OpName %32 "b"
1146 OpName %36 "bv2"
1147 OpName %41 "bv3"
1148 OpName %50 "bv4"
1149 %2 = OpTypeVoid
1150 %3 = OpTypeFunction %2
1151 %6 = OpTypeFloat 32
1152 %7 = OpTypePointer Function %6
1153 %9 = OpConstant %6 42
1154 %10 = OpTypeVector %6 2
1155 %11 = OpTypePointer Function %10
1156 %16 = OpTypeVector %6 3
1157 %17 = OpTypePointer Function %16
1158 %21 = OpTypeVector %6 4
1159 %22 = OpTypePointer Function %21
1160 %30 = OpTypeBool
1161 %31 = OpTypePointer Function %30
1162 %33 = OpConstantFalse %30
1163 %34 = OpTypeVector %30 2
1164 %35 = OpTypePointer Function %34
1165 %37 = OpConstantTrue %30
1166 %38 = OpConstantComposite %34 %37 %37
1167 %39 = OpTypeVector %30 3
1168 %40 = OpTypePointer Function %39
1169 %48 = OpTypeVector %30 4
1170 %49 = OpTypePointer Function %48
1171 %51 = OpTypeInt 32 0
1172 %52 = OpConstant %51 2
1173 %55 = OpConstant %6 0
1174 %57 = OpConstant %51 1
1175 %4 = OpFunction %2 None %3
1176 %5 = OpLabel
1177 %8 = OpVariable %7 Function
1178 %12 = OpVariable %11 Function
1179 %18 = OpVariable %17 Function
1180 %23 = OpVariable %22 Function
1181 %32 = OpVariable %31 Function
1182 %36 = OpVariable %35 Function
1183 %41 = OpVariable %40 Function
1184 %50 = OpVariable %49 Function
1185 OpStore %8 %9
1186 %13 = OpLoad %6 %8
1187 %14 = OpLoad %6 %8
1188 %15 = OpCompositeConstruct %10 %13 %14
1189 OpStore %12 %15
1190 %19 = OpLoad %10 %12
1191 %20 = OpVectorShuffle %16 %19 %19 0 0 1
1192 OpStore %18 %20
1193 %24 = OpLoad %16 %18
1194 %25 = OpLoad %6 %8
1195 %26 = OpCompositeExtract %6 %24 0
1196 %27 = OpCompositeExtract %6 %24 1
1197 %28 = OpCompositeExtract %6 %24 2
1198 %29 = OpCompositeConstruct %21 %26 %27 %28 %25
1199 OpStore %23 %29
1200 OpStore %32 %33
1201 OpStore %36 %38
1202 %42 = OpLoad %30 %32
1203 %43 = OpLoad %34 %36
1204 %44 = OpVectorShuffle %34 %43 %43 0 0
1205 %45 = OpCompositeExtract %30 %44 0
1206 %46 = OpCompositeExtract %30 %44 1
1207 %47 = OpCompositeConstruct %39 %42 %45 %46
1208 OpStore %41 %47
1209 %53 = OpAccessChain %7 %23 %52
1210 %54 = OpLoad %6 %53
1211
1212 %100 = OpCompositeConstruct %21 %20 %54
1213 %101 = OpCompositeConstruct %21 %15 %19
1214 %102 = OpCompositeConstruct %16 %27 %15
1215 %103 = OpCompositeConstruct %48 %33 %47
1216 %104 = OpCompositeConstruct %34 %42 %45
1217 %105 = OpCompositeConstruct %39 %38 %46
1218
1219 %206 = OpCompositeExtract %30 %103 0
1220 %86 = OpCopyObject %30 %206
1221 %201 = OpCompositeExtract %6 %100 3
1222 %56 = OpFOrdNotEqual %30 %201 %55
1223 %200 = OpVectorShuffle %16 %100 %100 0 1 2
1224 %80 = OpCopyObject %16 %200
1225 %58 = OpAccessChain %7 %18 %57
1226 %59 = OpLoad %6 %58
1227 %60 = OpFOrdNotEqual %30 %59 %55
1228 %61 = OpLoad %34 %36
1229 %211 = OpCompositeExtract %30 %105 2
1230 %62 = OpLogicalAnd %30 %45 %211
1231 %209 = OpCompositeExtract %30 %104 1
1232 %63 = OpLogicalOr %30 %209 %46
1233 %64 = OpCompositeConstruct %48 %56 %60 %62 %63
1234 %202 = OpVectorShuffle %10 %101 %101 0 1
1235 OpStore %12 %202
1236 %203 = OpVectorShuffle %10 %101 %101 2 3
1237 %81 = OpVectorShuffle %16 %203 %19 0 0 1
1238 %204 = OpCompositeExtract %6 %102 0
1239 %82 = OpCompositeConstruct %21 %26 %204 %28 %25
1240 %205 = OpVectorShuffle %10 %102 %102 1 2
1241 %83 = OpCopyObject %10 %205
1242 %207 = OpVectorShuffle %39 %103 %103 1 2 3
1243 %84 = OpCopyObject %39 %207
1244 OpStore %50 %64
1245 %208 = OpCompositeExtract %30 %104 0
1246 %85 = OpCopyObject %30 %208
1247 %210 = OpVectorShuffle %34 %105 %105 0 1
1248 OpStore %36 %210
1249 OpReturn
1250 OpFunctionEnd
1251 )";
1252
1253 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
1254 }
1255
1256 } // namespace
1257 } // namespace fuzz
1258 } // namespace spvtools
1259