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