1 // Copyright (c) 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "source/fuzz/transformation_vector_shuffle.h"
16
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "source/fuzz/instruction_descriptor.h"
20 #include "test/fuzz/fuzz_test_util.h"
21
22 namespace spvtools {
23 namespace fuzz {
24 namespace {
25
TEST(TransformationVectorShuffleTest,BasicTest)26 TEST(TransformationVectorShuffleTest, BasicTest) {
27 std::string shader = R"(
28 OpCapability Shader
29 %1 = OpExtInstImport "GLSL.std.450"
30 OpMemoryModel Logical GLSL450
31 OpEntryPoint Fragment %4 "main"
32 OpExecutionMode %4 OriginUpperLeft
33 OpSource ESSL 310
34 %2 = OpTypeVoid
35 %3 = OpTypeFunction %2
36 %6 = OpTypeBool
37 %7 = OpTypeVector %6 2
38 %10 = OpConstantTrue %6
39 %11 = OpConstantFalse %6
40 %12 = OpConstantComposite %7 %10 %11
41 %112 = OpUndef %7
42 %13 = OpTypeVector %6 3
43 %16 = OpConstantComposite %13 %10 %11 %10
44 %17 = OpTypeVector %6 4
45 %20 = OpConstantComposite %17 %10 %11 %10 %11
46 %21 = OpTypeInt 32 1
47 %22 = OpTypeVector %21 2
48 %25 = OpConstant %21 1
49 %26 = OpConstant %21 0
50 %27 = OpConstantComposite %22 %25 %26
51 %28 = OpTypeVector %21 3
52 %31 = OpConstantComposite %28 %25 %26 %25
53 %32 = OpTypeVector %21 4
54 %33 = OpTypePointer Function %32
55 %35 = OpConstantComposite %32 %25 %26 %25 %26
56 %36 = OpTypeInt 32 0
57 %37 = OpTypeVector %36 2
58 %40 = OpConstant %36 1
59 %41 = OpConstant %36 0
60 %42 = OpConstantComposite %37 %40 %41
61 %43 = OpTypeVector %36 3
62 %46 = OpConstantComposite %43 %40 %41 %40
63 %47 = OpTypeVector %36 4
64 %50 = OpConstantComposite %47 %40 %41 %40 %41
65 %51 = OpTypeFloat 32
66 %55 = OpConstant %51 1
67 %56 = OpConstant %51 0
68 %58 = OpTypeVector %51 3
69 %61 = OpConstantComposite %58 %55 %56 %55
70 %62 = OpTypeVector %51 4
71 %65 = OpConstantComposite %62 %55 %56 %55 %56
72 %4 = OpFunction %2 None %3
73 %5 = OpLabel
74 OpSelectionMerge %100 None
75 OpBranchConditional %10 %101 %102
76 %101 = OpLabel
77 %103 = OpCompositeConstruct %62 %55 %55 %55 %56
78 OpBranch %100
79 %102 = OpLabel
80 OpBranch %100
81 %100 = OpLabel
82 OpReturn
83 OpFunctionEnd
84 )";
85
86 const auto env = SPV_ENV_UNIVERSAL_1_4;
87 const auto consumer = nullptr;
88 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
89 spvtools::ValidatorOptions validator_options;
90 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
91 kConsoleMessageConsumer));
92 TransformationContext transformation_context(
93 MakeUnique<FactManager>(context.get()), validator_options);
94 transformation_context.GetFactManager()->AddFactDataSynonym(
95 MakeDataDescriptor(10, {}), MakeDataDescriptor(12, {0}));
96 transformation_context.GetFactManager()->AddFactDataSynonym(
97 MakeDataDescriptor(11, {}), MakeDataDescriptor(12, {1}));
98
99 transformation_context.GetFactManager()->AddFactDataSynonym(
100 MakeDataDescriptor(10, {}), MakeDataDescriptor(16, {0}));
101 transformation_context.GetFactManager()->AddFactDataSynonym(
102 MakeDataDescriptor(11, {}), MakeDataDescriptor(16, {1}));
103 transformation_context.GetFactManager()->AddFactDataSynonym(
104 MakeDataDescriptor(10, {}), MakeDataDescriptor(16, {2}));
105
106 transformation_context.GetFactManager()->AddFactDataSynonym(
107 MakeDataDescriptor(10, {}), MakeDataDescriptor(20, {0}));
108 transformation_context.GetFactManager()->AddFactDataSynonym(
109 MakeDataDescriptor(11, {}), MakeDataDescriptor(20, {1}));
110 transformation_context.GetFactManager()->AddFactDataSynonym(
111 MakeDataDescriptor(10, {}), MakeDataDescriptor(20, {2}));
112 transformation_context.GetFactManager()->AddFactDataSynonym(
113 MakeDataDescriptor(11, {}), MakeDataDescriptor(20, {3}));
114
115 transformation_context.GetFactManager()->AddFactDataSynonym(
116 MakeDataDescriptor(25, {}), MakeDataDescriptor(27, {0}));
117 transformation_context.GetFactManager()->AddFactDataSynonym(
118 MakeDataDescriptor(26, {}), MakeDataDescriptor(27, {1}));
119
120 transformation_context.GetFactManager()->AddFactDataSynonym(
121 MakeDataDescriptor(25, {}), MakeDataDescriptor(31, {0}));
122 transformation_context.GetFactManager()->AddFactDataSynonym(
123 MakeDataDescriptor(26, {}), MakeDataDescriptor(31, {1}));
124 transformation_context.GetFactManager()->AddFactDataSynonym(
125 MakeDataDescriptor(25, {}), MakeDataDescriptor(31, {2}));
126
127 transformation_context.GetFactManager()->AddFactDataSynonym(
128 MakeDataDescriptor(25, {}), MakeDataDescriptor(35, {0}));
129 transformation_context.GetFactManager()->AddFactDataSynonym(
130 MakeDataDescriptor(26, {}), MakeDataDescriptor(35, {1}));
131 transformation_context.GetFactManager()->AddFactDataSynonym(
132 MakeDataDescriptor(25, {}), MakeDataDescriptor(35, {2}));
133 transformation_context.GetFactManager()->AddFactDataSynonym(
134 MakeDataDescriptor(26, {}), MakeDataDescriptor(35, {3}));
135
136 transformation_context.GetFactManager()->AddFactDataSynonym(
137 MakeDataDescriptor(40, {}), MakeDataDescriptor(42, {0}));
138 transformation_context.GetFactManager()->AddFactDataSynonym(
139 MakeDataDescriptor(41, {}), MakeDataDescriptor(42, {1}));
140
141 transformation_context.GetFactManager()->AddFactDataSynonym(
142 MakeDataDescriptor(40, {}), MakeDataDescriptor(46, {0}));
143 transformation_context.GetFactManager()->AddFactDataSynonym(
144 MakeDataDescriptor(41, {}), MakeDataDescriptor(46, {1}));
145 transformation_context.GetFactManager()->AddFactDataSynonym(
146 MakeDataDescriptor(40, {}), MakeDataDescriptor(46, {2}));
147
148 transformation_context.GetFactManager()->AddFactDataSynonym(
149 MakeDataDescriptor(40, {}), MakeDataDescriptor(50, {0}));
150 transformation_context.GetFactManager()->AddFactDataSynonym(
151 MakeDataDescriptor(41, {}), MakeDataDescriptor(50, {1}));
152 transformation_context.GetFactManager()->AddFactDataSynonym(
153 MakeDataDescriptor(40, {}), MakeDataDescriptor(50, {2}));
154 transformation_context.GetFactManager()->AddFactDataSynonym(
155 MakeDataDescriptor(41, {}), MakeDataDescriptor(50, {3}));
156
157 transformation_context.GetFactManager()->AddFactDataSynonym(
158 MakeDataDescriptor(55, {}), MakeDataDescriptor(61, {0}));
159 transformation_context.GetFactManager()->AddFactDataSynonym(
160 MakeDataDescriptor(56, {}), MakeDataDescriptor(61, {1}));
161 transformation_context.GetFactManager()->AddFactDataSynonym(
162 MakeDataDescriptor(55, {}), MakeDataDescriptor(61, {2}));
163
164 transformation_context.GetFactManager()->AddFactDataSynonym(
165 MakeDataDescriptor(55, {}), MakeDataDescriptor(65, {0}));
166 transformation_context.GetFactManager()->AddFactDataSynonym(
167 MakeDataDescriptor(56, {}), MakeDataDescriptor(65, {1}));
168 transformation_context.GetFactManager()->AddFactDataSynonym(
169 MakeDataDescriptor(55, {}), MakeDataDescriptor(65, {2}));
170 transformation_context.GetFactManager()->AddFactDataSynonym(
171 MakeDataDescriptor(56, {}), MakeDataDescriptor(65, {3}));
172
173 // %103 does not dominate the return instruction.
174 ASSERT_FALSE(TransformationVectorShuffle(
175 MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 103, 65,
176 {3, 5, 7})
177 .IsApplicable(context.get(), transformation_context));
178
179 // Illegal to shuffle a bvec2 and a vec3
180 ASSERT_FALSE(TransformationVectorShuffle(
181 MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 112, 61,
182 {0, 2, 4})
183 .IsApplicable(context.get(), transformation_context));
184
185 // Illegal to shuffle an ivec2 and a uvec4
186 ASSERT_FALSE(TransformationVectorShuffle(
187 MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 27, 50,
188 {1, 3, 5})
189 .IsApplicable(context.get(), transformation_context));
190
191 // Vector 1 does not exist
192 ASSERT_FALSE(TransformationVectorShuffle(
193 MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 300, 50,
194 {1, 3, 5})
195 .IsApplicable(context.get(), transformation_context));
196
197 // Vector 2 does not exist
198 ASSERT_FALSE(TransformationVectorShuffle(
199 MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 27, 300,
200 {1, 3, 5})
201 .IsApplicable(context.get(), transformation_context));
202
203 // Index out of range
204 ASSERT_FALSE(
205 TransformationVectorShuffle(
206 MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {0, 20})
207 .IsApplicable(context.get(), transformation_context));
208
209 // Too many indices
210 ASSERT_FALSE(TransformationVectorShuffle(
211 MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112,
212 {0, 1, 0, 1, 0, 1, 0, 1})
213 .IsApplicable(context.get(), transformation_context));
214
215 // Too few indices
216 ASSERT_FALSE(
217 TransformationVectorShuffle(
218 MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {})
219 .IsApplicable(context.get(), transformation_context));
220
221 // Too few indices again
222 ASSERT_FALSE(
223 TransformationVectorShuffle(
224 MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {0})
225 .IsApplicable(context.get(), transformation_context));
226
227 // Indices define unknown type: we do not have vec2
228 ASSERT_FALSE(
229 TransformationVectorShuffle(
230 MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 65, 65, {0, 1})
231 .IsApplicable(context.get(), transformation_context));
232
233 // The instruction to insert before does not exist
234 ASSERT_FALSE(TransformationVectorShuffle(
235 MakeInstructionDescriptor(100, SpvOpCompositeConstruct, 1),
236 201, 20, 12, {0xFFFFFFFF, 3, 5})
237 .IsApplicable(context.get(), transformation_context));
238
239 // The 'fresh' id is already in use
240 ASSERT_FALSE(
241 TransformationVectorShuffle(
242 MakeInstructionDescriptor(100, SpvOpReturn, 0), 12, 12, 112, {})
243 .IsApplicable(context.get(), transformation_context));
244
245 protobufs::DataDescriptor temp_dd;
246
247 TransformationVectorShuffle transformation1(
248 MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {1, 0});
249 ASSERT_TRUE(
250 transformation1.IsApplicable(context.get(), transformation_context));
251 ApplyAndCheckFreshIds(transformation1, context.get(),
252 &transformation_context);
253 temp_dd = MakeDataDescriptor(200, {0});
254 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
255 MakeDataDescriptor(11, {}), temp_dd));
256 temp_dd = MakeDataDescriptor(200, {1});
257 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
258 MakeDataDescriptor(10, {}), temp_dd));
259
260 TransformationVectorShuffle transformation2(
261 MakeInstructionDescriptor(100, SpvOpReturn, 0), 201, 20, 12,
262 {0xFFFFFFFF, 3, 5});
263 ASSERT_TRUE(
264 transformation2.IsApplicable(context.get(), transformation_context));
265 ApplyAndCheckFreshIds(transformation2, context.get(),
266 &transformation_context);
267 temp_dd = MakeDataDescriptor(201, {1});
268 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
269 MakeDataDescriptor(11, {}), temp_dd));
270 temp_dd = MakeDataDescriptor(201, {2});
271 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
272 MakeDataDescriptor(11, {}), temp_dd));
273
274 TransformationVectorShuffle transformation3(
275 MakeInstructionDescriptor(100, SpvOpReturn, 0), 202, 27, 35, {5, 4, 1});
276 ASSERT_TRUE(
277 transformation3.IsApplicable(context.get(), transformation_context));
278 ApplyAndCheckFreshIds(transformation3, context.get(),
279 &transformation_context);
280 temp_dd = MakeDataDescriptor(202, {0});
281 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
282 MakeDataDescriptor(26, {}), temp_dd));
283 temp_dd = MakeDataDescriptor(202, {1});
284 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
285 MakeDataDescriptor(25, {}), temp_dd));
286 temp_dd = MakeDataDescriptor(202, {2});
287 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
288 MakeDataDescriptor(26, {}), temp_dd));
289
290 TransformationVectorShuffle transformation4(
291 MakeInstructionDescriptor(100, SpvOpReturn, 0), 203, 42, 46, {0, 1});
292 ASSERT_TRUE(
293 transformation4.IsApplicable(context.get(), transformation_context));
294 ApplyAndCheckFreshIds(transformation4, context.get(),
295 &transformation_context);
296 temp_dd = MakeDataDescriptor(203, {0});
297 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
298 MakeDataDescriptor(40, {}), temp_dd));
299 temp_dd = MakeDataDescriptor(203, {1});
300 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
301 MakeDataDescriptor(41, {}), temp_dd));
302
303 TransformationVectorShuffle transformation5(
304 MakeInstructionDescriptor(100, SpvOpReturn, 0), 204, 42, 46, {2, 3, 4});
305 ASSERT_TRUE(
306 transformation5.IsApplicable(context.get(), transformation_context));
307 ApplyAndCheckFreshIds(transformation5, context.get(),
308 &transformation_context);
309 temp_dd = MakeDataDescriptor(204, {0});
310 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
311 MakeDataDescriptor(40, {}), temp_dd));
312 temp_dd = MakeDataDescriptor(204, {1});
313 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
314 MakeDataDescriptor(41, {}), temp_dd));
315 temp_dd = MakeDataDescriptor(204, {2});
316 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
317 MakeDataDescriptor(40, {}), temp_dd));
318
319 TransformationVectorShuffle transformation6(
320 MakeInstructionDescriptor(100, SpvOpReturn, 0), 205, 42, 42,
321 {0, 1, 2, 3});
322 ASSERT_TRUE(
323 transformation6.IsApplicable(context.get(), transformation_context));
324 ApplyAndCheckFreshIds(transformation6, context.get(),
325 &transformation_context);
326 temp_dd = MakeDataDescriptor(205, {0});
327 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
328 MakeDataDescriptor(40, {}), temp_dd));
329 temp_dd = MakeDataDescriptor(205, {1});
330 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
331 MakeDataDescriptor(41, {}), temp_dd));
332 temp_dd = MakeDataDescriptor(205, {2});
333 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
334 MakeDataDescriptor(40, {}), temp_dd));
335 temp_dd = MakeDataDescriptor(205, {3});
336 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
337 MakeDataDescriptor(41, {}), temp_dd));
338
339 // swizzle vec4 from vec4 and vec4 using some undefs
340 TransformationVectorShuffle transformation7(
341 MakeInstructionDescriptor(100, SpvOpReturn, 0), 206, 65, 65,
342 {0xFFFFFFFF, 3, 6, 0xFFFFFFFF});
343 ASSERT_TRUE(
344 transformation7.IsApplicable(context.get(), transformation_context));
345 ApplyAndCheckFreshIds(transformation7, context.get(),
346 &transformation_context);
347 temp_dd = MakeDataDescriptor(206, {1});
348 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
349 MakeDataDescriptor(56, {}), temp_dd));
350
351 std::string after_transformation = R"(
352 OpCapability Shader
353 %1 = OpExtInstImport "GLSL.std.450"
354 OpMemoryModel Logical GLSL450
355 OpEntryPoint Fragment %4 "main"
356 OpExecutionMode %4 OriginUpperLeft
357 OpSource ESSL 310
358 %2 = OpTypeVoid
359 %3 = OpTypeFunction %2
360 %6 = OpTypeBool
361 %7 = OpTypeVector %6 2
362 %10 = OpConstantTrue %6
363 %11 = OpConstantFalse %6
364 %12 = OpConstantComposite %7 %10 %11
365 %112 = OpUndef %7
366 %13 = OpTypeVector %6 3
367 %16 = OpConstantComposite %13 %10 %11 %10
368 %17 = OpTypeVector %6 4
369 %20 = OpConstantComposite %17 %10 %11 %10 %11
370 %21 = OpTypeInt 32 1
371 %22 = OpTypeVector %21 2
372 %25 = OpConstant %21 1
373 %26 = OpConstant %21 0
374 %27 = OpConstantComposite %22 %25 %26
375 %28 = OpTypeVector %21 3
376 %31 = OpConstantComposite %28 %25 %26 %25
377 %32 = OpTypeVector %21 4
378 %33 = OpTypePointer Function %32
379 %35 = OpConstantComposite %32 %25 %26 %25 %26
380 %36 = OpTypeInt 32 0
381 %37 = OpTypeVector %36 2
382 %40 = OpConstant %36 1
383 %41 = OpConstant %36 0
384 %42 = OpConstantComposite %37 %40 %41
385 %43 = OpTypeVector %36 3
386 %46 = OpConstantComposite %43 %40 %41 %40
387 %47 = OpTypeVector %36 4
388 %50 = OpConstantComposite %47 %40 %41 %40 %41
389 %51 = OpTypeFloat 32
390 %55 = OpConstant %51 1
391 %56 = OpConstant %51 0
392 %58 = OpTypeVector %51 3
393 %61 = OpConstantComposite %58 %55 %56 %55
394 %62 = OpTypeVector %51 4
395 %65 = OpConstantComposite %62 %55 %56 %55 %56
396 %4 = OpFunction %2 None %3
397 %5 = OpLabel
398 OpSelectionMerge %100 None
399 OpBranchConditional %10 %101 %102
400 %101 = OpLabel
401 %103 = OpCompositeConstruct %62 %55 %55 %55 %56
402 OpBranch %100
403 %102 = OpLabel
404 OpBranch %100
405 %100 = OpLabel
406 %200 = OpVectorShuffle %7 %12 %112 1 0
407 %201 = OpVectorShuffle %13 %20 %12 0xFFFFFFFF 3 5
408 %202 = OpVectorShuffle %28 %27 %35 5 4 1
409 %203 = OpVectorShuffle %37 %42 %46 0 1
410 %204 = OpVectorShuffle %43 %42 %46 2 3 4
411 %205 = OpVectorShuffle %47 %42 %42 0 1 2 3
412 %206 = OpVectorShuffle %62 %65 %65 0xFFFFFFFF 3 6 0xFFFFFFFF
413 OpReturn
414 OpFunctionEnd
415 )";
416 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
417 }
418
TEST(TransformationVectorShuffleTest,IllegalInsertionPoints)419 TEST(TransformationVectorShuffleTest, IllegalInsertionPoints) {
420 std::string shader = R"(
421 OpCapability Shader
422 %1 = OpExtInstImport "GLSL.std.450"
423 OpMemoryModel Logical GLSL450
424 OpEntryPoint Fragment %4 "main" %51 %27
425 OpExecutionMode %4 OriginUpperLeft
426 OpSource ESSL 310
427 OpName %4 "main"
428 OpName %25 "buf"
429 OpMemberName %25 0 "value"
430 OpName %27 ""
431 OpName %51 "color"
432 OpMemberDecorate %25 0 Offset 0
433 OpDecorate %25 Block
434 OpDecorate %27 DescriptorSet 0
435 OpDecorate %27 Binding 0
436 OpDecorate %51 Location 0
437 %2 = OpTypeVoid
438 %3 = OpTypeFunction %2
439 %6 = OpTypeFloat 32
440 %7 = OpTypeVector %6 4
441 %150 = OpTypeVector %6 2
442 %10 = OpConstant %6 0.300000012
443 %11 = OpConstant %6 0.400000006
444 %12 = OpConstant %6 0.5
445 %13 = OpConstant %6 1
446 %14 = OpConstantComposite %7 %10 %11 %12 %13
447 %15 = OpTypeInt 32 1
448 %18 = OpConstant %15 0
449 %25 = OpTypeStruct %6
450 %26 = OpTypePointer Uniform %25
451 %27 = OpVariable %26 Uniform
452 %28 = OpTypePointer Uniform %6
453 %32 = OpTypeBool
454 %103 = OpConstantTrue %32
455 %34 = OpConstant %6 0.100000001
456 %48 = OpConstant %15 1
457 %50 = OpTypePointer Output %7
458 %51 = OpVariable %50 Output
459 %100 = OpTypePointer Function %6
460 %4 = OpFunction %2 None %3
461 %5 = OpLabel
462 %101 = OpVariable %100 Function
463 %102 = OpVariable %100 Function
464 OpBranch %19
465 %19 = OpLabel
466 %60 = OpPhi %7 %14 %5 %58 %20
467 %59 = OpPhi %15 %18 %5 %49 %20
468 %29 = OpAccessChain %28 %27 %18
469 %30 = OpLoad %6 %29
470 %31 = OpConvertFToS %15 %30
471 %33 = OpSLessThan %32 %59 %31
472 OpLoopMerge %21 %20 None
473 OpBranchConditional %33 %20 %21
474 %20 = OpLabel
475 %39 = OpCompositeExtract %6 %60 0
476 %40 = OpFAdd %6 %39 %34
477 %55 = OpCompositeInsert %7 %40 %60 0
478 %44 = OpCompositeExtract %6 %60 1
479 %45 = OpFSub %6 %44 %34
480 %58 = OpCompositeInsert %7 %45 %55 1
481 %49 = OpIAdd %15 %59 %48
482 OpBranch %19
483 %21 = OpLabel
484 OpStore %51 %60
485 OpSelectionMerge %105 None
486 OpBranchConditional %103 %104 %105
487 %104 = OpLabel
488 OpBranch %105
489 %105 = OpLabel
490 OpReturn
491 OpFunctionEnd
492 )";
493
494 const auto env = SPV_ENV_UNIVERSAL_1_4;
495 const auto consumer = nullptr;
496 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
497 spvtools::ValidatorOptions validator_options;
498 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
499 kConsoleMessageConsumer));
500 TransformationContext transformation_context(
501 MakeUnique<FactManager>(context.get()), validator_options);
502 // Cannot insert before the OpVariables of a function.
503 ASSERT_FALSE(
504 TransformationVectorShuffle(
505 MakeInstructionDescriptor(101, SpvOpVariable, 0), 200, 14, 14, {0, 1})
506 .IsApplicable(context.get(), transformation_context));
507 ASSERT_FALSE(
508 TransformationVectorShuffle(
509 MakeInstructionDescriptor(101, SpvOpVariable, 1), 200, 14, 14, {1, 2})
510 .IsApplicable(context.get(), transformation_context));
511 ASSERT_FALSE(
512 TransformationVectorShuffle(
513 MakeInstructionDescriptor(102, SpvOpVariable, 0), 200, 14, 14, {1, 2})
514 .IsApplicable(context.get(), transformation_context));
515 // OK to insert right after the OpVariables.
516 ASSERT_FALSE(
517 TransformationVectorShuffle(
518 MakeInstructionDescriptor(102, SpvOpBranch, 1), 200, 14, 14, {1, 1})
519 .IsApplicable(context.get(), transformation_context));
520
521 // Cannot insert before the OpPhis of a block.
522 ASSERT_FALSE(
523 TransformationVectorShuffle(MakeInstructionDescriptor(60, SpvOpPhi, 0),
524 200, 14, 14, {2, 0})
525 .IsApplicable(context.get(), transformation_context));
526 ASSERT_FALSE(
527 TransformationVectorShuffle(MakeInstructionDescriptor(59, SpvOpPhi, 0),
528 200, 14, 14, {3, 0})
529 .IsApplicable(context.get(), transformation_context));
530 // OK to insert after the OpPhis.
531 ASSERT_TRUE(TransformationVectorShuffle(
532 MakeInstructionDescriptor(59, SpvOpAccessChain, 0), 200, 14,
533 14, {3, 4})
534 .IsApplicable(context.get(), transformation_context));
535
536 // Cannot insert before OpLoopMerge
537 ASSERT_FALSE(TransformationVectorShuffle(
538 MakeInstructionDescriptor(33, SpvOpBranchConditional, 0),
539 200, 14, 14, {3})
540 .IsApplicable(context.get(), transformation_context));
541
542 // Cannot insert before OpSelectionMerge
543 ASSERT_FALSE(TransformationVectorShuffle(
544 MakeInstructionDescriptor(21, SpvOpBranchConditional, 0),
545 200, 14, 14, {2})
546 .IsApplicable(context.get(), transformation_context));
547 }
548
TEST(TransformationVectorShuffleTest,HandlesIrrelevantIds1)549 TEST(TransformationVectorShuffleTest, HandlesIrrelevantIds1) {
550 std::string shader = R"(
551 OpCapability Shader
552 %1 = OpExtInstImport "GLSL.std.450"
553 OpMemoryModel Logical GLSL450
554 OpEntryPoint Fragment %4 "main"
555 OpExecutionMode %4 OriginUpperLeft
556 OpSource ESSL 310
557 %2 = OpTypeVoid
558 %3 = OpTypeFunction %2
559 %6 = OpTypeBool
560 %7 = OpTypeVector %6 2
561 %10 = OpConstantTrue %6
562 %11 = OpConstantFalse %6
563 %12 = OpConstantComposite %7 %10 %11
564 %112 = OpConstantComposite %7 %11 %10
565 %13 = OpTypeVector %6 3
566 %16 = OpConstantComposite %13 %10 %11 %10
567 %17 = OpTypeVector %6 4
568 %20 = OpConstantComposite %17 %10 %11 %10 %11
569 %21 = OpTypeInt 32 1
570 %22 = OpTypeVector %21 2
571 %25 = OpConstant %21 1
572 %26 = OpConstant %21 0
573 %27 = OpConstantComposite %22 %25 %26
574 %28 = OpTypeVector %21 3
575 %31 = OpConstantComposite %28 %25 %26 %25
576 %32 = OpTypeVector %21 4
577 %33 = OpTypePointer Function %32
578 %35 = OpConstantComposite %32 %25 %26 %25 %26
579 %36 = OpTypeInt 32 0
580 %37 = OpTypeVector %36 2
581 %40 = OpConstant %36 1
582 %41 = OpConstant %36 0
583 %42 = OpConstantComposite %37 %40 %41
584 %43 = OpTypeVector %36 3
585 %46 = OpConstantComposite %43 %40 %41 %40
586 %47 = OpTypeVector %36 4
587 %50 = OpConstantComposite %47 %40 %41 %40 %41
588 %51 = OpTypeFloat 32
589 %55 = OpConstant %51 1
590 %56 = OpConstant %51 0
591 %58 = OpTypeVector %51 3
592 %61 = OpConstantComposite %58 %55 %56 %55
593 %62 = OpTypeVector %51 4
594 %65 = OpConstantComposite %62 %55 %56 %55 %56
595 %4 = OpFunction %2 None %3
596 %5 = OpLabel
597 OpSelectionMerge %100 None
598 OpBranchConditional %10 %101 %102
599 %101 = OpLabel
600 %103 = OpCompositeConstruct %62 %55 %55 %55 %56
601 OpBranch %100
602 %102 = OpLabel
603 OpBranch %100
604 %100 = OpLabel
605 OpReturn
606 OpFunctionEnd
607 )";
608
609 const auto env = SPV_ENV_UNIVERSAL_1_4;
610 const auto consumer = nullptr;
611 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
612 spvtools::ValidatorOptions validator_options;
613 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
614 kConsoleMessageConsumer));
615 TransformationContext transformation_context(
616 MakeUnique<FactManager>(context.get()), validator_options);
617 TransformationVectorShuffle transformation(
618 MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {2, 0});
619 ASSERT_TRUE(
620 transformation.IsApplicable(context.get(), transformation_context));
621 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
622 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
623 kConsoleMessageConsumer));
624 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
625 MakeDataDescriptor(12, {0}), MakeDataDescriptor(200, {1})));
626 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
627 MakeDataDescriptor(112, {0}), MakeDataDescriptor(200, {0})));
628 }
629
TEST(TransformationVectorShuffleTest,HandlesIrrelevantIds2)630 TEST(TransformationVectorShuffleTest, HandlesIrrelevantIds2) {
631 std::string shader = R"(
632 OpCapability Shader
633 %1 = OpExtInstImport "GLSL.std.450"
634 OpMemoryModel Logical GLSL450
635 OpEntryPoint Fragment %4 "main"
636 OpExecutionMode %4 OriginUpperLeft
637 OpSource ESSL 310
638 %2 = OpTypeVoid
639 %3 = OpTypeFunction %2
640 %6 = OpTypeBool
641 %7 = OpTypeVector %6 2
642 %10 = OpConstantTrue %6
643 %11 = OpConstantFalse %6
644 %12 = OpConstantComposite %7 %10 %11
645 %112 = OpConstantComposite %7 %11 %10
646 %13 = OpTypeVector %6 3
647 %16 = OpConstantComposite %13 %10 %11 %10
648 %17 = OpTypeVector %6 4
649 %20 = OpConstantComposite %17 %10 %11 %10 %11
650 %21 = OpTypeInt 32 1
651 %22 = OpTypeVector %21 2
652 %25 = OpConstant %21 1
653 %26 = OpConstant %21 0
654 %27 = OpConstantComposite %22 %25 %26
655 %28 = OpTypeVector %21 3
656 %31 = OpConstantComposite %28 %25 %26 %25
657 %32 = OpTypeVector %21 4
658 %33 = OpTypePointer Function %32
659 %35 = OpConstantComposite %32 %25 %26 %25 %26
660 %36 = OpTypeInt 32 0
661 %37 = OpTypeVector %36 2
662 %40 = OpConstant %36 1
663 %41 = OpConstant %36 0
664 %42 = OpConstantComposite %37 %40 %41
665 %43 = OpTypeVector %36 3
666 %46 = OpConstantComposite %43 %40 %41 %40
667 %47 = OpTypeVector %36 4
668 %50 = OpConstantComposite %47 %40 %41 %40 %41
669 %51 = OpTypeFloat 32
670 %55 = OpConstant %51 1
671 %56 = OpConstant %51 0
672 %58 = OpTypeVector %51 3
673 %61 = OpConstantComposite %58 %55 %56 %55
674 %62 = OpTypeVector %51 4
675 %65 = OpConstantComposite %62 %55 %56 %55 %56
676 %4 = OpFunction %2 None %3
677 %5 = OpLabel
678 OpSelectionMerge %100 None
679 OpBranchConditional %10 %101 %102
680 %101 = OpLabel
681 %103 = OpCompositeConstruct %62 %55 %55 %55 %56
682 OpBranch %100
683 %102 = OpLabel
684 OpBranch %100
685 %100 = OpLabel
686 OpReturn
687 OpFunctionEnd
688 )";
689
690 const auto env = SPV_ENV_UNIVERSAL_1_4;
691 const auto consumer = nullptr;
692 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
693 spvtools::ValidatorOptions validator_options;
694 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
695 kConsoleMessageConsumer));
696 TransformationContext transformation_context(
697 MakeUnique<FactManager>(context.get()), validator_options);
698 transformation_context.GetFactManager()->AddFactIdIsIrrelevant(112);
699 TransformationVectorShuffle transformation(
700 MakeInstructionDescriptor(100, SpvOpReturn, 0), 200, 12, 112, {2, 0});
701 ASSERT_TRUE(
702 transformation.IsApplicable(context.get(), transformation_context));
703 ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
704 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
705 kConsoleMessageConsumer));
706 // Because %12 is not irrelevant, we get a synonym between it and %200[1].
707 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
708 MakeDataDescriptor(12, {0}), MakeDataDescriptor(200, {1})));
709 // Because %112 is irrelevant, we do not get a synonym between it and %200[0].
710 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
711 MakeDataDescriptor(112, {0}), MakeDataDescriptor(200, {0})));
712 }
713
TEST(TransformationVectorShuffleTest,HandlesIrrelevantIds3)714 TEST(TransformationVectorShuffleTest, HandlesIrrelevantIds3) {
715 std::string shader = R"(
716 OpCapability Shader
717 %1 = OpExtInstImport "GLSL.std.450"
718 OpMemoryModel Logical GLSL450
719 OpEntryPoint Fragment %4 "main"
720 OpExecutionMode %4 OriginUpperLeft
721 OpSource ESSL 320
722 %2 = OpTypeVoid
723 %3 = OpTypeFunction %2
724 %6 = OpTypeInt 32 1
725 %7 = OpTypeVector %6 2
726 %8 = OpTypePointer Function %7
727 %10 = OpConstant %6 0
728 %11 = OpConstant %6 1
729 %12 = OpConstantComposite %7 %10 %11
730 %40 = OpConstantComposite %7 %10 %11
731 %13 = OpTypeBool
732 %14 = OpConstantFalse %13
733 %4 = OpFunction %2 None %3
734 %5 = OpLabel
735 %9 = OpVariable %8 Function
736 OpStore %9 %12
737 OpSelectionMerge %16 None
738 OpBranchConditional %14 %15 %16
739 %15 = OpLabel
740 OpBranch %16
741 %16 = OpLabel
742 OpReturn
743 OpFunctionEnd
744 )";
745
746 const auto env = SPV_ENV_UNIVERSAL_1_4;
747 const auto consumer = nullptr;
748 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
749 spvtools::ValidatorOptions validator_options;
750 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
751 kConsoleMessageConsumer));
752 TransformationContext transformation_context(
753 MakeUnique<FactManager>(context.get()), validator_options);
754 transformation_context.GetFactManager()->AddFactIdIsIrrelevant(40);
755 transformation_context.GetFactManager()->AddFactBlockIsDead(15);
756
757 TransformationVectorShuffle transformation1(
758 MakeInstructionDescriptor(15, SpvOpBranch, 0), 200, 12, 12, {0, 3});
759 ASSERT_TRUE(
760 transformation1.IsApplicable(context.get(), transformation_context));
761 ApplyAndCheckFreshIds(transformation1, context.get(),
762 &transformation_context);
763 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
764 MakeDataDescriptor(200, {0}), MakeDataDescriptor(12, {0})));
765 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
766 MakeDataDescriptor(200, {1}), MakeDataDescriptor(12, {1})));
767
768 TransformationVectorShuffle transformation2(
769 MakeInstructionDescriptor(16, SpvOpReturn, 0), 201, 12, 40, {0, 1});
770 ASSERT_TRUE(
771 transformation2.IsApplicable(context.get(), transformation_context));
772 ApplyAndCheckFreshIds(transformation2, context.get(),
773 &transformation_context);
774 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
775 MakeDataDescriptor(201, {0}), MakeDataDescriptor(12, {0})));
776 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
777 MakeDataDescriptor(201, {1}), MakeDataDescriptor(12, {1})));
778
779 TransformationVectorShuffle transformation3(
780 MakeInstructionDescriptor(16, SpvOpReturn, 0), 202, 40, 12, {2, 3});
781 ASSERT_TRUE(
782 transformation3.IsApplicable(context.get(), transformation_context));
783 ApplyAndCheckFreshIds(transformation3, context.get(),
784 &transformation_context);
785 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
786 MakeDataDescriptor(202, {0}), MakeDataDescriptor(12, {0})));
787 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
788 MakeDataDescriptor(202, {1}), MakeDataDescriptor(12, {1})));
789
790 TransformationVectorShuffle transformation4(
791 MakeInstructionDescriptor(16, SpvOpReturn, 0), 203, 40, 12, {0, 3});
792 ASSERT_TRUE(
793 transformation4.IsApplicable(context.get(), transformation_context));
794 ApplyAndCheckFreshIds(transformation4, context.get(),
795 &transformation_context);
796 // Because %40 is irrelevant we do not get a synonym between it and %203[0].
797 ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
798 MakeDataDescriptor(203, {0}), MakeDataDescriptor(40, {0})));
799 // Because %12 is *not* irrelevant we do get a synonym between it and %203[1].
800 ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
801 MakeDataDescriptor(203, {1}), MakeDataDescriptor(12, {1})));
802 }
803
804 } // namespace
805 } // namespace fuzz
806 } // namespace spvtools
807